diff --git a/wowfunding/orm/orm.py b/wowfunding/orm/orm.py index f095df5..e8d9d2b 100644 --- a/wowfunding/orm/orm.py +++ b/wowfunding/orm/orm.py @@ -318,6 +318,8 @@ class Comment(base): locked = sa.Column(sa.Boolean, default=False) + automated = 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) @@ -360,7 +362,7 @@ class Comment(base): raise @classmethod - def add_comment(cls, pid: int, user_id: int, message: str, cid: int = None, message_id: int = None): + def add_comment(cls, pid: int, user_id: int, message: str, cid: int = None, message_id: int = None, automated=False): from flask.ext.login import current_user from wowfunding.factory import db_session if not message: @@ -373,7 +375,7 @@ class Comment(base): 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) + comment = Comment(user_id=user_id, proposal_id=proposal.id, automated=automated) if cid: parent = Comment.find_by_id(cid=cid) if not parent: diff --git a/wowfunding/routes.py b/wowfunding/routes.py index fc2e81c..6cd0c07 100644 --- a/wowfunding/routes.py +++ b/wowfunding/routes.py @@ -22,7 +22,7 @@ def about(): def proposal_add(): if current_user.is_anonymous: return make_response(redirect(url_for('login'))) - return make_response(render_template(('proposal_edit.html'))) + return make_response(render_template(('proposal/edit.html'))) @app.route('/proposal/comment', methods=['POST']) @@ -69,7 +69,7 @@ def proposal(pid): p.get_comments() if not p: return make_response(redirect(url_for('proposals'))) - return make_response(render_template(('proposal.html'), proposal=p)) + return make_response(render_template(('proposal/proposal.html'), proposal=p)) @app.route('/api/proposal/add', methods=['POST']) @@ -79,9 +79,10 @@ def proposal(pid): parameter('pid', type=int, required=False, location='json'), parameter('funds_target', type=float, required=True, location='json'), parameter('addr_receiving', type=str, required=True, location='json'), - parameter('category', type=str, required=True, location='json') + parameter('category', type=str, required=True, location='json'), + parameter('status', type=int, required=True, location='json', default=1) ) -def proposal_api_add(title, content, pid, funds_target, addr_receiving, category): +def proposal_api_add(title, content, pid, funds_target, addr_receiving, category, status): import markdown2 if current_user.is_anonymous: @@ -95,6 +96,12 @@ def proposal_api_add(title, content, pid, funds_target, addr_receiving, category if category and category not in settings.FUNDING_CATEGORIES: return make_response(jsonify('unknown category'), 500) + if status not in settings.FUNDING_STATUSES.keys(): + make_response(jsonify('unknown status'), 500) + + if status != 1 and not current_user.admin: + return make_response(jsonify('no rights to change status'), 500) + try: from wowfunding.bin.anti_xss import such_xss content_escaped = such_xss(content) @@ -117,6 +124,16 @@ def proposal_api_add(title, content, pid, funds_target, addr_receiving, category p.addr_receiving = addr_receiving if category: p.category = category + + # detect if an admin moved a proposal to a new status and auto-comment + if p.status != status and current_user.admin: + msg = "Moved to status \"%s\"." % settings.FUNDING_STATUSES[status].capitalize() + try: + Comment.add_comment(user_id=current_user.id, message=msg, pid=pid, automated=True) + except: + pass + + p.status = status p.last_edited = datetime.now() else: if funds_target <= 1: @@ -130,7 +147,7 @@ def proposal_api_add(title, content, pid, funds_target, addr_receiving, category p.funds_target = funds_target p.addr_receiving = addr_receiving p.category = category - p.status = 1 + p.status = status db_session.add(p) db_session.commit() @@ -149,7 +166,7 @@ def proposal_edit(pid): if not p: return make_response(redirect(url_for('proposals'))) - return make_response(render_template(('proposal_edit.html'), proposal=p)) + return make_response(render_template(('proposal/edit.html'), proposal=p)) @app.route('/search') diff --git a/wowfunding/static/css/wow.css b/wowfunding/static/css/wow.css index 7e8a990..f690338 100644 --- a/wowfunding/static/css/wow.css +++ b/wowfunding/static/css/wow.css @@ -32,6 +32,7 @@ body { font-weight: bold; color: #ff0000; font-size: 22px; + margin-bottom: 0; } .proposal_content blockquote { @@ -219,7 +220,7 @@ a { .proposal_content{ background-color: #00000008; - padding: .75rem 1.25rem; + padding: 1.25rem 1.25rem; } .form-control { @@ -403,6 +404,10 @@ span.date_posted a{ margin-top: 0.4rem !important; } +.comment-container, .comment-container .comment-container{ + margin-bottom: 0.4rem !important; +} + span.username a.author{ color: #008926; font-weight: bold; @@ -410,4 +415,8 @@ span.username a.author{ :target { background: linear-gradient(90deg, #ff606008, #ffa93e2b); -} \ No newline at end of file +} + +.form-admin{ + border: 1px solid #b60000; +} diff --git a/wowfunding/templates/comments.html b/wowfunding/templates/comments.html index 9574a6f..378a939 100644 --- a/wowfunding/templates/comments.html +++ b/wowfunding/templates/comments.html @@ -22,8 +22,14 @@
- + {{c.user.username}} + {% if c.user.username == proposal.user.username %} + [op] + {% endif %} + {% if c.user.admin %} + [admin] + {% endif %} @@ -31,17 +37,26 @@ {{c.date_added.strftime('%Y-%m-%d %H:%M')}}
- {{c.message}} + {{c.message}}
+ {% if not c.automated %} reply + {% endif %} {% for _c in c.comments %}
- + {{_c.user.username}} + {% if _c.user.username == proposal.user.username %} + [op] + {% endif %} + {% if _c.user.admin %} + [admin] + {% endif %} + diff --git a/wowfunding/templates/proposal/edit.html b/wowfunding/templates/proposal/edit.html index 66fb3df..4a6eb72 100644 --- a/wowfunding/templates/proposal/edit.html +++ b/wowfunding/templates/proposal/edit.html @@ -40,10 +40,19 @@
- {% if pid %} - + {% if current_user.admin %} +
+

Admin options:

+
+ + +
{% endif %} - +
@@ -69,7 +78,7 @@
@@ -135,6 +144,14 @@ data.pid = pid; } + if (document.getElementById('status')){ + var status = document.getElementById('status').value + status = parseInt(status); + data.status = status; + } else { + data.status = 1; + } + var xhr = new XMLHttpRequest(); xhr.open('POST', '/api/proposal/add', true); xhr.setRequestHeader('Content-Type', 'application/json; charset=UTF-8'); diff --git a/wowfunding/templates/proposal/macros/navbar.html b/wowfunding/templates/proposal/macros/navbar.html new file mode 100644 index 0000000..9ebb72b --- /dev/null +++ b/wowfunding/templates/proposal/macros/navbar.html @@ -0,0 +1,32 @@ +
+
+
+
+
+ + + + +
+
+ + wow +
+
+
+ {% if cat %} + + Results limited by category '{{cat}}'. Undo filter. + +
+ {% endif %} +
+
\ No newline at end of file diff --git a/wowfunding/templates/proposal/macros/table.html b/wowfunding/templates/proposal/macros/table.html new file mode 100644 index 0000000..05b0b61 --- /dev/null +++ b/wowfunding/templates/proposal/macros/table.html @@ -0,0 +1,44 @@ +{% macro proposal_table(title, _proposals) %} + + + + + + + {% if status >= 2 %} + + {% else %} + + {% endif %} + + + + + {% for p in _proposals %} + + + + + + + + {% endfor %} + +
{{title}}UsernameDateFunding + +
{{ p.headline }}{{ p.user.username }}{{ p.date_added.strftime('%Y-%m-%d %H:%M') }} + + {% if p.funds_progress >= 0.1 and status == 0 %} + {{p.funds_progress|int}}% + {% else %} + - + {% endif %} + + + {% if p.comment_count %} + {{p.comment_count}} + {% else %} + - + {% endif %} +
+{% endmacro %} diff --git a/wowfunding/templates/proposal/overview.html b/wowfunding/templates/proposal/overview.html new file mode 100644 index 0000000..9171161 --- /dev/null +++ b/wowfunding/templates/proposal/overview.html @@ -0,0 +1,37 @@ +{% extends "base.html" %} +{% block content %} +{% from 'proposal/macros/table.html' import proposal_table %} + +
+ {% include 'proposal/macros/navbar.html' %} + +
+
+
+
+ {% if proposals['proposed'] %} + {{ proposal_table(title='Proposals', _proposals=proposals['proposed']) }} +
+ {% else %} + + {% endif %} +
+
+
+
+ {% if proposals['funding'] %} + {{ proposal_table(title='Funding required', _proposals=proposals['funding']) }} + {% else %} + No proposals here yet. + {% endif %} +
+
+
+ + {% include 'sidebar.html' %} +
+ + +
+ +{% endblock %} diff --git a/wowfunding/templates/proposal/proposal.html b/wowfunding/templates/proposal/proposal.html index c95a102..263f63c 100644 --- a/wowfunding/templates/proposal/proposal.html +++ b/wowfunding/templates/proposal/proposal.html @@ -9,12 +9,28 @@
- -

{{ proposal.headline }}

+

{{ proposal.headline }}

-

-

Posted on {{ proposal.date_added.strftime('%Y-%m-%d') }} by {{ proposal.user.username}}

+

+ + Posted on {{ proposal.date_added.strftime('%Y-%m-%d') }} by {{ proposal.user.username}} + +
+ + Status: + {% if proposal.status == 0 %} + Disabled + {% elif proposal.status == 1 %} + Seeking community approval + {% elif proposal.status == 2 %} + Seeking funding + {% elif proposal.status == 3 %} + Work in progress + {% elif proposal.status == 3 %} + Completed + {% endif %} +

@@ -26,9 +42,9 @@


+ {% if proposal.status >= 2 %}
-
Funds
@@ -74,13 +90,23 @@
Donatation address: -
{{ proposal.addr_donation }}
+
{% if proposal.addr_donation %}{{ proposal.addr_donation }}{% else %}None generated yet{% endif %}
+ {% elif proposal.status == 0 %} +
+
+
+ + This proposal is disabled. +
+
+
+ {% endif %}