From 554070cb52dd0cee0a38866a944b5fbf4c6db94a Mon Sep 17 00:00:00 2001 From: anishTP Date: Thu, 28 Sep 2023 12:34:04 +0530 Subject: [PATCH] Added signals and handler for project data change Handler triggers a generate thumnail method using the html2image module. - CSS styling to the added to the template. - Project models needs a new column for BYTEA data - A method to add the generated image to the new BYTEA column needs to be added - Cache headers have to be set in the view to tell Nginx to the cache the date --- funnel/signals.py | 3 + funnel/templates/thumbnail_preview.html | 26 +++ funnel/views/project.py | 5 +- funnel/views/thumnbnails.py | 27 +++ requirements.txt | 296 ++++++++++++++++++++++++ 5 files changed, 356 insertions(+), 1 deletion(-) create mode 100644 funnel/templates/thumbnail_preview.html create mode 100644 funnel/views/thumnbnails.py create mode 100644 requirements.txt diff --git a/funnel/signals.py b/funnel/signals.py index 8681036f1..a6b45f897 100644 --- a/funnel/signals.py +++ b/funnel/signals.py @@ -60,3 +60,6 @@ # Commentset role change signals (sends user, document) project_role_change = app_signals.signal('project_role_change') proposal_role_change = app_signals.signal('proposal_role_change') + +# Project data change signal +project_data_change = app_signals.signal('project_data_change') diff --git a/funnel/templates/thumbnail_preview.html b/funnel/templates/thumbnail_preview.html new file mode 100644 index 000000000..f14af8858 --- /dev/null +++ b/funnel/templates/thumbnail_preview.html @@ -0,0 +1,26 @@ + + + + + + + + + +
+
+
+
{{project.account.title}}
+

+ {{ project.title }} +

