Find a file
russell@unturf.com 9fc280fd7b
fix: email images — propagate shop_cdn_endpoint + thumbnails in offers
Two coupled fixes the rendered sale email exposed:

  <img src="None/<shop_id>/<product_id>/thumbnail1?ts=...">

1. ShopContextRequestWrapper (lib/crypto_watcher/__init__.py:1243)
   wraps env_request for email-rendering inside the watcher loop. It
   overrode domain / host_url / app and proxied everything else via
   __getattr__. send_purchase_email + send_sale_email read
   `request.shop_cdn_endpoint` — but that's a reified Pyramid request
   method, not a static attr on env_request. __getattr__'s default
   returned None, and the email's <img src> became `None/.../...`.

   Fix: add explicit `shop_cdn_endpoint` (and `shop`) properties on
   the wrapper, derived from the wrapper's `_shop`. Order:
     - BYOB shop with primary_s3_cdn_endpoint set → that
     - else `app["bucket.secure_uploads.get_endpoint"]` (MPS default)
     - else None
   The BYOB branch also defends against an enabled-but-blank
   primary_s3_cdn_endpoint — drops to the default rather than
   returning None.

2. Offer + auction-outbid emails carried no product thumbnail at
   all — bummer, since the recipient can't visually identify which
   item the negotiation is about. New _product_thumbnail_html(request,
   product) helper renders a 184px-max <img> identical to the
   purchase/sale shape (or empty string if the product has no
   thumbnail1 extension / no CDN endpoint).

   Wired into:
     - send_offer_received_email
     - send_offer_accepted_email
     - send_offer_countered_email
     - send_offer_declined_email
     - send_offer_withdrawn_email
     - send_offer_buyer_cancelled_email
     - send_auction_outbid_email

   Templates in lib/mail_messages.py gained a `{thumbnail}` slot
   between the headline and the click-through link. Text variants are
   unchanged (no inline images in text email).

Both fixes target the same surface: every transactional email now
renders the right image, regardless of whether it's sent from a
view (Pyramid request) or the crypto watcher loop (wrapped env_req).
2026-05-14 17:30:02 -04:00
docs docs: notification system + design-system surface for offers/auctions 2026-05-14 14:49:39 -04:00
make_post_sell fix: email images — propagate shop_cdn_endpoint + thumbnails in offers 2026-05-14 17:30:02 -04:00
.gitignore chore: stop tracking GIT_HASH — setup.py owns it at install time 2026-05-13 14:11:48 -04:00
.gitlab-ci.deploy.yml revert: remove alembic from CI deploy, fix belongs in salt states 2026-02-19 09:28:43 -05:00
.gitlab-ci.yml fix: harden rm -rf with retry loop and existence check in CI build 2026-03-04 14:42:29 -05:00
Caddyfile Enable gzip & fix favicon 2022-06-29 14:03:41 -04:00
CHANGELOG.rst Redesign ring header into structured 2-row grid, show full now-playing title and thumbnail 2026-02-09 11:46:54 -05:00
CLAUDE.md chore: stop tracking GIT_HASH — setup.py owns it at install time 2026-05-13 14:11:48 -04:00
development.ini MPS-23: single warm sending identity for transactional mail 2026-05-12 11:13:11 -04:00
GIT_HASH bump GIT_HASH to e159d2f 2026-04-23 17:37:51 -04:00
journal.rst Extend groupr regression test to include download functionality and bump to v1.0.5 2025-07-27 18:51:07 -04:00
Makefile docs: use make migration — never hand-write revision IDs 2026-04-06 14:20:13 -04:00
MANIFEST.in prune tests... 2025-03-03 17:07:01 -05:00
piano-roll-man.html Fix product page image and content overflow issues 2025-10-04 20:27:01 -04:00
pytest.ini fix: disable pytest-timeout — crashes xdist workers on CI 2026-02-23 15:24:00 -05:00
README.rst Redesign ring header into structured 2-row grid, show full now-playing title and thumbnail 2026-02-09 11:46:54 -05:00
requirements-dev.txt Pin setuptools<81 — version 82 removed pkg_resources 2026-02-08 12:18:29 -05:00
requirements-prod.txt Time to open the sauce : ) 2021-12-31 21:39:40 -05:00
requirements-test.txt fix: add timeouts to PayPal sandbox tests and pytest-timeout safety net 2026-02-23 14:51:19 -05:00
requirements.py3.txt Pin setuptools<81 — version 82 removed pkg_resources 2026-02-08 12:18:29 -05:00
requirements.txt mps: torrent magnet links auto-generated on file upload 2026-04-05 20:03:47 -04:00
setup.py include voxsplit.c in package data 2026-02-18 06:52:01 -05:00
test.ini feat: bounded SSE feeds for offer & auction state machines 2026-05-12 21:03:50 -04:00

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

