diff --git a/files/assets/css/main.css b/files/assets/css/main.css index 806619bf1..094a57e69 100644 --- a/files/assets/css/main.css +++ b/files/assets/css/main.css @@ -4582,6 +4582,13 @@ div.deleted.banned { .patron[style="background-color:#FFFFFF;"] { color: black !important; } +.post--category-tag { + padding: 2px 5px 3px 5px; + border-radius: 5px; + font-size: 12px; + font-weight: 700; + margin-right: 0.25rem; +} .container, .container-fluid { background-color: var(--background) !important; } @@ -5686,6 +5693,19 @@ g { border-radius:.35rem; } +.category--tag-button { + display: inline-block; + cursor: pointer; +} + +#submit-categories input { + display: none; +} + +#submit-categories input:checked + label { + border: 5px var(--black) double; +} + /* ------- Font Awesome ------- */ @font-face{ font-family:"Font Awesome 6 Pro"; @@ -6038,6 +6058,7 @@ g { .fa-circle-info:before{content:"\f05a"} .fa-comment-question:before{content:"\e14b"} .fa-sitemap:before{content:"\f0e8"} +.fa-grid:before{content:"\e195"} .pronouns { font-size: 9px; diff --git a/files/assets/js/category_modal.js b/files/assets/js/category_modal.js new file mode 100644 index 000000000..5f353cecc --- /dev/null +++ b/files/assets/js/category_modal.js @@ -0,0 +1,41 @@ +function category_modal(id, title, sub) { + document.getElementById("category-modal-title").innerHTML = `Category: ${title}`; + + xhrCategories = new XMLHttpRequest(); + xhrCategories.open("GET", "/categories.json"); + xhrCategories.onload = function () { + let data; + try { + data = JSON.parse(xhrCategories.response); + } catch(e) { console.log(e) } + + categories = [{id: '', name: 'None', sub: sub, color_text: '#000', color_bg: '#FFF'}]; + categories = [].concat(categories, data[sub]); + + document.getElementById("category-modal-body").innerHTML = ''; + categories.forEach(function (c) { + document.getElementById("category-modal-body").innerHTML += + `
`; + }); + + document.querySelectorAll('.category--tag-button').forEach(tag => + tag.addEventListener('click', function (e) { + reqBody = new FormData(); + reqBody.append('formkey', formkey()); + reqBody.append('post_id', id); + reqBody.append('category_id', tag.dataset.category); + + xhrSubmit = new XMLHttpRequest(); + xhrSubmit.open('POST', `/post_recategorize`); + xhrSubmit.onload = function () { + window.location.reload(); + } + xhrSubmit.send(reqBody); + }) + ); + } + xhrCategories.send(); +} diff --git a/files/assets/js/submit.js b/files/assets/js/submit.js index e9196bd8a..63982e9ba 100644 --- a/files/assets/js/submit.js +++ b/files/assets/js/submit.js @@ -169,6 +169,31 @@ function checkRepost() { } } +function updateCategories() { + if (document.getElementById("submit-categories") == null) { + return; + } + sub = document.getElementById("sub").value; + + xhrCategories = new XMLHttpRequest(); + xhrCategories.open("GET", "/categories.json"); + xhrCategories.onload = function () { + let data; + try { + data = JSON.parse(xhrCategories.response); + } catch(e) { console.log(e) } + + document.getElementById("submit-categories").innerHTML = ''; + data[sub].forEach(function (c) { + document.getElementById("submit-categories").innerHTML += + `` + + ``; + }); + } + xhrCategories.send(); +} document.addEventListener('keydown', (e) => { if(!((e.ctrlKey || e.metaKey) && e.key === "Enter")) @@ -179,4 +204,5 @@ document.addEventListener('keydown', (e) => { submitButton.click(); }); -checkRepost() \ No newline at end of file +checkRepost(); +updateCategories(); diff --git a/files/classes/__init__.py b/files/classes/__init__.py index 6723e92a2..1fd0f795c 100644 --- a/files/classes/__init__.py +++ b/files/classes/__init__.py @@ -8,6 +8,7 @@ from .user import * from .userblock import * from .submission import * from .votes import * +from .category import * from .domains import * from .subscriptions import * from files.__main__ import app @@ -20,4 +21,4 @@ from .saves import * from .views import * from .notifications import * from .follows import * -from .lottery import * \ No newline at end of file +from .lottery import * diff --git a/files/classes/category.py b/files/classes/category.py new file mode 100644 index 000000000..655e711d6 --- /dev/null +++ b/files/classes/category.py @@ -0,0 +1,22 @@ +from sqlalchemy import * +from sqlalchemy.orm import relationship +from files.__main__ import Base + +class Category(Base): + __tablename__ = "category" + + id = Column(Integer, primary_key=True, nullable=False) + name = Column(String(128), nullable=False) + sub = Column(String(20), ForeignKey("subs.name")) + color_text = Column(String(6)) + color_bg = Column(String(6)) + + def as_json(self): + data = { + 'id': self.id, + 'name': self.name, + 'sub': self.sub if self.sub else '', + 'color_text': '#' + self.color_text, + 'color_bg': '#' + self.color_bg, + } + return data diff --git a/files/classes/mod_logs.py b/files/classes/mod_logs.py index 4ac311a8c..a6aef3dfe 100644 --- a/files/classes/mod_logs.py +++ b/files/classes/mod_logs.py @@ -303,6 +303,11 @@ ACTIONTYPES = { "icon": 'fa-thumbtack fa-rotate--45', "color": 'bg-success' }, + 'post_recategorize': { + "str": 'changed category of {self.target_link}', + "icon": 'fa-grid', + "color": 'bg-primary' + }, 'purge_cache': { "str": 'purged cache', "icon": 'fa-memory', diff --git a/files/classes/submission.py b/files/classes/submission.py index 786096345..b0a493457 100644 --- a/files/classes/submission.py +++ b/files/classes/submission.py @@ -53,6 +53,7 @@ class Submission(Base): body = Column(String) body_html = Column(String) flair = Column(String) + category_id = Column(Integer, ForeignKey("category.id")) ban_reason = Column(String) embed_url = Column(String) new = Column(Boolean) @@ -65,6 +66,7 @@ class Submission(Base): comments = relationship("Comment", primaryjoin="Comment.parent_submission==Submission.id", back_populates="post") subr = relationship("Sub", primaryjoin="foreign(Submission.sub)==remote(Sub.name)") options = relationship("SubmissionOption", order_by="SubmissionOption.id") + category = relationship("Category", primaryjoin="Submission.category_id==Category.id") bump_utc = deferred(Column(Integer, server_default=FetchedValue())) diff --git a/files/helpers/const.py b/files/helpers/const.py index f5599610e..b916da659 100644 --- a/files/helpers/const.py +++ b/files/helpers/const.py @@ -132,6 +132,8 @@ AGENDAPOSTER_MSG_HTML = """Hi ")
+@admin_level_required(PERMS['ADMIN_CATEGORIES_MANAGE'])
+def admin_categories_update(v, cid):
+ if not FEATURES['CATEGORIES']:
+ abort(404)
+
+ cat_name = request.values.get("name").strip()
+ cat_color_text = request.values.get("color_text").strip().strip('#').lower()
+ cat_color_bg = request.values.get("color_bg").strip().strip('#').lower()
+
+ try:
+ cat_id = int(cid)
+ except:
+ abort(400)
+
+ cat = g.db.query(Category).filter(Category.id == cat_id).one_or_none()
+ if not cat:
+ abort(400)
+
+ cat.name = cat_name
+ cat.color_text = cat_color_text
+ cat.color_bg = cat_color_bg
+
+ g.db.add(cat)
+ g.db.commit()
+
+ return redirect("/admin/categories")
+
+@app.post("/admin/categories/delete/API Access Control
-
-
-
{% if LOTTERY_ENABLED -%}
Lottery
@@ -75,6 +70,10 @@
Configuration
{% if v.admin_level > 2 %}
diff --git a/files/templates/admin/categories.html b/files/templates/admin/categories.html
new file mode 100644
index 000000000..e279f581c
--- /dev/null
+++ b/files/templates/admin/categories.html
@@ -0,0 +1,51 @@
+{% extends "default.html" %}
+
+{% block title %}
+
+
+
+{% endblock %}
diff --git a/files/templates/category_modal.html b/files/templates/category_modal.html
new file mode 100644
index 000000000..504bb6450
--- /dev/null
+++ b/files/templates/category_modal.html
@@ -0,0 +1,16 @@
+
+
+
diff --git a/files/templates/comments.html b/files/templates/comments.html
index 5474c5668..b8b4b8cc7 100644
--- a/files/templates/comments.html
+++ b/files/templates/comments.html
@@ -795,6 +795,9 @@
{% include "emoji_modal.html" %}
{% if v.admin_level > 1 %}
{% include "ban_modal.html" %}
+ {% if FEATURES['CATEGORIES'] -%}
+ {% include "category_modal.html" %}
+ {%- endif %}
{% endif %}
+
+
+
+ {% for category in categories %}
+ Category
+ {{ HOLE_NAME | capitalize }}
+ Name
+ Text Color
+ Background Color
+ Actions
+
+
+
+ {% endfor %}
+
+ {{help.submission_category_tag(category.name, category.color_text, category.color_bg)}}
+ {{category.sub if category.sub else '—'|safe}}
+
+
+
+
+
+