add edit logs

pull/225/head
Aevann 2024-03-08 00:52:55 +02:00
parent fa80540fc6
commit 18ba6becd3
12 changed files with 159 additions and 4 deletions

View File

@ -38,3 +38,5 @@ from .currency_logs import *
if FEATURES['IP_LOGGING']:
from .ip_logs import *
from .edit_logs import *

View File

@ -232,6 +232,7 @@ class Comment(Base):
options = relationship("CommentOption", order_by="CommentOption.id")
casino_game = relationship("CasinoGame")
wall_user = relationship("User", primaryjoin="User.id==Comment.wall_user_id")
edits = relationship("CommentEdit", order_by="CommentEdit.id.desc()")
def __init__(self, *args, **kwargs):
if "created_utc" not in kwargs:

View File

@ -0,0 +1,38 @@
import time
from sqlalchemy import Column, ForeignKey
from sqlalchemy.sql.sqltypes import *
from files.classes import Base
class PostEdit(Base):
__tablename__ = "post_edits"
id = Column(Integer, primary_key=True)
post_id = Column(Integer, ForeignKey("posts.id"))
old_body = Column(String)
old_body_html = Column(String)
old_title = Column(String)
old_title_html = Column(String)
created_utc = Column(Integer)
def __init__(self, *args, **kwargs):
if "created_utc" not in kwargs: kwargs["created_utc"] = int(time.time())
super().__init__(*args, **kwargs)
def __repr__(self):
return f"<{self.__class__.__name__}(id={self.id})>"
class CommentEdit(Base):
__tablename__ = "comment_edits"
id = Column(Integer, primary_key=True)
comment_id = Column(Integer, ForeignKey("comments.id"))
old_body = Column(String)
old_body_html = Column(String)
created_utc = Column(Integer)
def __init__(self, *args, **kwargs):
if "created_utc" not in kwargs: kwargs["created_utc"] = int(time.time())
super().__init__(*args, **kwargs)
def __repr__(self):
return f"<{self.__class__.__name__}(id={self.id})>"

View File

@ -85,6 +85,7 @@ class Post(Base):
comments = relationship("Comment", primaryjoin="Comment.parent_post==Post.id", back_populates="post")
hole_obj = relationship("Hole", primaryjoin="foreign(Post.hole)==remote(Hole.name)")
options = relationship("PostOption", order_by="PostOption.id")
edits = relationship("PostEdit", order_by="PostEdit.id.desc()")
def __init__(self, *args, **kwargs):
if "created_utc" not in kwargs:

View File

