diff --git a/app/blueprints/packages/packages.py b/app/blueprints/packages/packages.py
index 5d8711a..2dd0340 100644
--- a/app/blueprints/packages/packages.py
+++ b/app/blueprints/packages/packages.py
@@ -32,9 +32,10 @@ from app.rediscache import has_key, set_key
from app.tasks.importtasks import importRepoScreenshot
from app.utils import *
from . import bp, get_package_tabs
-from ...logic.LogicError import LogicError
-from ...logic.packages import do_edit_package
+from app.logic.LogicError import LogicError
+from app.logic.packages import do_edit_package
from app.models.packages import PackageProvides
+from app.tasks.webhooktasks import post_discord_webhook
@menu.register_menu(bp, ".mods", "Mods", order=11, endpoint_arguments_constructor=lambda: { 'type': 'mod' })
@@ -370,6 +371,8 @@ def move_to_state(package):
if state == PackageState.APPROVED:
if not package.approved_at:
+ post_discord_webhook.delay(package.author.username,
+ "New package {}".format(package.getURL("packages.view", absolute=True)), False)
package.approved_at = datetime.datetime.now()
screenshots = PackageScreenshot.query.filter_by(package=package, approved=False).all()
@@ -377,6 +380,9 @@ def move_to_state(package):
s.approved = True
msg = "Approved {}".format(package.title)
+ elif state == PackageState.READY_FOR_REVIEW:
+ post_discord_webhook.delay(package.author.username,
+ "Ready for Review: {}".format(package.getURL("packages.view", absolute=True)), True)
addNotification(package.maintainers, current_user, NotificationType.PACKAGE_APPROVAL, msg, package.getURL("packages.view"), package)
severity = AuditSeverity.NORMAL if current_user in package.maintainers else AuditSeverity.EDITOR
diff --git a/app/blueprints/packages/reviews.py b/app/blueprints/packages/reviews.py
index 4523a7f..0d8c5e0 100644
--- a/app/blueprints/packages/reviews.py
+++ b/app/blueprints/packages/reviews.py
@@ -23,6 +23,7 @@ from wtforms import *
from wtforms.validators import *
from app.models import db, PackageReview, Thread, ThreadReply, NotificationType
from app.utils import is_package_page, addNotification, get_int_or_abort
+from app.tasks.webhooktasks import post_discord_webhook
@bp.route("/reviews/")
@@ -108,6 +109,10 @@ def review(package):
addNotification(package.maintainers, current_user, type, notif_msg,
url_for("threads.view", id=thread.id), package)
+ if was_new:
+ post_discord_webhook.delay(thread.author.username,
+ "Reviewed {}: {}".format(package.title, thread.getViewURL(absolute=True)), False)
+
db.session.commit()
return redirect(package.getURL("packages.view"))
diff --git a/app/blueprints/threads/__init__.py b/app/blueprints/threads/__init__.py
index 710d435..7afbdd5 100644
--- a/app/blueprints/threads/__init__.py
+++ b/app/blueprints/threads/__init__.py
@@ -15,6 +15,8 @@
# along with this program. If not, see .
from flask import *
+from app.tasks.webhooktasks import post_discord_webhook
+
bp = Blueprint("threads", __name__)
from flask_login import current_user, login_required
@@ -243,6 +245,8 @@ def view(id):
approvers = User.query.filter(User.rank >= UserRank.APPROVER).all()
addNotification(approvers, current_user, NotificationType.EDITOR_MISC, msg,
thread.getViewURL(), thread.package)
+ post_discord_webhook.delay(current_user.username,
+ "Replied to bot messages: {}".format(thread.getViewURL(absolute=True)), True)
db.session.commit()
@@ -331,7 +335,6 @@ def new():
if is_review_thread:
package.review_thread = thread
-
notif_msg = "New thread '{}'".format(thread.title)
if package is not None:
addNotification(package.maintainers, current_user, NotificationType.NEW_THREAD, notif_msg, thread.getViewURL(), package)
@@ -339,6 +342,10 @@ def new():
approvers = User.query.filter(User.rank >= UserRank.APPROVER).all()
addNotification(approvers, current_user, NotificationType.EDITOR_MISC, notif_msg, thread.getViewURL(), package)
+ if is_review_thread:
+ post_discord_webhook.delay(current_user.username,
+ "Opened approval thread: {}".format(thread.getViewURL(absolute=True)), True)
+
db.session.commit()
return redirect(thread.getViewURL())
diff --git a/app/models/threads.py b/app/models/threads.py
index f002942..13dae75 100644
--- a/app/models/threads.py
+++ b/app/models/threads.py
@@ -54,8 +54,19 @@ class Thread(db.Model):
watchers = db.relationship("User", secondary=watchers, backref="watching")
- def getViewURL(self):
- return url_for("threads.view", id=self.id, _external=False)
+ def get_description(self):
+ comment = self.replies[0].comment.replace("\r\n", " ").replace("\n", " ").replace(" ", " ")
+ if len(comment) > 100:
+ return comment[:97] + "..."
+ else:
+ return comment
+
+ def getViewURL(self, absolute=False):
+ if absolute:
+ from ..utils import abs_url_for
+ return abs_url_for("threads.view", id=self.id)
+ else:
+ return url_for("threads.view", id=self.id, _external=False)
def getSubscribeURL(self):
return url_for("threads.subscribe", id=self.id)
diff --git a/app/tasks/webhooktasks.py b/app/tasks/webhooktasks.py
new file mode 100644
index 0000000..0abcf72
--- /dev/null
+++ b/app/tasks/webhooktasks.py
@@ -0,0 +1,40 @@
+# ContentDB
+# Copyright (C) 2021 rubenwardy
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see .
+from typing import Optional
+
+import requests
+
+from app import app
+from app.models import User
+from app.tasks import celery
+
+@celery.task()
+def post_discord_webhook(username: Optional[str], content: str, is_queue: bool):
+ discord_url = app.config.get("DISCORD_WEBHOOK_QUEUE" if is_queue else "DISCORD_WEBHOOK_FEED")
+ if discord_url is None:
+ return
+
+ json = {
+ "content": content,
+ }
+
+ if username:
+ json["username"] = username
+ user = User.query.filter_by(username=username).first()
+ if user:
+ json["avatar_url"] = user.getProfilePicURL().replace("/./", "/")
+
+ requests.post(discord_url, json=json)
diff --git a/app/templates/threads/view.html b/app/templates/threads/view.html
index 23c3232..bff5c33 100644
--- a/app/templates/threads/view.html
+++ b/app/templates/threads/view.html
@@ -1,7 +1,26 @@
{% extends "base.html" %}
{% block title %}
-{{ thread.title }} - {{ _("Threads") }}
+ {%- if thread.package -%}
+ {%- if thread.review -%}
+ {%- if thread.review.recommends -%}
+ {%- set rating = "👍" -%}
+ {%- else -%}
+ {%- set rating = "👎" -%}
+ {%- endif -%}
+ {%- endif -%}
+ {{ rating }} {{ _("%(title)s on %(package)s", title=thread.title, package=thread.package.title) }}
+ {%- else -%}
+ {{ thread.title }}
+ {%- endif -%}
+{% endblock %}
+
+{% block headextra %}
+
+
+
+
+
{% endblock %}
{% block content %}
diff --git a/config.example.cfg b/config.example.cfg
index d933832..fa974ec 100644
--- a/config.example.cfg
+++ b/config.example.cfg
@@ -28,6 +28,9 @@ MAIL_UTILS_ERROR_SEND_TO = [""]
UPLOAD_DIR = "/var/cdb/uploads/"
THUMBNAIL_DIR = "/var/cdb/thumbnails/"
+DISCORD_WEBHOOK_FEED = None
+DISCORD_WEBHOOK_QUEUE = None
+
TEMPLATES_AUTO_RELOAD = False
LOG_SQL = False