Fix Signal receiving
This commit is contained in:
9
.dockerignore
Normal file
9
.dockerignore
Normal file
@@ -0,0 +1,9 @@
|
||||
.git
|
||||
.podman
|
||||
artifacts
|
||||
.container-home
|
||||
db.sqlite3
|
||||
docker/data
|
||||
signal-cli-config
|
||||
__pycache__
|
||||
*.pyc
|
||||
1
.gitignore
vendored
1
.gitignore
vendored
@@ -166,3 +166,4 @@ oom
|
||||
node_modules/
|
||||
.podman/
|
||||
.beads/
|
||||
.sisyphus/
|
||||
|
||||
2
Makefile
2
Makefile
@@ -4,7 +4,7 @@ run:
|
||||
bash $(QUADLET_MGR) up
|
||||
|
||||
build:
|
||||
docker-compose --env-file=stack.env build
|
||||
OPERATION=uwsgi podman build --build-arg OPERATION=uwsgi -t localhost/xf/gia:prod -f Dockerfile .
|
||||
|
||||
stop:
|
||||
bash $(QUADLET_MGR) down
|
||||
|
||||
10
app/urls.py
10
app/urls.py
@@ -220,6 +220,16 @@ urlpatterns = [
|
||||
compose.ComposeContactMatch.as_view(),
|
||||
name="compose_contact_match",
|
||||
),
|
||||
path(
|
||||
"compose/contacts/create/",
|
||||
compose.ComposeContactCreate.as_view(),
|
||||
name="compose_contact_create",
|
||||
),
|
||||
path(
|
||||
"compose/contacts/create-all/",
|
||||
compose.ComposeContactCreateAll.as_view(),
|
||||
name="compose_contact_create_all",
|
||||
),
|
||||
# AIs
|
||||
path(
|
||||
"ai/workspace/",
|
||||
|
||||
@@ -13,7 +13,18 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="level-right">
|
||||
<a class="button is-light" href="{% url 'compose_workspace' %}">
|
||||
<form id="create-all-form" method="post" action="{% url 'compose_contact_create_all' %}">
|
||||
{% csrf_token %}
|
||||
<button
|
||||
type="submit"
|
||||
class="button is-info is-light js-create-all"
|
||||
id="create-all-btn"
|
||||
title="Create persons for all unlinked contacts with detected names">
|
||||
<span class="icon is-small"><i class="fa-solid fa-user-plus"></i></span>
|
||||
<span>Create All</span>
|
||||
</button>
|
||||
</form>
|
||||
<a class="button is-light ml-2" href="{% url 'compose_workspace' %}">
|
||||
<span class="icon is-small"><i class="fa-solid fa-table-cells-large"></i></span>
|
||||
<span>Manual Workspace</span>
|
||||
</a>
|
||||
@@ -187,8 +198,27 @@
|
||||
</td>
|
||||
<td data-discovered-col="3" class="discovered-col-3"><code>{{ row.identifier }}</code></td>
|
||||
<td data-discovered-col="4" class="discovered-col-4">
|
||||
{% if not row.linked_person and row.suggestions %}
|
||||
{% if not row.linked_person %}
|
||||
<div class="buttons are-small">
|
||||
{% if row.detected_name %}
|
||||
<form method="post" action="{% url 'compose_contact_create' %}" style="display: inline-flex;">
|
||||
{% csrf_token %}
|
||||
<input type="hidden" name="service" value="{{ row.service }}">
|
||||
<input type="hidden" name="identifier" value="{{ row.identifier }}">
|
||||
<input type="hidden" name="person_name" value="{{ row.detected_name }}">
|
||||
<button
|
||||
type="submit"
|
||||
class="button is-small is-info is-light js-create-contact"
|
||||
data-service="{{ row.service }}"
|
||||
data-identifier="{{ row.identifier }}"
|
||||
data-name="{{ row.detected_name }}"
|
||||
title="Create new person from detected name">
|
||||
<span class="icon is-small"><i class="fa-solid fa-plus"></i></span>
|
||||
<span>Create</span>
|
||||
</button>
|
||||
</form>
|
||||
{% endif %}
|
||||
{% if row.suggestions %}
|
||||
{% for suggestion in row.suggestions %}
|
||||
<form method="post" style="display: inline-flex;">
|
||||
{% csrf_token %}
|
||||
@@ -204,6 +234,7 @@
|
||||
</button>
|
||||
</form>
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
</div>
|
||||
{% else %}
|
||||
<span class="has-text-grey">-</span>
|
||||
@@ -436,6 +467,41 @@
|
||||
if (ev.key === "Escape") hidePopover();
|
||||
});
|
||||
|
||||
document.querySelectorAll(".js-create-contact").forEach((btn) => {
|
||||
btn.addEventListener("click", function (ev) {
|
||||
const name = this.dataset.name || "this contact";
|
||||
const identifier = this.dataset.identifier || "";
|
||||
const service = this.dataset.service || "";
|
||||
const confirmMsg = "Create new person '" + name + "' and link to " + identifier + " (" + service + ")?";
|
||||
if (!confirm(confirmMsg)) {
|
||||
ev.preventDefault();
|
||||
return false;
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
const createAllBtn = document.getElementById("create-all-btn");
|
||||
if (createAllBtn) {
|
||||
createAllBtn.addEventListener("click", function (ev) {
|
||||
const table = document.getElementById("discovered-contacts-table");
|
||||
if (!table) return;
|
||||
const unlinkedWithName = table.querySelectorAll("tbody tr").filter((row) => {
|
||||
const statusCell = row.querySelector('[data-discovered-col="5"]');
|
||||
return statusCell && statusCell.textContent.includes("unlinked");
|
||||
}).length;
|
||||
if (unlinkedWithName === 0) {
|
||||
ev.preventDefault();
|
||||
alert("No unlinked contacts with detected names to create.");
|
||||
return false;
|
||||
}
|
||||
const confirmMsg = "Create " + unlinkedWithName + " new contact" + (unlinkedWithName > 1 ? "s" : "") + " from detected names?";
|
||||
if (!confirm(confirmMsg)) {
|
||||
ev.preventDefault();
|
||||
return false;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
applyFilters();
|
||||
applyColumns();
|
||||
})();
|
||||
|
||||
@@ -2361,6 +2361,131 @@ class ComposeContactMatch(LoginRequiredMixin, View):
|
||||
)
|
||||
|
||||
|
||||
class ComposeContactCreate(LoginRequiredMixin, View):
|
||||
template_name = "pages/compose-contact-match.html"
|
||||
|
||||
def post(self, request):
|
||||
service = _default_service(request.POST.get("service"))
|
||||
identifier = str(request.POST.get("identifier") or "").strip()
|
||||
person_name = str(request.POST.get("person_name") or "").strip()
|
||||
|
||||
if not identifier:
|
||||
return render(
|
||||
request,
|
||||
self.template_name,
|
||||
self._context(request, "Identifier is required.", "warning"),
|
||||
)
|
||||
|
||||
if not person_name:
|
||||
return render(
|
||||
request,
|
||||
self.template_name,
|
||||
self._context(request, "Person name is required.", "warning"),
|
||||
)
|
||||
|
||||
existing = PersonIdentifier.objects.filter(
|
||||
user=request.user,
|
||||
service=service,
|
||||
identifier=identifier,
|
||||
).first()
|
||||
|
||||
if existing and existing.person:
|
||||
return render(
|
||||
request,
|
||||
self.template_name,
|
||||
self._context(
|
||||
request,
|
||||
f"{identifier} ({service}) is already linked to {existing.person.name}.",
|
||||
"warning",
|
||||
),
|
||||
)
|
||||
|
||||
person = Person.objects.create(user=request.user, name=person_name)
|
||||
|
||||
PersonIdentifier.objects.create(
|
||||
user=request.user,
|
||||
person=person,
|
||||
service=service,
|
||||
identifier=identifier,
|
||||
)
|
||||
|
||||
message = f"Created person '{person_name}' and linked {identifier} ({service})."
|
||||
return render(
|
||||
request,
|
||||
self.template_name,
|
||||
self._context(request, message, "success"),
|
||||
)
|
||||
|
||||
|
||||
class ComposeContactCreateAll(LoginRequiredMixin, View):
|
||||
template_name = "pages/compose-contact-match.html"
|
||||
|
||||
def post(self, request):
|
||||
candidates = _manual_contact_rows(request.user)
|
||||
|
||||
created_count = 0
|
||||
skipped_count = 0
|
||||
errors = []
|
||||
|
||||
for candidate in candidates:
|
||||
if candidate.get("linked_person"):
|
||||
skipped_count += 1
|
||||
continue
|
||||
|
||||
detected_name = candidate.get("detected_name", "")
|
||||
if not detected_name:
|
||||
skipped_count += 1
|
||||
continue
|
||||
|
||||
service = candidate.get("service", "")
|
||||
identifier = candidate.get("identifier", "")
|
||||
|
||||
if not service or not identifier:
|
||||
skipped_count += 1
|
||||
continue
|
||||
|
||||
existing = PersonIdentifier.objects.filter(
|
||||
user=request.user,
|
||||
service=service,
|
||||
identifier=identifier,
|
||||
).first()
|
||||
|
||||
if existing and existing.person:
|
||||
skipped_count += 1
|
||||
continue
|
||||
|
||||
try:
|
||||
person = Person.objects.create(user=request.user, name=detected_name)
|
||||
|
||||
PersonIdentifier.objects.create(
|
||||
user=request.user,
|
||||
person=person,
|
||||
service=service,
|
||||
identifier=identifier,
|
||||
)
|
||||
|
||||
created_count += 1
|
||||
except Exception as e:
|
||||
errors.append(f"{identifier} ({service}): {str(e)}")
|
||||
skipped_count += 1
|
||||
|
||||
if errors:
|
||||
message = f"Created {created_count} contacts. Errors: {'; '.join(errors[:5])}"
|
||||
level = "warning"
|
||||
elif created_count > 0:
|
||||
message = f"Created {created_count} new contact{'s' if created_count != 1 else ''}. Skipped {skipped_count}."
|
||||
level = "success"
|
||||
else:
|
||||
message = f"No new contacts to create. {skipped_count} already linked or without names."
|
||||
level = "info"
|
||||
|
||||
return render(
|
||||
request,
|
||||
self.template_name,
|
||||
self._context(request, message, level),
|
||||
)
|
||||
|
||||
|
||||
class ComposePage(LoginRequiredMixin, View):
|
||||
template_name = "pages/compose.html"
|
||||
|
||||
|
||||
@@ -35,7 +35,11 @@ ensure_dirs() {
|
||||
mkdir -p "$REDIS_DATA_DIR" "$WHATSAPP_DATA_DIR" "$VRUN_DIR" "$ROOT_DIR/signal-cli-config"
|
||||
# Container runs as uid 1000 (xf); rootless Podman remaps uids so plain
|
||||
# chown won't work — podman unshare translates to the correct host uid.
|
||||
if [[ -n "${QUADLET_SKIP_UNSHARE:-}" ]] || [[ -n "${CONTAINER_HOST:-}" ]] || [[ -n "${PODMAN_HOST:-}" ]] || [[ -n "${DOCKER_HOST:-}" ]]; then
|
||||
echo "Skipping podman unshare chown (QUADLET_SKIP_UNSHARE or remote host detected)"
|
||||
else
|
||||
podman unshare chown 1000:1000 "$WHATSAPP_DATA_DIR" 2>/dev/null || true
|
||||
fi
|
||||
}
|
||||
|
||||
rm_if_exists() {
|
||||
|
||||
Reference in New Issue
Block a user