Make Post Sell
==============

The `Make Post Sell <https://www.makepostsell.com>`_ monolith platform service.

You can use the SaaS or self-host! Accepts credit cards (Stripe), PayPal, Monero (XMR), and Dogecoin (DOGE) payments.

Our `blog acts as our user guide <https://blog.makepostsell.com/>`_ & also uses ``make_post_sell``!

| `Source Code <https://git.unturf.com/engineering/make-post-sell/make_post_sell>`_ | `PyPI <https://pypi.org/project/make-post-sell/>`_ | `SaaS <https://my.makepostsell.com>`_ |

Features
--------

* **Multi-tenant SaaS** — each shop gets its own subdomain or custom domain
* **Payments** — Stripe, PayPal, Adyen, Monero (XMR), Dogecoin (DOGE)
* **Watch Mode** — continuous media playback with DJ crossfade transitions, discovery ring, queue management, and autoplay
* **Pop-out Player** — draggable media window with keyboard shortcuts, ``/random`` and ``/tv`` endpoints
* **Email Subscriptions** — digest emails (immediately, daily, weekly) with @mention notifications
* **Feeds** — RSS, Atom, and sitemap generation per shop
* **AJAX Comments** — real-time comment posting without page reload, preserves media playback
* **Related Content** — Jaccard similarity ranking with thumbnails
* **Lazy Carts** — in-memory until a product is added, no empty rows from bots
* **CSS Grid Lanes** — optional masonry layout per shop
* **Vanilla JS** — no jQuery, no framework dependencies
* **Public Domain** — all contributed code is placed in the public domain

See ``CHANGELOG.rst`` for detailed release history.


Quick Start: Operating a Server with PyPI or Source Code
==========================================================

Before you start, navigate to the directory where you want to install ``make_post_sell`` database & files.

This Makefile-based workflow lets you choose between installing ``make_post_sell`` from PyPI packages or directly from the source code (editable mode). Both flows create a virtual environment in ``./env`` and store configuration and SQLite data in the persistent ``./data`` directory.

1. **Install make_post_sell**

   - **PyPI Installation:**  
     Download the Makefile and run::
     
         wget "https://git.unturf.com/engineering/make-post-sell/make_post_sell/-/raw/master/Makefile"
         make install-from-pypi

   - **Source Installation (Editable Mode):**  
     Clone the repository and run::
     
         git clone ssh://git@git.unturf.com:2222/engineering/make-post-sell/make_post_sell.git
         make install-from-source

   - **Production Installation (Non‑Editable):**  
     For production use (non‑editable even from source), run::
     
         git clone ssh://git@git.unturf.com:2222/engineering/make-post-sell/make_post_sell.git
         make install-from-source-prod

2. **Activate the Virtual Environment**

   Before running any commands, activate the virtual environment::
   
         source env/bin/activate

