diff --git a/wowfunding/orm/orm.py b/wowfunding/orm/orm.py index 4663a6d..a5a9700 100644 --- a/wowfunding/orm/orm.py +++ b/wowfunding/orm/orm.py @@ -103,6 +103,7 @@ class Proposal(base): user = relationship("User", back_populates="proposals") payouts = relationship("Payout", back_populates="proposal") + comments = relationship("Comment", back_populates="proposal", lazy='select') def __init__(self, headline, content, category, user: User): if not headline or not content: @@ -114,8 +115,6 @@ class Proposal(base): raise Exception('wrong category') self.category = category - - @property def json(self): return { @@ -133,14 +132,30 @@ class Proposal(base): @classmethod def find_by_id(cls, pid: int): + from wowfunding.factory import db_session q = cls.query q = q.filter(Proposal.id == pid) result = q.first() if not result: return + # check if we have a valid addr_donation generated. if not, make one. if not result.addr_donation: Proposal.generate_donation_addr(result) + + q = db_session.query(Comment) + q = q.filter(Comment.proposal_id == result.id) + q = q.filter(Comment.replied_to == None) + comments = q.all() + + for c in comments: + q = db_session.query(Comment) + q = q.filter(Comment.proposal_id == result.id) + q = q.filter(Comment.replied_to == c.id) + _c = q.all() + setattr(c, 'comments', _c) + + setattr(result, '_comments', comments) return result @property @@ -274,26 +289,34 @@ class Comment(base): __tablename__ = "comments" id = sa.Column(sa.Integer, primary_key=True) + proposal_id = sa.Column(sa.Integer, sa.ForeignKey('proposals.id')) + proposal = relationship("Proposal", back_populates="comments") + user_id = sa.Column(sa.Integer, sa.ForeignKey('users.user_id'), nullable=False) user = relationship("User", back_populates="comments") + date_added = sa.Column(sa.TIMESTAMP, default=datetime.now) + message = sa.Column(sa.VARCHAR, nullable=False) replied_to = sa.Column(sa.ForeignKey("comments.id")) locked = sa.Column(sa.Boolean, default=False) + ix_comment_replied_to = sa.Index("ix_comment_replied_to", replied_to) + ix_comment_proposal_id = sa.Index("ix_comment_proposal_id", proposal_id) + @staticmethod - def get(comment_id: int): + def find_by_id(cid: int): from wowfunding.factory import db_session - return db_session.query(Comment).filter(Comment.id == comment_id).first() + return db_session.query(Comment).filter(Comment.id == cid).first() @staticmethod - def remove(comment_id: int): + def remove(cid: int): from wowfunding.factory import db_session from flask.ext.login import current_user if current_user.id != user_id and not current_user.admin: raise Exception("no rights to remove this comment") - comment = Comment.get(comment_id=comment_id) + comment = Comment.get(cid=cid) try: comment.delete() db_session.commit() @@ -303,12 +326,12 @@ class Comment(base): raise @staticmethod - def lock(comment_id: int): + def lock(cid: int): from wowfunding.factory import db_session from flask.ext.login import current_user if not current_user.admin: raise Exception("admin required") - comment = Comment.get(comment_id=comment_id) + comment = Comment.find_by_id(cid=cid) if not comment: raise Exception("comment by that id not found") comment.locked = True @@ -321,7 +344,7 @@ class Comment(base): raise @classmethod - def add_comment(cls, user_id: int, message: str, replied_to: int, message_id: int = None): + def add_comment(cls, pid: int, user_id: int, message: str, cid: int = None, message_id: int = None): from flask.ext.login import current_user from wowfunding.factory import db_session if not message: @@ -331,9 +354,12 @@ class Comment(base): raise Exception("no rights to add or modify this comment") if not message_id: - comment = Comment(user_id=self.id) - if replied_to: - parent = Comment.get(comment_id=comment_id) + proposal = Proposal.find_by_id(pid=pid) + if not proposal: + raise Exception("no proposal by that id") + comment = Comment(user_id=user_id, proposal_id=proposal.id) + if cid: + parent = Comment.find_by_id(cid=cid) if not parent: raise Exception("cannot reply to a non-existent comment") comment.replied_to = parent.id @@ -342,7 +368,7 @@ class Comment(base): user = db_session.query(User).filter(User.id == user_id).first() if not user: raise Exception("no user by that id") - comment = next(c for c in self.comments if c.id == message_id) + comment = next(c for c in user.comments if c.id == message_id) if comment.locked and not current_user.admin: raise Exception("your comment has been locked/removed") except StopIteration: diff --git a/wowfunding/routes.py b/wowfunding/routes.py index 61f7cad..e5d9bb8 100644 --- a/wowfunding/routes.py +++ b/wowfunding/routes.py @@ -5,7 +5,7 @@ from flask_yoloapi import endpoint, parameter import settings from wowfunding.factory import app, db_session -from wowfunding.orm.orm import Proposal, User +from wowfunding.orm.orm import Proposal, User, Comment @app.route('/') @@ -25,6 +25,44 @@ def proposal_add(): return make_response(render_template(('proposal_edit.html'))) +@app.route('/proposal/comment', methods=['POST']) +@endpoint.api( + parameter('pid', type=int, required=True), + parameter('text', type=str, required=True), + parameter('cid', type=int, required=False) +) +def proposal_comment(pid, text, cid): + if current_user.is_anonymous: + flash('not logged in', 'error') + return redirect(url_for('proposal', pid=pid)) + if len(text) <= 3: + flash('comment too short', 'error') + return redirect(url_for('proposal', pid=pid)) + try: + Comment.add_comment(user_id=current_user.id, message=text, pid=pid, cid=cid) + except Exception as ex: + flash('Could not add comment: %s' % str(ex), 'error') + return redirect(url_for('proposal', pid=pid)) + + flash('Comment posted.') + return redirect(url_for('proposal', pid=pid)) + + +@app.route('/proposal//comment/') +def propsal_comment_reply(cid, pid): + from wowfunding.orm.orm import Comment + c = Comment.find_by_id(cid) + if not c or c.replied_to: + return redirect(url_for('proposal', pid=pid)) + p = Proposal.find_by_id(pid) + if not p: + return redirect(url_for('proposals')) + if c.proposal_id != p.id: + return redirect(url_for('proposals')) + + return make_response(render_template('comment_reply.html', c=c, pid=pid, cid=cid)) + + @app.route('/proposal/') def proposal(pid): p = Proposal.find_by_id(pid=pid) diff --git a/wowfunding/static/css/wow.css b/wowfunding/static/css/wow.css index 308c643..e57b053 100644 --- a/wowfunding/static/css/wow.css +++ b/wowfunding/static/css/wow.css @@ -360,3 +360,47 @@ textarea.comment{ width: 100%; max-width: 600px; } + +.votearrow { + width: 10px; + height: 10px; + border: 0px; + margin: 3px 2px 6px; + margin-right: 10px; + margin-top: 7px; + background: url(/static/grayarrow.gif) no-repeat; +} + +span.username a{ + font-family: Verdana, Geneva, sans-serif; + font-size: 12pt; + color: #828282; +} + +.comment-container a.reply{ + margin-bottom:2px; + font-family: Verdana, Geneva, sans-serif; + font-size: 11pt; + text-decoration: underline; + color: black; +} + +span.date_posted a{ + color: #828282; + font-family: Verdana, Geneva, sans-serif; + font-size: 10pt; + margin-left:2px; +} + +.comment-container .comment-container{ + margin-top: 0.4rem !important; +} + +span.username a.author{ + color: #008926; + font-weight: bold; +} + +:target { + background: linear-gradient(90deg, #ff606008, #ffa93e2b); +} \ No newline at end of file diff --git a/wowfunding/static/doge_head.png b/wowfunding/static/doge_head.png new file mode 100644 index 0000000..babdc64 Binary files /dev/null and b/wowfunding/static/doge_head.png differ diff --git a/wowfunding/static/grayarrow.gif b/wowfunding/static/grayarrow.gif new file mode 100644 index 0000000..888485f Binary files /dev/null and b/wowfunding/static/grayarrow.gif differ diff --git a/wowfunding/templates/comment_reply.html b/wowfunding/templates/comment_reply.html new file mode 100644 index 0000000..75901cb --- /dev/null +++ b/wowfunding/templates/comment_reply.html @@ -0,0 +1,40 @@ +{% extends "base.html" %} +{% block content %} + + +
+ {% include 'messages.html' %} + +
+ + +
+
+ +
+
+
+ {{c.user.username}} + {{c.date_added.strftime('%Y-%m-%d %H:%M')}}
+ {{c.message}} +

+ {% if logged_in %} +
+ + + +

+
+ {% else %} + You need to be logged in to comment. + {% endif %} +
+
+
+
+
+
+ + + +{% endblock %} diff --git a/wowfunding/templates/comments.html b/wowfunding/templates/comments.html index 89d655d..d7e2cec 100644 --- a/wowfunding/templates/comments.html +++ b/wowfunding/templates/comments.html @@ -1,63 +1,61 @@
-
Comments
+
Comments
{% if logged_in %}
- +

{% else %} - You need to be logged in to comment.
- Press F to pay respects. + You need to be logged in to comment. +
{% endif %}
+ {% for c in proposal._comments %} -
- +
+
-
Commenter Name
- Cras sit amet nibh libero, in gravida nulla. Nulla vel metus scelerisque ante sollicitudin. Cras - purus odio, vestibulum in vulputate at, tempus viverra turpis. Fusce condimentum nunc ac nisi - vulputate fringilla. Donec lacinia congue felis in faucibus. -
-
+ + + {{c.user.username}} + + + + + {{c.date_added.strftime('%Y-%m-%d %H:%M')}} + +
+ {{c.message}} +
+ reply - -
- -
-
Commenter Name
- Cras sit amet nibh libero, in gravida nulla. Nulla vel metus scelerisque ante sollicitudin. Cras - purus odio, vestibulum in vulputate at, tempus viverra turpis. Fusce condimentum nunc ac nisi - vulputate fringilla. Donec lacinia congue felis in faucibus. - -
- + {% for _c in c.comments %} +
+
-
Commenter Name
- Cras sit amet nibh libero, in gravida nulla. Nulla vel metus scelerisque ante sollicitudin. - Cras purus odio, vestibulum in vulputate at, tempus viverra turpis. Fusce condimentum nunc - ac nisi vulputate fringilla. Donec lacinia congue felis in faucibus. + + + {{_c.user.username}} + + + + + {{c.date_added.strftime('%Y-%m-%d %H:%M')}} + +
+ {{_c.message}}
- -
- -
-
Commenter Name
- Cras sit amet nibh libero, in gravida nulla. Nulla vel metus scelerisque ante sollicitudin. - Cras purus odio, vestibulum in vulputate at, tempus viverra turpis. Fusce condimentum nunc - ac nisi vulputate fringilla. Donec lacinia congue felis in faucibus. -
-
- + {% endfor %}
+ {% endfor %}
diff --git a/wowfunding/templates/messages.html b/wowfunding/templates/messages.html index 53ee556..b20058d 100644 --- a/wowfunding/templates/messages.html +++ b/wowfunding/templates/messages.html @@ -1,17 +1,15 @@ -{% with messages = get_flashed_messages() %} +{% with messages = get_flashed_messages(with_categories=True) %} {% if messages %}
{% for message in messages %} - {% if message.category != 'error' %} -
- {{ message }} -
- {% else %} -
- {{ message }} -
- {% endif %} +
+ + {{ message[1] }} +
{% endfor %}