Compare commits

..

21 Commits

Author SHA1 Message Date
Sheldan
37147a866f [maven-release-plugin] prepare release sissi-1.4.28 2023-12-10 14:59:29 +01:00
Sheldan
9a7d0613b1 [SIS-xxx] enabling giveaway module
updating to newer abstracto version
preparing for release
2023-12-10 14:58:19 +01:00
Sheldan
7e60447ae6 [maven-release-plugin] prepare for next development iteration 2023-12-01 23:39:45 +01:00
Sheldan
e4a899a125 [maven-release-plugin] prepare release sissi-1.4.27 2023-12-01 23:39:41 +01:00
Sheldan
ce8341e69a [SIS-xxx] changing caching
prepare for release
2023-12-01 23:38:38 +01:00
Sheldan
fa6333fa49 [maven-release-plugin] prepare for next development iteration 2023-12-01 23:16:02 +01:00
Sheldan
3393dea591 [maven-release-plugin] prepare release sissi-1.4.26 2023-12-01 23:15:57 +01:00
Sheldan
3c3bdfaed9 [SIS-xxx] preparing for release 2023-12-01 23:15:31 +01:00
Sheldan
172e3c4190 [SIS-xxx] adding uuid to clear cache 2023-12-01 23:14:57 +01:00
Sheldan
52b86804b9 [maven-release-plugin] prepare for next development iteration 2023-12-01 22:54:18 +01:00
Sheldan
de8d9982f3 [maven-release-plugin] prepare release sissi-1.4.25 2023-12-01 22:54:14 +01:00
Sheldan
29e1b22783 [SIS-xxx] preparing for release 2023-12-01 22:53:37 +01:00
Sheldan
5852d4837e [SIS-xxx] synchronizing the lookup for donations, so that simultaneous calls are not possible 2023-12-01 22:49:34 +01:00
Sheldan
b345fa5502 [SIS-xxx] fixing logging setup in case of a debra donation loading error 2023-11-30 21:02:16 +01:00
Sheldan
d6470e3714 [SIS-xxx] changing meetup time display to include week day name 2023-11-30 19:55:47 +01:00
Sheldan
b4cebe2b41 [maven-release-plugin] prepare for next development iteration 2023-11-29 21:08:14 +01:00
Sheldan
f3dd85d7d5 [maven-release-plugin] prepare release sissi-1.4.24 2023-11-29 21:08:10 +01:00
Sheldan
db318afb2b [SIS-xxx] preparing for release 2023-11-29 21:07:34 +01:00
Sheldan
ddd710d1c2 [SIS-xxx] changing wording of debra campaign info image 2023-11-29 21:05:02 +01:00
Sheldan
81824db1f1 [SIS-xxx] adding html wrapper for debra images
restructuring and splitting image generation into multiple files
adding doge sun image generation
2023-11-29 00:04:29 +01:00
Sheldan
0390d7c8ca [maven-release-plugin] prepare for next development iteration 2023-11-23 01:04:11 +01:00
58 changed files with 384 additions and 283 deletions

View File

@@ -3,7 +3,7 @@
<parent>
<groupId>dev.sheldan.sissi.application</groupId>
<artifactId>application</artifactId>
<version>1.4.23</version>
<version>1.4.28</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>executable</artifactId>
@@ -136,6 +136,11 @@
<artifactId>statistic-impl</artifactId>
</dependency>
<dependency>
<groupId>dev.sheldan.abstracto.modules</groupId>
<artifactId>giveaway-impl</artifactId>
</dependency>
<!-- sissi modules -->
<dependency>

View File