3. **Start the Development Server**

   You'll want to configure the system in ``data/development.ini``.

   Typically I control most stuff with environment vars, for example ``vars.sh``::

         # boto3 style credentials for s3/digital-ocean spaces.
         # this is for storing content & physical products.
         export MPS_APP_MAIN_BUCKET="removed"
         export MPS_APP_SECURE_UPLOADS_ACCESS_KEY="removed"
         export MPS_APP_SECURE_UPLOADS_SECRET_KEY="removed"

         # stripe keys for collecting credit cards & crypto.
         # NOTE: These are used by tests, shops configure their own keys in the UI
         export MPS_TEST_STRIPE_PUBLIC_API_KEY="pk_test_removed"
         export MPS_TEST_STRIPE_SECRET_API_KEY="sk_test_removed"

         # the root domain acts as a SaaS for many shop domains!
         export MAKE_POST_SELL_ROOT_DOMAIN="example.com"
         export MAKE_POST_SELL_ROOT_URL="http://example.com:6501"
         
         # optional: email for the root domain owner
         export MAKE_POST_SELL_DOMAIN_OWNER_EMAIL="admin@example.com"

         # optional: DKIM email signing (commented out by default)
         # export MPS_APP_DKIM_PRIVATE_KEY_PATH="/path/to/dkim/private.key"
         # export MPS_APP_DKIM_SELECTOR="selector"

   With the virtual environment active, start the server::

         source vars.sh
         make serve

   Then browse to `http://127.0.0.1:6501/ <http://127.0.0.1:6501/>`_ to view the app.



Running Tests
-------------

We currently use `pytest`:

.. code-block:: bash

 make test


SQL Migrations
===============

If your deployment is brand new, you don't need to run any migrations.

Otherwise, it should be safe to run this at anytime to catch your database up:

.. code-block:: bash

 alembic -c development.ini upgrade head

To look at the current revision and the history run these:

.. code-block:: bash

 alembic -c development.ini history
 alembic -c development.ini current

If you ever want to cut a new migration script, you can run this:

.. code-block:: bash

 alembic -c development.ini revision -m "Added email_id column to User table."

Then you can edit / modify the generated ``.py`` file with your changes.

You can also autogenerate a new migration script using `--autogenerate`.
Alembic will prepare a migration script by comparing the state of the
database with the state of the model:

.. code-block:: bash

  alembic -c development.ini revision --autogenerate -m "autogenerated indicies."

You should review the recommended migration script before `upgrade`.

misc
====

You may source the new Python virtual environment during development:

.. code-block:: bash

 # source env/bin/activate.fish
 . env/bin/activate


Python Pyramid Shell
==========================

If you want to use an interactive Python interpreter to interact with Make Post Sell app/models & DB:

.. code-block:: bash

 pshell development.ini

For example, we needed to migrate production data using this script:

.. code-block:: python

 # begin the database transaction.
 request.tm.begin()

 suses = models.stripe_user_shop.get_all_stripe_user_shop_objects(request.dbsession)
 for sus in suses:
     try:
         sus.active_card_id = sus.stripe_customer_default_source.id
         request.dbsession.add(sus)
     except AttributeError:
         pass

 # flush / commit all changes stored the the sqlachemy session.
 request.dbsession.flush()

 # commit/close the database transaction to really make changes.
 request.tm.commit()


Contributing
===================

* Establish communication with Russell or another admin to bless your git.unturf.com gitlab account & put you into the proper roles.
* Russell should see your account request but due to spam you have to ask him directly for approval via email or some other means of comms.
* Clone repo & make commits
* Create merge requests, we automatically run the unit & headless functional tests on each commit
* On merge we release to the production site & see the change across users.

Optionally, format your code.

This is not set in stone, but if you want to use a formatter this is the path for now!

**Python**
  black (manual)

**Jinja2**
  None (not needed, neither is an HTML formatter)

**JavaScript**
  Prettier or biome (manual)

**CSS**
  Prettier or biome (manual)


Licence
==============================================

All contributed code is placed in the public domain.

source code: `https://git.unturf.com/engineering/make-post-sell/make_post_sell <https://git.unturf.com/engineering/make-post-sell/make_post_sell>`_

MakePostSell & make-post-sell are trademarked, do not misrepresent the brand.

Feel free to white label any code or themes into your own brand.

**Original Developer:**  
`Russell Ballestrini <https://russell.ballestrini.net>`_