+
+ {{ project.tagline }} +
+
+ {{ project.datelocation }} + {{ project.primary_venue }} +
+
+ + diff --git a/funnel/views/project.py b/funnel/views/project.py index 94a1e10f7..63db7b199 100644 --- a/funnel/views/project.py +++ b/funnel/views/project.py @@ -48,7 +48,7 @@ db, sa, ) -from ..signals import project_role_change +from ..signals import project_role_change, project_data_change from ..typing import ReturnRenderWith, ReturnView from .helpers import html_in_json, render_redirect from .jobs import import_tickets, tag_locations @@ -283,6 +283,8 @@ def new_project(self) -> ReturnView: flash(_("Your new project has been created"), 'info') + project_data_change.send(self.obj) + # tag locations tag_locations.queue(project.id) @@ -455,6 +457,7 @@ def edit(self) -> ReturnView: db.session.commit() flash(_("Your changes have been saved"), 'info') tag_locations.queue(self.obj.id) + project_data_change.send(self.obj) # Find and delete draft if it exists if self.get_draft() is not None: diff --git a/funnel/views/thumnbnails.py b/funnel/views/thumnbnails.py new file mode 100644 index 000000000..ba129cd36 --- /dev/null +++ b/funnel/views/thumnbnails.py @@ -0,0 +1,27 @@ +"""View for autogenerating thumbnail previews""" + +from flask import render_template +from html2image import Html2Image +from ..models import ( + Account, + Project, +) +from .jobs import rqjob +from ..signals import project_data_change + + +thumbnail = Html2Image(size=(1067, 600)) + + +@project_data_change.connect +def generate_thumbnail_image(project = Project) -> None: + render_thumbnail_image(project = project) + +@rqjob() +def render_thumbnail_image(project = Project) -> None: + """Render the thumbnail image and cache the file using a background task""" + + image_html = render_template('thumbnail_preview.html.jinja2', project = project ) + + thumbnail_image = thumbnail.screenshot(html_str=image_html, save_as='thumbnail.png', + size=(1067, 600)) diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 000000000..b7541b8ea --- /dev/null +++ b/requirements.txt @@ -0,0 +1,296 @@ +aiohttp==3.8.5 +aiohttp-retry==2.8.3 +aiosignal==1.3.1 +alembic==1.12.0 +aniso8601==9.0.1 +anyio==4.0.0 +argon2-cffi==23.1.0 +argon2-cffi-bindings==21.2.0 +arrow==1.2.3 +astroid==2.15.6 +async-timeout==4.0.3 +attrs==23.1.0 +Babel==2.12.1 +bandit==1.7.5 +base58==2.1.1 +-e git+https://github.com/hasgeek/baseframe.git@84d2d87ba1fdcc9945bc80ab11f43c7627a372d8#egg=baseframe +bcrypt==4.0.1 +beautifulsoup4==4.12.2 +better-profanity==0.6.1 +black==23.7.0 +bleach==6.0.0 +blinker==1.6.2 +boto3==1.28.43 +botocore==1.31.43 +Brotli==1.1.0 +build==1.0.3 +cachelib==0.9.0 +cachetools==5.3.1 +cattrs==22.1.0 +certifi==2023.7.22 +cffi==1.15.1 +cfgv==3.4.0 +chardet==5.2.0 +charset-normalizer==3.2.0 +chevron==0.14.0 +click==8.1.7 +-e git+https://github.com/hasgeek/coaster.git@d9e84f51dedb3a7863e1c3d1b0608c55c777f079#egg=coaster +colorama==0.4.6 +coverage==6.5.0 +coveralls==3.3.1 +crontab==1.0.1 +cryptography==41.0.3 +cssbeautifier==1.14.9 +cssmin==0.2.0 +cssselect==1.2.0 +cssutils==2.7.1 +dataclasses-json==0.6.0 +dill==0.3.7 +distlib==0.3.7 +djlint==1.32.1 +dnspython==2.4.2 +docopt==0.6.2 +EditorConfig==0.12.3 +emoji==2.8.0 +exceptiongroup==1.1.3 +filelock==3.12.3 +flake8==6.1.0 +flake8-annotations==3.0.1 +flake8-assertive==2.1.0 +flake8-blind-except==0.2.1 +flake8-bugbear==23.7.10 +flake8-builtins==2.1.0 +flake8-comprehensions==3.14.0 +flake8-docstrings==1.7.0 +flake8-isort==6.0.0 +flake8-logging-format==0.9.0 +flake8-mutable==1.2.0 +flake8-plugin-utils==1.3.3 +flake8-print==5.0.0 +flake8-pytest-style==1.7.2 +Flask==2.3.3 +Flask-Admin==1.6.1 +Flask-Assets==2.0 +flask-babel==3.1.0 +Flask-Caching==2.0.2 +Flask-DebugToolbar==0.13.1 +Flask-Executor==1.0.0 +Flask-FlatPages==0.8.1 +Flask-Lastuser @ git+https://github.com/hasgeek/flask-lastuser@173a1c437068bfbec6912846390ea691801c973d +Flask-Mail==0.9.1 +flask-mailman==0.3.0 +Flask-Migrate==4.0.4 +flask-redis==0.4.0 +Flask-RQ2==18.3 +Flask-SQLAlchemy==3.0.5 +Flask-WTF==1.1.1 +freezegun==1.2.2 +frozenlist==1.4.0 +furl==2.1.3 +future==0.18.3 +geoip2==4.7.0 +gherkin-official==24.0.0 +gitdb==4.0.10 +GitPython==3.1.35 +grapheme==0.6.0 +gunicorn==21.2.0 +h11==0.14.0 +h2==4.1.0 +hpack==4.0.0 +html-tag-names==0.1.2 +html-void-elements==0.1.0 +html2image==2.0.4.3 +html2text==2020.1.16 +html5lib==1.1 +html5print==0.1.2 +htmlmin==0.1.12 +httpcore==0.17.3 +httplib2==0.22.0 +httpx==0.24.1 +hyperframe==6.0.1 +icalendar==5.0.7 +identify==2.5.27 +idna==3.4 +ijson==3.2.3 +importlib-metadata==6.8.0 +iniconfig==2.0.0 +install==1.3.5 +isort==5.12.0 +isoweek==1.3.3 +itsdangerous==2.1.2 +Jinja2==3.1.2 +jmespath==1.0.1 +joblib==1.3.2 +jsbeautifier==1.14.9 +jsmin==3.0.1 +json5==0.9.14 +lazy-object-proxy==1.9.0 +lesscpy==0.15.1 +linkify-it-py==2.0.2 +lxml==4.9.3 +lxml-stubs==0.4.0 +Mako==1.2.4 +Markdown==3.4.4 +markdown-it-py==3.0.0 +MarkupSafe==2.1.3 +marshmallow==3.20.1 +maxminddb==2.4.0 +mccabe==0.7.0 +mdit-py-plugins==0.4.0 +mdurl==0.1.2 +mkdocs-material-extensions==1.1.1 +multidict==6.0.4 +mxsniff==0.3.5 +mypy==1.5.1 +mypy-extensions==1.0.0 +mypy-json-report==1.0.4 +nltk==3.8.1 +nodeenv==1.8.0 +oauth2==1.9.0.post1 +oauth2client==4.1.3 +oauthlib==3.2.2 +orderedmultidict==1.0.1 +outcome==1.2.0 +packaging==23.1 +parse==1.19.1 +parse-type==0.6.2 +passlib==1.7.4 +pathspec==0.11.2 +pbr==5.11.1 +pep8-naming==0.13.3 +phonenumbers==8.13.20 +pip-compile-multi==2.6.3 +pip-tools==7.3.0 +platformdirs==3.10.0 +pluggy==1.3.0 +ply==3.11 +po2json==0.2.2 +pre-commit==3.4.0 +premailer==3.10.0 +progressbar2==4.2.0 +psycopg==3.1.10 +psycopg-binary==3.1.10 +psycopg2-binary==2.9.7 +py==1.11.0 +pyasn1==0.5.0 +pyasn1-modules==0.3.0 +pycodestyle==2.11.0 +pycountry==22.3.5 +pycparser==2.21 +pydocstyle==6.3.0 +pyflakes==3.1.0 +Pygments==2.16.1 +pyIsEmail==2.0.1 +PyJWT==2.8.0 +pylint==2.17.5 +pymdown-extensions==10.3 +pyparsing==3.1.1 +pypng==0.20220715.0 +pyproject_hooks==1.0.0 +PySocks==1.7.1 +pytest==7.4.2 +pytest-asyncio==0.21.1 +pytest-base-url==2.0.0 +pytest-bdd==6.1.1 +pytest-cov==4.1.0 +pytest-dotenv==0.5.2 +pytest-env==1.0.1 +pytest-html==4.0.0 +pytest-metadata==3.0.0 +pytest-rerunfailures==12.0 +pytest-selenium==4.0.1 +pytest-socket==0.6.0 +pytest-variables==3.0.0 +python-dateutil==2.8.2 +python-dotenv==1.0.0 +python-telegram-bot==20.5 +python-utils==3.7.0 +pytz==2023.3.post1 +pyupgrade==3.10.1 +PyVimeo==1.1.0 +PyYAML==6.0.1 +qrcode==7.4.2 +rcssmin==1.1.1 +redis==5.0.0 +Redis-Sentinel-Url==1.0.1 +reformat-gherkin==3.0.1 +regex==2023.8.8 +requests==2.31.0 +requests-file==1.5.1 +requests-mock==1.11.0 +requests-oauthlib==1.3.1 +respx==0.20.2 +rich==13.5.2 +rq==1.15.1 +rq-dashboard @ git+https://github.com/jace/rq-dashboard@a3d4ba50cc796642057ed65061f646b7ca417465 +rq-scheduler==0.13.1 +rsa==4.9 +ruff==0.0.287 +s3transfer==0.6.2 +selenium==4.9.1 +semantic-version==2.10.0 +sentry-sdk==1.30.0 +six==1.16.0 +slimit==0.8.1 +smmap==5.0.0 +sniffio==1.3.0 +snowballstemmer==2.2.0 +sortedcontainers==2.4.0 +soupsieve==2.5 +SQLAlchemy==2.0.20 +sqlalchemy-json==0.7.0 +SQLAlchemy-Utils==0.41.1 +statsd==4.0.1 +stevedore==5.1.0 +sttable==0.0.1 +tenacity==8.2.3 +tinycss2==1.2.1 +tinydb==4.8.0 +tldextract==3.5.0 +tokenize-rt==5.2.0 +toml==0.10.2 +tomli==2.0.1 +tomlkit==0.12.1 +toposort==1.10 +tqdm==4.66.1 +trio==0.22.2 +trio-websocket==0.10.4 +tuspy==1.0.1 +tweepy==4.14.0 +twilio==8.8.0 +typeguard==4.1.3 +types-chevron==0.14.2.5 +types-geoip2==3.0.0 +types-ipaddress==1.0.8 +types-maxminddb==1.5.0 +types-mock==5.1.0.2 +types-pyOpenSSL==23.2.0.2 +types-python-dateutil==2.8.19.14 +types-pytz==2023.3.0.1 +types-redis==4.6.0.5 +types-requests==2.31.0.2 +types-urllib3==1.26.25.14 +typing-inspect==0.9.0 +typing_extensions==4.7.1 +ua-parser==0.18.0 +uc-micro-py==1.0.2 +Unidecode==1.3.6 +urllib3==1.26.16 +user-agents==2.2.0 +virtualenv==20.24.4 +wcwidth==0.2.6 +webassets==2.0 +webencodings==0.5.1 +websocket-client==1.6.3 +Werkzeug==2.3.7 +whitenoise==6.5.0 +wrapt==1.15.0 +wsproto==1.2.0 +WTForms==3.0.1 +WTForms-JSON==0.3.5 +WTForms-SQLAlchemy==0.3 +xxhash==3.3.0 +yarl==1.9.2 +z-base-32==0.1.2 +zipp==3.16.2 +zxcvbn==4.4.28