@@ -3,7 +3,7 @@
<parent>
<groupId>dev.sheldan.sissi</groupId>
<artifactId>sissi</artifactId>
<version>1.4.23</version>
<version>1.4.28</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@@ -3,7 +3,7 @@
<parent>
<groupId>dev.sheldan.sissi.application.module.custom</groupId>
<artifactId>sissi-customizations</artifactId>
<version>1.4.23</version>
<version>1.4.28</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@@ -3,7 +3,7 @@
<parent>
<artifactId>application</artifactId>
<groupId>dev.sheldan.sissi.application</groupId>
<version>1.4.23</version>
<version>1.4.28</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@@ -3,7 +3,7 @@
<parent>
<groupId>dev.sheldan.sissi.application</groupId>
<artifactId>sissi-modules</artifactId>
<version>1.4.23</version>
<version>1.4.28</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@@ -21,7 +21,7 @@ public class DebraDonationStatusController {
@GetMapping(value = "/latestDonations", produces = "application/json")
public DonationStats getLatestDonations() {
Long serverId = Long.parseLong(System.getenv(DEBRA_DONATION_NOTIFICATION_SERVER_ID_ENV_NAME));
DonationsResponse donationResponse = donationService.getCachedDonationAmount(serverId);
DonationsResponse donationResponse = donationService.getSynchronizedCachedDonationAmount(serverId);
List<DonationInfo> donations = donationService.getLatestDonations(donationResponse, Integer.MAX_VALUE)
.stream()
.map(DonationInfo::fromDonationItemModel)
@@ -36,7 +36,7 @@ public class DebraDonationStatusController {
@GetMapping(value = "/highestDonations", produces = "application/json")
public DonationStats getHighestDonations() {
Long serverId = Long.parseLong(System.getenv(DEBRA_DONATION_NOTIFICATION_SERVER_ID_ENV_NAME));
DonationsResponse donationResponse = donationService.getCachedDonationAmount(serverId);
DonationsResponse donationResponse = donationService.getSynchronizedCachedDonationAmount(serverId);
List<DonationInfo> donations = donationService.getHighestDonations(donationResponse, Integer.MAX_VALUE)
.stream()
.map(DonationInfo::fromDonationItemModel)
@@ -51,7 +51,7 @@ public class DebraDonationStatusController {
@GetMapping(value = "/campaignInfo", produces = "application/json")
public CampaignInfo getCampaignInfo() {
Long serverId = Long.parseLong(System.getenv(DEBRA_DONATION_NOTIFICATION_SERVER_ID_ENV_NAME));
DonationsResponse donationResponse = donationService.getCachedDonationAmount(serverId);
DonationsResponse donationResponse = donationService.getSynchronizedCachedDonationAmount(serverId);
Description pageObject = donationResponse.getPage();
return CampaignInfo

View File

@@ -134,9 +134,13 @@ public class DonationService {
.collect(Collectors.toList());
}
public synchronized DonationsResponse getSynchronizedCachedDonationAmount(Long serverId) {
return self.getCachedDonationAmount(serverId);
}
@Cacheable(value = "donation-cache")
public DonationsResponse getCachedDonationAmount(Long serverId) {
return fetchCurrentDonationAmount(serverId);
public synchronized DonationsResponse getCachedDonationAmount(Long serverId) {
return self.fetchCurrentDonationAmount(serverId);
}
public DonationsResponse fetchCurrentDonationAmount(Long serverId) {
@@ -148,10 +152,8 @@ public class DonationService {
.build();
Response response = okHttpClient.newCall(request).execute();
if(!response.isSuccessful()) {
if (log.isDebugEnabled()) {
log.error("Failed to retrieve donation response. Response had code {} with body {}.",
response.code(), response.body());
}
log.error("Failed to retrieve donation response. Response had code {} with body {} and headers {}.",
response.code(), response.body().string(), response.headers());
throw new DonationAmountNotFoundException();
}
Gson gson = getGson();

View File

@@ -3,7 +3,7 @@
<parent>
<groupId>dev.sheldan.sissi.application</groupId>
<artifactId>sissi-modules</artifactId>
<version>1.4.23</version>
<version>1.4.28</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@@ -3,7 +3,7 @@
<parent>
<groupId>dev.sheldan.sissi.application</groupId>
<artifactId>application</artifactId>
<version>1.4.23</version>
<version>1.4.28</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@@ -3,7 +3,7 @@
<parent>
<groupId>dev.sheldan.sissi.application</groupId>
<artifactId>sissi-modules</artifactId>
<version>1.4.23</version>
<version>1.4.28</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@@ -3,7 +3,7 @@
<parent>
<artifactId>sissi-modules</artifactId>
<groupId>dev.sheldan.sissi.application</groupId>
<version>1.4.23</version>
<version>1.4.28</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@@ -15,10 +15,10 @@ type: application
# This is the chart version. This version number should be incremented each time you make changes
# to the chart and its templates, including the app version.
# Versions are expected to follow Semantic Versioning (https://semver.org/)
version: 1.4.23
version: 1.4.28
# This is the version number of the application being deployed. This version number should be
# incremented each time you make changes to the application. Versions are not expected to
# follow Semantic Versioning. They should reflect the version the application is using.
# It is recommended to use it with quotes.
appVersion: "1.4.23"
appVersion: "1.4.28"

View File

@@ -8,7 +8,7 @@ bot:
repository: harbor.sheldan.dev/sissi
pullPolicy: IfNotPresent
image: sissi-bot
tag: 1.4.23
tag: 1.4.28
livenessProbe:
initialDelaySeconds: 60
periodSeconds: 5
@@ -25,7 +25,7 @@ restApi:
repository: harbor.sheldan.dev/sissi
pullPolicy: IfNotPresent
image: sissi-rest-api
tag: 1.4.23
tag: 1.4.28
podAnnotations: {}
podSecurityContext: {}
securityContext: {}
@@ -68,26 +68,26 @@ templateDeployment:
repository: harbor.sheldan.dev/abstracto
pullPolicy: Always
image: abstracto-template-deployment
tag: 1.5.12
tag: 1.5.13
templateDeploymentData:
repository: harbor.sheldan.dev/sissi
pullPolicy: Always
image: sissi-template-data
tag: 1.4.23
tag: 1.4.28
dbConfigDeployment:
enabled: true
repository: harbor.sheldan.dev/abstracto
pullPolicy: Always
image: abstracto-db-deployment
tag: 1.5.12
tag: 1.5.13
dbConfigDeploymentData:
repository: harbor.sheldan.dev/sissi
pullPolicy: Always
image: sissi-db-data
tag: 1.4.23
tag: 1.4.28
dbCredentials:
host:

View File

@@ -3,7 +3,7 @@
<parent>
<groupId>dev.sheldan.sissi</groupId>
<artifactId>deployment</artifactId>
<version>1.4.23</version>
<version>1.4.28</version>
</parent>
<modelVersion>4.0.0</modelVersion>
@@ -203,6 +203,16 @@
<destFileName>statistic.zip</destFileName>
</artifactItem>
<artifactItem>
<groupId>dev.sheldan.abstracto-templates.templates</groupId>
<artifactId>giveaway</artifactId>
<version>${abstracto.templates.version}</version>
<type>zip</type>
<overWrite>true</overWrite>
<outputDirectory>${file.basedir}/template-data/template-artifacts/</outputDirectory>
<destFileName>giveaway.zip</destFileName>
</artifactItem>
<!-- sissi template artefacts -->
<artifactItem>
<groupId>dev.sheldan.sissi.templates</groupId>
@@ -418,6 +428,16 @@
<destFileName>statistic.zip</destFileName>
</artifactItem>
<artifactItem>
<groupId>dev.sheldan.abstracto-templates.translations</groupId>
<artifactId>giveaway</artifactId>
<version>${abstracto.templates.version}</version>
<type>zip</type>
<overWrite>true</overWrite>
<outputDirectory>${file.basedir}/template-data/translation-artifacts/</outputDirectory>
<destFileName>giveaway.zip</destFileName>
</artifactItem>
<!-- sissi translation artefacts -->
<artifactItem>
@@ -707,6 +727,17 @@
<destFileName>statistic.zip</destFileName>
</artifactItem>
<artifactItem>
<groupId>dev.sheldan.abstracto.modules</groupId>
<artifactId>giveaway-impl</artifactId>
<version>${abstracto.version}</version>
<classifier>liquibase</classifier>
<type>zip</type>
<overWrite>true</overWrite>
<outputDirectory>${file.basedir}/db-data/liquibase-artifacts/</outputDirectory>
<destFileName>giveaway.zip</destFileName>
</artifactItem>
<!-- customizations -->
<artifactItem>

View File

@@ -1,2 +1,2 @@
REGISTRY_PREFIX=harbor.sheldan.dev/sissi/
VERSION=1.4.23
VERSION=1.4.28

View File

@@ -8,6 +8,7 @@
{ "zip": "statistic", "file": "statistic-changeLog.xml"},
{ "zip": "starboard", "file": "starboard-changeLog.xml"},
{ "zip": "quotes", "file": "quotes-changeLog.xml"},
{ "zip": "giveaway", "file": "giveaway-changeLog.xml"},
{ "zip": "meetup", "file": "meetup-changeLog.xml"},
{ "zip": "rss-news", "file": "rssNews-changeLog.xml"},
{ "zip": "debra", "file": "debra-changeLog.xml"},

View File

@@ -1,4 +1,4 @@
#!/bin/sh
echo "Starting python server..."
python3 -u python/main.py
cd python && python3 -u main.py

View File

@@ -1,13 +1,13 @@
{
"template_artifacts": [
"core","starboard", "link-embed", "moderation", "entertainment", "custom-command", "utility", "webservices", "remind", "suggestion", "modmail", "assignable-roles", "experience-tracking", "logging", "statistic", "twitch",
"core","starboard", "link-embed", "moderation", "entertainment", "custom-command", "utility", "webservices", "remind", "suggestion", "modmail", "assignable-roles", "experience-tracking", "logging", "statistic", "twitch", "giveaway",
"quotes", "meetup", "debra", "rss-news",
"moderation-custom",
"moderation-template-overrides", "experience-template-overrides", "logging-template-overrides"
],
"translation_artifacts": [
"core",
"starboard", "link-embed", "moderation", "entertainment", "custom-command", "utility", "webservices", "suggestion", "remind", "modmail", "assignable-roles", "experience-tracking", "logging", "statistic", "twitch",
"starboard", "link-embed", "moderation", "entertainment", "custom-command", "utility", "webservices", "suggestion", "remind", "modmail", "assignable-roles", "experience-tracking", "logging", "statistic", "twitch", "giveaway",
"quotes", "meetup", "debra", "rss-news",
"moderation-custom",
"moderation-translation-overrides", "experience-translation-overrides", "logging-translation-overrides"

View File

@@ -3,7 +3,7 @@
<parent>
<groupId>dev.sheldan.sissi</groupId>
<artifactId>sissi</artifactId>
<version>1.4.23</version>
<version>1.4.28</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@@ -13,15 +13,15 @@
<groupId>dev.sheldan.sissi</groupId>
<artifactId>sissi</artifactId>
<name>Sissi</name>
<version>1.4.23</version>
<version>1.4.28</version>
<properties>
<maven.compiler.target>17</maven.compiler.target>
<maven.compiler.source>17</maven.compiler.source>
<!-- edit in release.yml as well -->
<!-- when releasing a new bot version, update the .env as well-->
<abstracto.version>1.5.12</abstracto.version>
<abstracto.templates.version>1.4.23</abstracto.templates.version>
<abstracto.version>1.5.13</abstracto.version>
<abstracto.templates.version>1.4.24</abstracto.templates.version>
<apache-jena.version>4.9.0</apache-jena.version>
<rssreader.version>3.5.0</rssreader.version>
</properties>
@@ -59,7 +59,7 @@
<scm>
<url>https://maven.pkg.github.com/Sheldan/Sissi</url>
<developerConnection>scm:git:git@github.com:Sheldan/Sissi.git</developerConnection>
<tag>sissi-1.4.23</tag>
<tag>sissi-1.4.28</tag>
</scm>
</project>

View File

@@ -0,0 +1,225 @@
from flask import request, render_template
from PIL import Image, ImageDraw, ImageFont
import requests
import os
import json
import logging
import uuid
from __main__ import app
from utils import serve_pil_image
sissi_host = os.getenv('SISSI_HOST')
sissi_port = os.getenv('SISSI_PORT')
latest_donations_url = f'http://{sissi_host}:{sissi_port}/debra/latestDonations'
highest_donations_url = f'http://{sissi_host}:{sissi_port}/debra/highestDonations'
campaign_info_url = f'http://{sissi_host}:{sissi_port}/debra/campaignInfo'
class DonationImageGenerationParameters:
validation_message = ''
validation_value = ''
validated = None
def __init__(self, font_name, font_size, canvas_width, canvas_height, donation_count, r, g, b):
self.font_name = font_name
self.font_size = font_size
self.canvas_width = canvas_width
self.canvas_height = canvas_height
self.donation_count = donation_count
self.color = (r, g, b)
def validate(self):
self.validated = True
if self.font_name not in DonationImageGenerationConstants.allowed_fonts:
self.validated = False
self.validation_message = f'Font must be one of ' + ','.join(DonationImageGenerationConstants.allowed_fonts)
self.validation_value = self.font_name
if self.font_size > DonationImageGenerationConstants.font_range[1] or self.font_size < DonationImageGenerationConstants.font_range[0]:
self.validated = False
self.validation_message = f'Font size must be between {DonationImageGenerationConstants.font_range[0]} and {DonationImageGenerationConstants.font_range[1]}'
self.validation_value = self.font_size
if self.canvas_height > DonationImageGenerationConstants.canvas_height_range[1] or self.canvas_height < DonationImageGenerationConstants.canvas_height_range[0]:
self.validated = False
self.validation_message = f'Canvas height must be between {DonationImageGenerationConstants.canvas_height_range[0]} and {DonationImageGenerationConstants.canvas_height_range[1]}'
self.validation_value = self.canvas_height
if self.canvas_width > DonationImageGenerationConstants.canvas_width_range[1] or self.canvas_width < DonationImageGenerationConstants.canvas_width_range[0]:
self.validated = False
self.validation_message = f'Canvas width must be between {DonationImageGenerationConstants.canvas_width_range[0]} and {DonationImageGenerationConstants.color_range[1]}'
self.validation_value = self.canvas_width
if self.donation_count > DonationImageGenerationConstants.donation_count_range[1] or self.donation_count < DonationImageGenerationConstants.donation_count_range[0]:
self.validated = False
self.validation_message = f'Donation count must be between {DonationImageGenerationConstants.donation_count_range[0]} and {DonationImageGenerationConstants.donation_count_range[1]}'
self.validation_value = self.donation_count
if self.color[0] > DonationImageGenerationConstants.color_range[1] or self.color[0] < DonationImageGenerationConstants.color_range[0]:
self.validated = False
self.validation_message = f'Red must be between {DonationImageGenerationConstants.color_range[0]} and {DonationImageGenerationConstants.color_range[1]} inclusively'
self.validation_value = self.color[0]
if self.color[1] > DonationImageGenerationConstants.color_range[1] or self.color[1] < DonationImageGenerationConstants.color_range[0]:
self.validated = False
self.validation_message = f'Green must be between {DonationImageGenerationConstants.color_range[0]} and {DonationImageGenerationConstants.color_range[1]} inclusively'
self.validation_value = self.color[1]
if self.color[2] > DonationImageGenerationConstants.color_range[1] or self.color[2] < DonationImageGenerationConstants.color_range[0]:
self.validated = False
self.validation_message = f'Blue must be between {DonationImageGenerationConstants.color_range[0]} and {DonationImageGenerationConstants.color_range[1]} inclusively'
self.validation_value = self.color[2]
@app.route('/debra/latestDonations')
def latest_donations():
donation_stats = requests.get(latest_donations_url)
logging.info(f'returning latest donations')
return donation_stats.text
@app.route('/debra/highestDonations')
def highest_donations():
donation_stats = requests.get(highest_donations_url)
logging.info(f'returning highest donations')
return donation_stats.text
@app.route('/debra/campaignInfo')
def campaign_info_route():
donation_stats = requests.get(campaign_info_url)
logging.info(f'returning campaign info')
return donation_stats.text
@app.route('/debra/image/help')
def show_image_generation_help():
def make_param(parameters_obj, name, default, values):
parameters_obj[name] = {
'default': default,
'values': values
}
parameters = {}
make_param(parameters, 'font', DonationImageGenerationConstants.font_default, DonationImageGenerationConstants.allowed_fonts)
make_param(parameters, 'fontSize', DonationImageGenerationConstants.font_size_default, DonationImageGenerationConstants.font_range)
make_param(parameters, 'canvasWidth', DonationImageGenerationConstants.canvas_width_default, DonationImageGenerationConstants.canvas_width_range)
make_param(parameters, 'canvasHeight', DonationImageGenerationConstants.canvas_height_default, DonationImageGenerationConstants.canvas_height_range)
make_param(parameters, 'donationCount', DonationImageGenerationConstants.donation_count_default, DonationImageGenerationConstants.donation_count_range)
make_param(parameters, 'r', DonationImageGenerationConstants.r_default, DonationImageGenerationConstants.color_range)
make_param(parameters, 'g', DonationImageGenerationConstants.g_default, DonationImageGenerationConstants.color_range)
make_param(parameters, 'b', DonationImageGenerationConstants.b_default, DonationImageGenerationConstants.color_range)
info_object = {
'parameters': parameters
}
return json.dumps(info_object)
@app.route('/debra/image/info')
def total_donations_image():
campaign_info = json.loads(requests.get(campaign_info_url).text)
logging.info(f'rendering campaign info')
parameters = parse_image_parameters()
if not parameters.validated:
return parameters.validation_message, 400
img = Image.new('RGBA', (parameters.canvas_width, parameters.canvas_height), (255, 0, 0, 0))
d1 = ImageDraw.Draw(img)
font = ImageFont.truetype(f'{parameters.font_name}.ttf', parameters.font_size)
d1.text((0, 0), f"{campaign_info['collected']}/{campaign_info['target']}", fill=parameters.color, font=font)
return serve_pil_image(img)
@app.route('/debra/image/latestDonations')
def latest_donation_image():
donation_stats = json.loads(requests.get(latest_donations_url).text)
logging.info(f'rendering latest donations')
parameters = parse_image_parameters()
if not parameters.validated:
return parameters.validation_message, 400
return rendering_donation_image(donation_stats, parameters)
@app.route('/debra/image/highestDonations')
def highest_donation_image():
donation_stats = json.loads(requests.get(highest_donations_url).text)
logging.info(f'rendering highest donations')
parameters = parse_image_parameters()
if not parameters.validated:
return parameters.validation_message, 400
return rendering_donation_image(donation_stats, parameters)
@app.route('/debra/image/highestDonations/html')
def highest_donations_image_html_wrapper():
refresh_interval = int(request.args.get('refreshInterval', 30, type=int))
random_bit = str(uuid.uuid4())
parameters_query = request.query_string.decode()
return render_template('image_refresh_wrapper.html', imagePath=f'/debra/image/highestDonations?{parameters_query}&{random_bit}', refreshInterval=refresh_interval)
@app.route('/debra/image/latestDonations/html')
def latest_donations_image_html_wrapper():
refresh_interval = int(request.args.get('refreshInterval', 30, type=int))
random_bit = str(uuid.uuid4())
parameters_query = request.query_string.decode()
return render_template('image_refresh_wrapper.html', imagePath=f'/debra/image/latestDonations?{parameters_query}&{random_bit}', refreshInterval=refresh_interval)
@app.route('/debra/image/info/html')
def total_donations_image_html_wrapper():
refresh_interval = int(request.args.get('refreshInterval', 30, type=int))
random_bit = str(uuid.uuid4())
parameters_query = request.query_string.decode()
return render_template('image_refresh_wrapper.html', imagePath=f'/debra/image/info?{parameters_query}&{random_bit}', refreshInterval=refresh_interval)
def rendering_donation_image(donation_stats, parameters):
img = Image.new('RGBA', (parameters.canvas_width, parameters.canvas_height), (255, 0, 0, 0))
d1 = ImageDraw.Draw(img)
font = ImageFont.truetype(f'{parameters.font_name}.ttf', parameters.font_size)
donations_to_draw = donation_stats['donations'][:parameters.donation_count]
height = parameters.font_size
it = 0
for donation in donations_to_draw:
name = donation['firstName'] if not donation['anonymous'] else 'anonym'
d1.text((0, height * it), f"{donation['donationAmount']}€ von {name}", fill=parameters.color, font=font)
it += 1
return serve_pil_image(img)
def parse_image_parameters() -> DonationImageGenerationParameters:
font = request.args.get('font', DonationImageGenerationConstants.font_default, type=str)
font_size = int(request.args.get('fontSize', DonationImageGenerationConstants.font_size_default, type=int))
canvas_width = int(request.args.get('canvasWidth', DonationImageGenerationConstants.canvas_width_default, type=int))
canvas_height = int(request.args.get('canvasHeight', DonationImageGenerationConstants.canvas_height_default, type=int))
donation_count = int(request.args.get('donationCount', DonationImageGenerationConstants.donation_count_default, type=int))
r = int(request.args.get('r', DonationImageGenerationConstants.r_default, type=int))
g = int(request.args.get('g', DonationImageGenerationConstants.g_default, type=int))
b = int(request.args.get('b', DonationImageGenerationConstants.b_default, type=int))
parameters = DonationImageGenerationParameters(font, font_size, canvas_width, canvas_height, donation_count, r, g, b)
parameters.validate()
return parameters
class DonationImageGenerationConstants:
allowed_fonts = ['Andale_Mono', 'Courier_New', 'Impact', 'Trebuchet_MS_Italic',
'Arial', 'Courier_New_Bold', 'Times_New_Roman', 'Verdana',
'Arial_Black', 'Courier_New_Bold_Italic', 'Times_New_Roman_Bold', 'Verdana_Bold',
'Arial_Bold', 'Courier_New_Italic', 'Times_New_Roman_Bold_Italic', 'Verdana_Bold_Italic',
'Arial_Bold_Italic', 'Georgia', 'Times_New_Roman_Italic', 'Verdana_Italic',
'Arial_Italic', 'Georgia_Bold', 'Trebuchet_MS',
'Comic_Sans_MS', 'Georgia_Bold_Italic', 'Trebuchet_MS_Bold',
'Comic_Sans_MS_Bold', 'Georgia_Italic', 'Trebuchet_MS_Bold_Italic']
font_range = (2, 150)
canvas_width_range = (1, 2500)
canvas_height_range = (1, 2500)
donation_count_range = (1, 25)
color_range = (0, 255)
font_default = 'Arial'
font_size_default = 40
canvas_width_default = 1024
canvas_height_default = 300
donation_count_default = 5
r_default = 0
g_default = 0
b_default = 0

View File

@@ -0,0 +1,19 @@
from __main__ import app
from PIL import Image, ImageDraw, ImageFont
from flask import request
from utils import serve_pil_image
@app.route('/memes/doge/orangeSun/')
def image_gen():
text = request.args.get('text')
with Image.open('res/img/semf_template.jpg') as im:
d1 = ImageDraw.Draw(im)
text_box_size = (300, 240)
W, H = text_box_size
font = ImageFont.truetype(f'Impact.ttf', 60)
_, _, w, h = d1.textbbox((0, 0), text, font=font)
d1.text(((W-w)/2 + 320, (H-h)/2 + 120), text, font=font, fill=(255, 255, 255))
return serve_pil_image(im)

View File

@@ -1,228 +1,22 @@
from flask import Flask, send_file, request
from io import BytesIO
from PIL import Image, ImageDraw, ImageFont
import requests
import os
import json
import logging
import os
from flask import Flask
FORMAT = '%(asctime)s - %(name)s - %(levelname)s - %(message)s'
logging.basicConfig(encoding='utf-8', level=logging.INFO, format=FORMAT)
app = Flask(__name__)
sissi_host = os.getenv('SISSI_HOST')
sissi_port = os.getenv('SISSI_PORT')
latest_donations_url = f'http://{sissi_host}:{sissi_port}/debra/latestDonations'
highest_donations_url = f'http://{sissi_host}:{sissi_port}/debra/highestDonations'
campaign_info_url = f'http://{sissi_host}:{sissi_port}/debra/campaignInfo'
class ValidationException(Exception):
def __init__(self, provided_value, message):
self.provided_value = provided_value
self.message = message
super().__init__(f'{self.message}: provided value: {provided_value}')
class DonationImageGenerationConstants:
allowed_fonts = ['Andale_Mono', 'Courier_New', 'Impact', 'Trebuchet_MS_Italic',
'Arial', 'Courier_New_Bold', 'Times_New_Roman', 'Verdana',
'Arial_Black', 'Courier_New_Bold_Italic', 'Times_New_Roman_Bold', 'Verdana_Bold',
'Arial_Bold', 'Courier_New_Italic', 'Times_New_Roman_Bold_Italic', 'Verdana_Bold_Italic',
'Arial_Bold_Italic', 'Georgia', 'Times_New_Roman_Italic', 'Verdana_Italic',
'Arial_Italic', 'Georgia_Bold', 'Trebuchet_MS',
'Comic_Sans_MS', 'Georgia_Bold_Italic', 'Trebuchet_MS_Bold',
'Comic_Sans_MS_Bold', 'Georgia_Italic', 'Trebuchet_MS_Bold_Italic']
font_range = (2, 150)
canvas_width_range = (1, 2500)
canvas_height_range = (1, 2500)
donation_count_range = (1, 25)
color_range = (0, 255)
font_default = 'Arial'
font_size_default = 40
canvas_width_default = 1024
canvas_height_default = 300
donation_count_default = 5
r_default = 0
g_default = 0
b_default = 0
class DonationImageGenerationParameters:
validation_message = ''
validation_value = ''
validated = None
def __init__(self, font_name, font_size, canvas_width, canvas_height, donation_count, r, g, b):
self.font_name = font_name
self.font_size = font_size
self.canvas_width = canvas_width
self.canvas_height = canvas_height
self.donation_count = donation_count
self.color = (r, g, b)
def validate(self):
self.validated = True
if self.font_name not in DonationImageGenerationConstants.allowed_fonts:
self.validated = False
self.validation_message = f'Font must be one of ' + ','.join(DonationImageGenerationConstants.allowed_fonts)
self.validation_value = self.font_name
if self.font_size > DonationImageGenerationConstants.font_range[1] or self.font_size < DonationImageGenerationConstants.font_range[0]:
self.validated = False
self.validation_message = f'Font size must be between {DonationImageGenerationConstants.font_range[0]} and {DonationImageGenerationConstants.font_range[1]}'
self.validation_value = self.font_size
if self.canvas_height > DonationImageGenerationConstants.canvas_height_range[1] or self.canvas_height < DonationImageGenerationConstants.canvas_height_range[0]:
self.validated = False
self.validation_message = f'Canvas height must be between {DonationImageGenerationConstants.canvas_height_range[0]} and {DonationImageGenerationConstants.canvas_height_range[1]}'
self.validation_value = self.canvas_height
if self.canvas_width > DonationImageGenerationConstants.canvas_width_range[1] or self.canvas_width < DonationImageGenerationConstants.canvas_width_range[0]:
self.validated = False
self.validation_message = f'Canvas width must be between {DonationImageGenerationConstants.canvas_width_range[0]} and {DonationImageGenerationConstants.color_range[1]}'
self.validation_value = self.canvas_width
if self.donation_count > DonationImageGenerationConstants.donation_count_range[1] or self.donation_count < DonationImageGenerationConstants.donation_count_range[0]:
self.validated = False
self.validation_message = f'Donation count must be between {DonationImageGenerationConstants.donation_count_range[0]} and {DonationImageGenerationConstants.donation_count_range[1]}'
self.validation_value = self.donation_count
if self.color[0] > DonationImageGenerationConstants.color_range[1] or self.color[0] < DonationImageGenerationConstants.color_range[0]:
self.validated = False
self.validation_message = f'Red must be between {DonationImageGenerationConstants.color_range[0]} and {DonationImageGenerationConstants.color_range[1]} inclusively'
self.validation_value = self.color[0]
if self.color[1] > DonationImageGenerationConstants.color_range[1] or self.color[1] < DonationImageGenerationConstants.color_range[0]:
self.validated = False
self.validation_message = f'Green must be between {DonationImageGenerationConstants.color_range[0]} and {DonationImageGenerationConstants.color_range[1]} inclusively'
self.validation_value = self.color[1]
if self.color[2] > DonationImageGenerationConstants.color_range[1] or self.color[2] < DonationImageGenerationConstants.color_range[0]:
self.validated = False
self.validation_message = f'Blue must be between {DonationImageGenerationConstants.color_range[0]} and {DonationImageGenerationConstants.color_range[1]} inclusively'
self.validation_value = self.color[2]
template_dir = os.path.abspath('res/templates')
app = Flask(__name__, template_folder=template_dir)
# loads the api end points
import debra
import image_gen
@app.route('/')
def hello():
return 'Hello, World?'
@app.route('/debra/latestDonations')
def latest_donations():
donation_stats = requests.get(latest_donations_url)
logging.info(f'returning latest donations')
return donation_stats.text
@app.route('/debra/highestDonations')
def highest_donations():
donation_stats = requests.get(highest_donations_url)
logging.info(f'returning highest donations')
return donation_stats.text
@app.route('/debra/campaignInfo')
def campaign_info_route():
donation_stats = requests.get(campaign_info_url)
logging.info(f'returning campaign info')
return donation_stats.text
@app.route('/debra/image/help')
def show_image_generation_help():
def make_param(parameters_obj, name, default, values):
parameters_obj[name] = {
'default': default,
'values': values
}
parameters = {}
make_param(parameters, 'font', DonationImageGenerationConstants.font_default, DonationImageGenerationConstants.allowed_fonts)
make_param(parameters, 'fontSize', DonationImageGenerationConstants.font_size_default, DonationImageGenerationConstants.font_range)
make_param(parameters, 'canvasWidth', DonationImageGenerationConstants.canvas_width_default, DonationImageGenerationConstants.canvas_width_range)
make_param(parameters, 'canvasHeight', DonationImageGenerationConstants.canvas_height_default, DonationImageGenerationConstants.canvas_height_range)
make_param(parameters, 'donationCount', DonationImageGenerationConstants.donation_count_default, DonationImageGenerationConstants.donation_count_range)
make_param(parameters, 'r', DonationImageGenerationConstants.r_default, DonationImageGenerationConstants.color_range)
make_param(parameters, 'g', DonationImageGenerationConstants.g_default, DonationImageGenerationConstants.color_range)
make_param(parameters, 'b', DonationImageGenerationConstants.b_default, DonationImageGenerationConstants.color_range)
info_object = {
'parameters': parameters
}
return json.dumps(info_object)
@app.route('/debra/image/info')
def total_donations_image():
campaign_info = json.loads(requests.get(campaign_info_url).text)
logging.info(f'rendering campaign info')
parameters = parse_image_parameters()
if not parameters.validated:
return parameters.validation_message, 400
img = Image.new('RGBA', (parameters.canvas_width, parameters.canvas_height), (255, 0, 0, 0))
d1 = ImageDraw.Draw(img)
font = ImageFont.truetype(f'{parameters.font_name}.ttf', parameters.font_size)
d1.text((0, 0), f"Aktuell {campaign_info['collected']}/{campaign_info['target']}", fill=parameters.color, font=font)
return serve_pil_image(img)
@app.route('/debra/image/latestDonations')
def latest_donation_image():
donation_stats = json.loads(requests.get(latest_donations_url).text)
logging.info(f'rendering latest donations')
parameters = parse_image_parameters()
if not parameters.validated:
return parameters.validation_message, 400
return rendering_donation_image(donation_stats, parameters)
@app.route('/debra/image/highestDonations')
def highest_donation_image():
donation_stats = json.loads(requests.get(highest_donations_url).text)
logging.info(f'rendering highest donations')
parameters = parse_image_parameters()
if not parameters.validated:
return parameters.validation_message, 400
return rendering_donation_image(donation_stats, parameters)
def rendering_donation_image(donation_stats, parameters):
img = Image.new('RGBA', (parameters.canvas_width, parameters.canvas_height), (255, 0, 0, 0))
d1 = ImageDraw.Draw(img)
font = ImageFont.truetype(f'{parameters.font_name}.ttf', parameters.font_size)
donations_to_draw = donation_stats['donations'][:parameters.donation_count]
height = parameters.font_size
it = 0
for donation in donations_to_draw:
name = donation['firstName'] if not donation['anonymous'] else 'anonym'
d1.text((0, height * it), f"{donation['donationAmount']}€ von {name}", fill=parameters.color, font=font)
it += 1
return serve_pil_image(img)
def parse_image_parameters() -> DonationImageGenerationParameters:
font = request.args.get('font', DonationImageGenerationConstants.font_default)
font_size = int(request.args.get('fontSize', DonationImageGenerationConstants.font_size_default))
canvas_width = int(request.args.get('canvasWidth', DonationImageGenerationConstants.canvas_width_default))
canvas_height = int(request.args.get('canvasHeight', DonationImageGenerationConstants.canvas_height_default))
donation_count = int(request.args.get('donationCount', DonationImageGenerationConstants.donation_count_default))
r = int(request.args.get('r', DonationImageGenerationConstants.r_default))
g = int(request.args.get('g', DonationImageGenerationConstants.g_default))
b = int(request.args.get('b', DonationImageGenerationConstants.b_default))
parameters = DonationImageGenerationParameters(font, font_size, canvas_width, canvas_height, donation_count, r, g, b)
parameters.validate()
return parameters
def serve_pil_image(pil_img):
img_io = BytesIO()
pil_img.save(img_io, 'PNG')
img_io.seek(0)
return send_file(img_io, mimetype='image/png')
if __name__ == "__main__":
from waitress import serve

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

View File

@@ -0,0 +1,7 @@
<meta http-equiv="refresh" content="{{ refreshInterval }}">
<html>
<head></head>
<body>
<img src="{{ imagePath }}">
</body>
</html>

View File

@@ -0,0 +1,17 @@
from io import BytesIO
from flask import send_file
def serve_pil_image(pil_img):
img_io = BytesIO()
pil_img.save(img_io, 'PNG')
img_io.seek(0)
return send_file(img_io, mimetype='image/png')
class ValidationException(Exception):
def __init__(self, provided_value, message):
self.provided_value = provided_value
self.message = message
super().__init__(f'{self.message}: provided value: {provided_value}')

View File

@@ -3,7 +3,7 @@
<parent>
<groupId>dev.sheldan.sissi</groupId>
<artifactId>sissi</artifactId>
<version>1.4.23</version>
<version>1.4.28</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@@ -3,7 +3,7 @@
<parent>
<groupId>dev.sheldan.sissi.templates</groupId>
<artifactId>customization-templates</artifactId>
<version>1.4.23</version>
<version>1.4.28</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@@ -3,7 +3,7 @@
<parent>
<artifactId>sissi-templates</artifactId>
<groupId>dev.sheldan.sissi.templates</groupId>
<version>1.4.23</version>
<version>1.4.28</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@@ -3,7 +3,7 @@
<parent>
<artifactId>module-templates</artifactId>
<groupId>dev.sheldan.sissi.templates</groupId>
<version>1.4.23</version>
<version>1.4.28</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@@ -3,7 +3,7 @@
<parent>
<artifactId>module-templates</artifactId>
<groupId>dev.sheldan.sissi.templates</groupId>
<version>1.4.23</version>
<version>1.4.28</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@@ -3,7 +3,7 @@
"embeds": [
{
<#include "abstracto_color">,
<#assign time><@format_instant_date_time instant=meetupTime/></#assign>
<#assign time><@format_instant_long_date_time instant=meetupTime/></#assign>
<#assign topicText>${topic?json_string}</#assign>
"description": "<#include "meetup_cancel_notification_description">"
}

View File

@@ -6,7 +6,7 @@
"title": {
"title": "${topic?json_string}"
},
"description": "<@format_instant_date_time instant=meetupTime/>
"description": "<@format_instant_long_date_time instant=meetupTime/>
${description?json_string}"
}
],

View File

@@ -4,8 +4,8 @@
{
<#include "abstracto_color">,
<#assign topicText=meetupTopic>
<#assign oldTime><@format_instant_date_time instant=oldDate/></#assign>
<#assign newTime><@format_instant_date_time instant=newDate/></#assign>
<#assign oldTime><@format_instant_long_date_time instant=oldDate/></#assign>
<#assign newTime><@format_instant_long_date_time instant=newDate/></#assign>
<#assign messageLink=meetupMessage.jumpUrl>
"description": "<@safe_include "changeMeetupTime_notification_text"/>"
}

View File

@@ -6,7 +6,7 @@
"title": {
"title": "${topic?json_string}"
},
"description": "<@format_instant_date_time instant=meetupTime/>
"description": "<@format_instant_long_date_time instant=meetupTime/>
${description?json_string}"
<#if location?? && location != "%22%22">,
"fields": [

View File

@@ -3,7 +3,7 @@
"embeds": [
{
<#include "abstracto_color">,
"description": "<#list meetups as meetup><#assign meetup=meetup><#assign topic=meetup.topic><#assign time><@format_instant_date_time instant=meetup.meetupTime/></#assign><#assign timeRelative><@format_instant_relative instant=meetup.meetupTime/></#assign><#assign link=meetup.meetupMessage.jumpUrl><#include "meetup_list_meetup_display">
"description": "<#list meetups as meetup><#assign meetup=meetup><#assign topic=meetup.topic><#assign time><@format_instant_long_date_time instant=meetup.meetupTime/></#assign><#assign timeRelative><@format_instant_relative instant=meetup.meetupTime/></#assign><#assign link=meetup.meetupMessage.jumpUrl><#include "meetup_list_meetup_display">
<#else><#include "meetup_list_no_meetups"></#list>"
}
]

View File

@@ -8,7 +8,7 @@
"title": {
"title": "${topic?json_string} - <@safe_include "meetup_message_id_display"/>"
},
<#assign time><@format_instant_date_time instant=meetupTime/></#assign>
<#assign time><@format_instant_long_date_time instant=meetupTime/></#assign>
<#assign timeRelative><@format_instant_relative instant=meetupTime/></#assign>
<#assign organizerText>${organizer.memberMention}</#assign>
<#assign meetupId=meetupId/>

View File

@@ -3,7 +3,7 @@
"embeds": [
{
<#include "abstracto_color">,
<#assign time><@format_instant_date_time instant=meetupTime/></#assign>
<#assign time><@format_instant_long_date_time instant=meetupTime/></#assign>
<#assign topicText>${topic?json_string}</#assign>
"description": "<#include "meetup_reminder_notification_description">"
}

View File

@@ -3,7 +3,7 @@
<parent>
<groupId>dev.sheldan.sissi.templates</groupId>
<artifactId>sissi-templates</artifactId>
<version>1.4.23</version>
<version>1.4.28</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@@ -3,7 +3,7 @@
<parent>
<groupId>dev.sheldan.sissi.templates</groupId>
<artifactId>module-templates</artifactId>
<version>1.4.23</version>
<version>1.4.28</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@@ -3,7 +3,7 @@
<parent>
<artifactId>module-templates</artifactId>
<groupId>dev.sheldan.sissi.templates</groupId>
<version>1.4.23</version>
<version>1.4.28</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@@ -3,7 +3,7 @@
<parent>
<groupId>dev.sheldan.sissi.templates</groupId>
<artifactId>templates</artifactId>
<version>1.4.23</version>
<version>1.4.28</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@@ -3,7 +3,7 @@
<parent>
<groupId>dev.sheldan.sissi.templates</groupId>
<artifactId>template-overrides</artifactId>
<version>1.4.23</version>
<version>1.4.28</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@@ -3,7 +3,7 @@
<parent>
<groupId>dev.sheldan.sissi.templates</groupId>
<artifactId>template-overrides</artifactId>
<version>1.4.23</version>
<version>1.4.28</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@@ -3,7 +3,7 @@
<parent>
<groupId>dev.sheldan.sissi.templates</groupId>
<artifactId>template-overrides</artifactId>
<version>1.4.23</version>
<version>1.4.28</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@@ -3,7 +3,7 @@
<parent>
<artifactId>sissi-templates</artifactId>
<groupId>dev.sheldan.sissi.templates</groupId>
<version>1.4.23</version>
<version>1.4.28</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@@ -3,7 +3,7 @@
<parent>
<groupId>dev.sheldan.sissi.templates.translations</groupId>
<artifactId>customization-translations</artifactId>
<version>1.4.23</version>
<version>1.4.28</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@@ -3,7 +3,7 @@
<parent>
<artifactId>sissi-translations</artifactId>
<groupId>dev.sheldan.sissi.templates.translations</groupId>
<version>1.4.23</version>
<version>1.4.28</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@@ -3,7 +3,7 @@
<parent>
<artifactId>module-translations</artifactId>
<groupId>dev.sheldan.sissi.templates.translations</groupId>
<version>1.4.23</version>
<version>1.4.28</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@@ -3,7 +3,7 @@
<parent>
<groupId>dev.sheldan.sissi.templates.translations</groupId>
<artifactId>module-translations</artifactId>
<version>1.4.23</version>
<version>1.4.28</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@@ -3,7 +3,7 @@
<parent>
<groupId>dev.sheldan.sissi.templates.translations</groupId>
<artifactId>sissi-translations</artifactId>
<version>1.4.23</version>
<version>1.4.28</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@@ -3,7 +3,7 @@
<parent>
<groupId>dev.sheldan.sissi.templates.translations</groupId>
<artifactId>module-translations</artifactId>
<version>1.4.23</version>
<version>1.4.28</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@@ -3,7 +3,7 @@
<parent>
<artifactId>module-translations</artifactId>
<groupId>dev.sheldan.sissi.templates.translations</groupId>
<version>1.4.23</version>
<version>1.4.28</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@@ -3,7 +3,7 @@
<parent>
<groupId>dev.sheldan.sissi.templates</groupId>
<artifactId>templates</artifactId>
<version>1.4.23</version>
<version>1.4.28</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@@ -3,7 +3,7 @@
<parent>
<groupId>dev.sheldan.sissi.templates.translations.overrides</groupId>
<artifactId>translation-overrides</artifactId>
<version>1.4.23</version>
<version>1.4.28</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@@ -3,7 +3,7 @@
<parent>
<groupId>dev.sheldan.sissi.templates.translations.overrides</groupId>
<artifactId>translation-overrides</artifactId>
<version>1.4.23</version>
<version>1.4.28</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@@ -3,7 +3,7 @@
<parent>
<groupId>dev.sheldan.sissi.templates.translations.overrides</groupId>
<artifactId>translation-overrides</artifactId>
<version>1.4.23</version>
<version>1.4.28</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@@ -3,7 +3,7 @@
<parent>
<groupId>dev.sheldan.sissi.templates.translations</groupId>
<artifactId>sissi-translations</artifactId>
<version>1.4.23</version>
<version>1.4.28</version>
</parent>
<modelVersion>4.0.0</modelVersion>