@ -171,6 +171,7 @@ PERMS = { # Minimum admin_level to perform action.
'VIEW_ACTIVE_USERS': 1,
'VIEW_ALT_VOTES': 1,
'VIEW_LAST_ACTIVE': 1,
'VIEW_EDITS': 1,
'ENABLE_VOTE_BUTTONS_ON_USER_PAGE': 1,
'NOTIFICATIONS_MODERATOR_ACTIONS': 1,
'EXEMPT_FROM_IP_LOGGING': 1,

View File

@ -2231,3 +2231,16 @@ def unmark_effortpost(pid, v):
send_repeatable_notification(p.author_id, f":marseyitsover: @{v.username} (a site admin) has unmarked {p.textlink} as an effortpost. {coins} coins have been deducted from you. :!marseyitsover:")
return {"message": "Post has been unmarked as an effortpost!"}
@app.get("/edits/<link>")
@limiter.limit(DEFAULT_RATELIMIT, deduct_when=lambda response: response.status_code < 400)
@limiter.limit(DEFAULT_RATELIMIT, deduct_when=lambda response: response.status_code < 400, key_func=get_ID)
@admin_level_required(PERMS['VIEW_EDITS'])
def view_edits(v, link):
try:
if "p_" in link: obj = get_post(int(link.split("p_")[1]), v=v)
elif "c_" in link: obj = get_comment(int(link.split("c_")[1]), v=v)
else: abort(400)
except: abort(400)
return render_template("edits.html", v=v, obj=obj)

View File

@ -637,6 +637,13 @@ def edit_comment(cid, v):
if c.author.hieroglyphs and marseyaward_body_regex.search(body_html):
abort(403, "You can only type marseys!")
edit_log = CommentEdit(
comment_id=c.id,
old_body=c.body,
old_body_html=c.body_html,
)
g.db.add(edit_log)
oldtext = c.body
c.body = body

View File

@ -1057,6 +1057,14 @@ def edit_post(pid, v):
changed = False
edit_log = PostEdit(
post_id=p.id,
old_title=p.title,
old_title_html=p.title_html,
old_body=p.body,
old_body_html=p.body_html,
)
g.db.add(edit_log)
if title != p.title:
title_html = filter_emojis_only(title, golden=False, obj=p, author=p.author)

View File

@ -233,9 +233,15 @@
<a class="vertical-align ml-1" href="{{c.permalink}}">#{{c.id}}</a>
<span class="{% if not c.edited_utc %}d-none{% endif %} font-italic" data-nonce="{{g.nonce}}" data-bs-toggle="tooltip" data-bs-placement="bottom" data-onmouseover="timestamp(this, '{{c.edited_utc}}')">
&nbsp; Edited <span id="comment-edited_string-{{c.id}}">{{c.edited_string}}</span>
</span>
{% if c.edited_utc and v and v.admin_level >= PERMS['VIEW_EDITS'] %}
<a href="/edits/{{c.fullname}}" class="font-italic" data-nonce="{{g.nonce}}" data-bs-toggle="tooltip" data-bs-placement="bottom" data-onmouseover="timestamp(this, '{{c.edited_utc}}')">
&nbsp; Edited <span id="comment-edited_string-{{c.id}}">{{c.edited_string}}</span>
</a>
{% else %}
<span class="{% if not c.edited_utc %}d-none{% endif %} font-italic" data-nonce="{{g.nonce}}" data-bs-toggle="tooltip" data-bs-placement="bottom" data-onmouseover="timestamp(this, '{{c.edited_utc}}')">
&nbsp; Edited <span id="comment-edited_string-{{c.id}}">{{c.edited_string}}</span>
</span>
{% endif %}
{% if c.treasure_amount and c.treasure_amount != '0' %}
{% if c.treasure_amount.startswith('l') %}

View File

@ -0,0 +1,26 @@
{% extends "default.html" %}
{% block pagetitle %}Edits on {{obj.shortlink}}{% endblock %}
{% block content %}
<h2>Edits on {{obj.textlink | safe}}</h2>
<div class="overflow-x-auto">
<table>
<thead>
<tr>
{% if obj.fullname.startswith('p_') %}
<th>Title</th>
{% endif %}
<th>Body</th>
</tr>
</thead>
{% for edit in obj.edits %}
<tr>
{% if obj.fullname.startswith('p_') %}
<td>{{edit.old_title_html | safe}}</td>
{% endif %}
<td>{{edit.old_body_html | safe}}</td>
</tr>
{% endfor %}
</table>
</div>
{% endblock %}

View File

@ -125,7 +125,11 @@
{% endif %}
{% if p.edited_utc %}
<span class="ml-2 d-inline-block">Edited <span data-bs-toggle="tooltip" data-bs-placement="bottom" id="edited_timestamp-{{p.id}}" data-nonce="{{g.nonce}}" data-onmouseover="timestamp(this, '{{p.edited_utc}}')">{{p.edited_string}}</span></span>
{% if v and v.admin_level >= PERMS['VIEW_EDITS'] %}
<a href="/edits/{{p.fullname}}" class="ml-2 d-inline-block">Edited <span data-bs-toggle="tooltip" data-bs-placement="bottom" id="edited_timestamp-{{p.id}}" data-nonce="{{g.nonce}}" data-onmouseover="timestamp(this, '{{p.edited_utc}}')">{{p.edited_string}}</span></a>
{% else %}
<span class="ml-2 d-inline-block">Edited <span data-bs-toggle="tooltip" data-bs-placement="bottom" id="edited_timestamp-{{p.id}}" data-nonce="{{g.nonce}}" data-onmouseover="timestamp(this, '{{p.edited_utc}}')">{{p.edited_string}}</span></span>
{% endif %}
{% endif %}
<span class="ml-2 d-inline-block">{{p.views}} thread views</span>

View File

@ -0,0 +1,48 @@
create table post_edits (
id integer primary key,
post_id integer not null,
old_title character varying(500),
old_title_html character varying(1500),
old_body character varying(100000),
old_body_html character varying(200000),
created_utc integer NOT NULL
);
CREATE SEQUENCE public.post_edits_id_seq
AS integer
START WITH 1
INCREMENT BY 1
NO MINVALUE
NO MAXVALUE
CACHE 1;
ALTER SEQUENCE public.post_edits_id_seq OWNED BY public.post_edits.id;
ALTER TABLE ONLY public.post_edits ALTER COLUMN id SET DEFAULT nextval('public.post_edits_id_seq'::regclass);
alter table only post_edits
add constraint post_edits_post_fkey foreign key (post_id) references public.posts(id);
create table comment_edits (
id integer primary key,
comment_id integer not null,
old_body character varying(100000),
old_body_html character varying(200000),
created_utc integer NOT NULL
);
CREATE SEQUENCE public.comment_edits_id_seq
AS integer
START WITH 1
INCREMENT BY 1
NO MINVALUE
NO MAXVALUE
CACHE 1;
ALTER SEQUENCE public.comment_edits_id_seq OWNED BY public.comment_edits.id;
ALTER TABLE ONLY public.comment_edits ALTER COLUMN id SET DEFAULT nextval('public.comment_edits_id_seq'::regclass);
alter table only comment_edits
add constraint comment_edits_comment_fkey foreign key (comment_id) references public.comments(id);