Skip to content

Repository files navigation

act

Story + calls-to-action app for volunteer orgs. Campaign pages where money is ONE way to help: give (wrapped Givebutter widget, or SimpleTip), mentor, hire, host an event, AMA, subscribe. Testimonials from named-or-anonymous vouchers (LinkedClaim URI per testimony, publish-gated), per-person share links with counted attribution, Instagram story/post card downloads.

First deployment target: VM 513 (voluntask), domain act.raisethevoices.org, for the Raise the Voices JREAS Hub campaign. Design + phased plan: projects repo Active/raise-the-voices/act-design.md; VM handoff: dashboard-vm513-handoff.md.

Run (dev)

python3 -m venv .venv && .venv/bin/pip install -r requirements.txt
.venv/bin/python manage.py migrate
.venv/bin/python manage.py seed_jreas        # RTV org + JREAS campaign (draft)
.venv/bin/python manage.py createsuperuser
.venv/bin/python manage.py runserver

Publish the campaign in /admin (Campaigns → jreas → status: published).

Deploy

Live: cooperation.org/letters/ on the civic-actions VM (10.0.0.154) since 2026-09-07; only /letters/, /admin/, /static/, /media/ are routed there. Later: act.raisethevoices.org (VM 513) for the campaign pages.

  • .env from .env.example (mode 600). Postgres: database act on VM 100 (roles act_owner for migrations, act_user for the running app). ACT_BASE_PATH/SCRIPT_NAME empty at a domain root.
  • Python 3.12 venv, pip install -r requirements.txt. WeasyPrint needs libpango-1.0-0 libpangoft2-1.0-0 libharfbuzz-subset0.
  • manage.py migrate --check (run migrate with the act_owner credentials if pending), collectstatic. media/ must be writable by the service user (act).
  • deploy/act-retry-mail.service + .timer: confirmation-mail retries (systemctl enable --now act-retry-mail.timer).
  • deploy/act.service (gunicorn 127.0.0.1:8050) and deploy/nginx-cooperation.org.conf (locations added inside the existing cooperation.org vhost) are what is live. deploy/nginx-act.conf is the own-domain variant for act.raisethevoices.org.
  • Deploy a change: git pull, .venv/bin/pip install -r requirements.txt, collectstatic --clear (hashed filenames; nginx caches /static/ for 7 days), tests with ACT_DEBUG=1 manage.py test, migrate --check, sudo systemctl restart act.
  • DNS + Caddy route are host-side actions. Register in cobox app-registry.md.

Deployments

One repo and one database schema, several deployments. ACT_APPS in .env picks the apps a deployment routes and shows in admin: campaigns (story + calls to action, owns /), letters (open letters and petitions at /letters/). Org and volunteer accounts are shared and always visible.

Site ACT_APPS Public paths
cooperation.org letters /letters/, /admin/ (root forwards to /letters/)
raisethevoices.org campaigns /, /c/<slug>/, /admin/

New capabilities (content management, content planning, email campaigns) arrive as further apps in this list.

Letters (open letters and petitions)

letters/ app, pages under /letters/<slug>/. A Letter belongs to an Org, is written in Markdown (bold, italics, paragraphs, bullets), and is draft until published in /admin. kind is open letter (counter only) or petition (addressee + goal). Theme: parchment, EB Garamond (bundled, OFL).

Signing: first name, last name, city, country, plus the letter's own fields (Letters → Signature fields: label, kind short / paragraph / checkbox, required, public). A signature counts when the signer has either confirmed their email or drawn a signature (signature_pad, stored as PNG). Email is required to get updates (keep_updated). Same email twice: an unconfirmed one is replaced, a confirmed one is refused.

Confirmation mail goes out over SMTP (EMAIL_HOST, EMAIL_HOST_USER, EMAIL_HOST_PASSWORD, DEFAULT_FROM_EMAIL). With EMAIL_HOST unset nothing is sent; every attempt, sent or failed, is an EmailLog row. A failed send is retried automatically 1 h, 6 h and 24 h later (letters.models.RETRY_DELAYS; manage.py retry_confirmations on deploy/act-retry-mail.timer, every 15 min), then it gives up. The schedule and last error live on the Signature. Admin → Signatures → filter "confirmation": confirmed / drawn / approved / sent, waiting / failed, retry scheduled / failed, gave up / no email sent; action "Resend confirmation email" starts over. Approved (checkbox in the list) makes a signature count and show even if the email never confirmed — for the friend who signed but never got the mail.

PDF: /letters/<slug>.pdf is the letter with every counted signature that has on_pdf ticked, ordered by pdf_sort then date. In admin, filter (city, country, …), tick rows, action "PDF of the letter with the selected signatures". WeasyPrint renders the same templates; static and media files are read from disk.

Money boundary

act never touches funds. The give rail embeds the Givebutter widget for the org's Givebutter account (charity of record: Civic Works — receipts and discretion-and-control disclosure are locked text in campaigns/donation_text.py, deliberately not DB-editable; see projects repo Active/raise-the-voices/legal/fundraising-compliance.md) or a <simple-tip> element. Set Org.givebutter_account_id + Campaign.givebutter_campaign_id in admin when the Givebutter campaign exists.

Volunteers

Volunteer logins get is_staff + a VolunteerProfile(org=...); admin queries are scoped to their org, delete is superuser-only, publishing (campaigns, testimonials, updates) is an approver action. LinkedTrust SSO activates when LINKEDTRUST_CLIENT_ID/SECRET are set (client registered at live.linkedtrust.us — see django-linkedtrust-auth README); Django session login always works as the fallback.

About

act — story + calls-to-action app for volunteer orgs: campaign pages (Givebutter/SimpleTip embeds), testimonials as LinkedClaims, share attribution, org-scoped volunteer editing

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages