Admins can change proposal statuses, auto-add comment to the WFS when they do and changed some templates

This commit is contained in:
Sander Ferdinand 2018-07-04 20:37:32 +02:00
parent b34d06d49e
commit 4f92894f79
9 changed files with 222 additions and 23 deletions

View file

@ -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:

View file

@ -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')

View file

@ -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);
}
}
.form-admin{
border: 1px solid #b60000;
}

View file

@ -22,8 +22,14 @@
<div class="votearrow" title="upvote"></div>
<div class="media-body">
<span class="username">
<a class="{% if c.user.username == proposal.user.username %}author{% endif %}" href="/user/{{ c.user.username }}">
<a href="/user/{{ c.user.username }}">
{{c.user.username}}
{% if c.user.username == proposal.user.username %}
<small>[op]</small>
{% endif %}
{% if c.user.admin %}
<small>[admin]</small>
{% endif %}
</a>
</span>
<span class="date_posted">
@ -31,17 +37,26 @@
{{c.date_added.strftime('%Y-%m-%d %H:%M')}}
</a>
</span><br>
{{c.message}}
<span style="{% if c.automated %}color:blue;{% endif %}">{{c.message}}</span>
<br>
{% if not c.automated %}
<a class="reply" href="{{url_for('propsal_comment_reply', cid=c.id, pid=proposal.id)}}">reply</a>
{% endif %}
{% for _c in c.comments %}
<div class="media mt-4 comment-container" id="comment-{{_c.id}}">
<div class="votearrow" title="upvote"></div>
<div class="media-body">
<span class="username">
<a class="{% if _c.user.username == proposal.user.username %}author{% endif %}" href="/user/{{ c.user.username }}">
<a href="/user/{{ c.user.username }}">
{{_c.user.username}}
{% if _c.user.username == proposal.user.username %}
<small>[op]</small>
{% endif %}
{% if _c.user.admin %}
<small>[admin]</small>
{% endif %}
</a>
</span>
<span class="date_posted">

View file

@ -40,10 +40,19 @@
</ol>
<form id="news_post" role="form" lpformnum="2" _lpchecked="1" onsubmit="return false;">
{% if pid %}
<input style="display:none" name="pid" value="{{pid}}">
{% if current_user.admin %}
<hr>
<h4>Admin options:</h4>
<div class="form-group">
<label for="status">Move proposal to:</label>
<select class="form-control form-admin" id="status" name="status">
{% for k, v in funding_statuses.items() %}
<option value="{{k}}"{% if proposal and k == proposal.status %} selected{% elif not proposal and k == 1 %} selected{% endif %}>{{v.capitalize()}}</option>
{% endfor %}
</select>
</div>
{% endif %}
<hr>
<!-- text input -->
<div class="form-group">
<label>Title</label>
@ -69,7 +78,7 @@
<label for="category">Category</label>
<select class="form-control" id="category" name="category">
{% for cat in funding_categories %}
<option value="{{cat}}"{% if proposal and cat == proposal.category %} selected{% endif %}>{{cat}}</option>
<option value="{{cat}}"{% if proposal and cat == proposal.category %} selected{% elif not proposal and cat == 'misc' %} selected{% endif %}>{{cat}}</option>
{% endfor %}
</select>
</div>
@ -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');

View file

@ -0,0 +1,32 @@
<div class="col-lg-8" style="padding-bottom: 0px;">
<div class="row">
<div class="form-group" style="text-align: center;">
<div>
<div data-toggle="buttons" class="btn-group btn-group-toggle">
<label onclick="proposalNavbarclickDataHref(this);" data-href="{{ url_for('proposals', status=1) }}" class="btn btn-success {% if status == 1 %}active{% endif %}">
Proposed <small>({{summary_data['statuses'][1]}})</small>
</label>
<label onclick="proposalNavbarclickDataHref(this);" data-href="{{ url_for('proposals', status=2) }}" class="btn btn-success {% if status == 2 %}active{% endif %}">
Funding required <small>({{summary_data['statuses'][2]}})</small>
</label>
<label onclick="proposalNavbarclickDataHref(this);" data-href="{{ url_for('proposals', status=3) }}" class="btn btn-success {% if status == 3 %}active{% endif %}">
Work in progress <small>({{summary_data['statuses'][3]}})</small>
</label>
<label onclick="proposalNavbarclickDataHref(this);" data-href="{{ url_for('proposals', status=4) }}" class="btn btn-success {% if status == 4 %}active{% endif %}">
Completed <small>({{summary_data['statuses'][4]}})</small>
</label>
</div>
<div id="point-wow-left">
<img src="/static/point-left.png" style="margin-left: 10px;width: 60px;">
<span style="color: #fc4dff;font-size: 16px;font-style: italic;font-weight: bold;margin-left: 6px;">wow</span>
</div>
</div>
</div>
{% if cat %}
<small class="form-text text-muted" style="margin-top: -2px;">
Results limited by category '{{cat}}'. <a href="{{ url_for('proposals', status=status) }}">Undo filter</a>.
</small>
<br>
{% endif %}
</div>
</div>

View file

@ -0,0 +1,44 @@
{% macro proposal_table(title, _proposals) %}
<table class="table table-proposal table-hover" style="margin-bottom:6px;">
<thead>
<tr>
<th style="font-size: x-large;">{{title}}</th>
<th>Username</th>
<th id="date">Date</th>
{% if status >= 2 %}
<th style="text-align: right;">Funding</th>
{% else %}
<th></th>
{% endif %}
<th style="display: table-cell;text-align: center;">
<img width="24" src="/static/msg.png">
</th>
</tr>
</thead>
<tbody>
{% for p in _proposals %}
<tr>
<td><b><a href="/proposal/{{ p.id }}">{{ p.headline }}</a></b></td>
<td><a href="/user/{{ p.user.username }}">{{ p.user.username }}</a></td>
<td id="date"><small>{{ p.date_added.strftime('%Y-%m-%d %H:%M') }}</small></td>
<td>
<span style="float:right;">
{% if p.funds_progress >= 0.1 and status == 0 %}
{{p.funds_progress|int}}%
{% else %}
-
{% endif %}
</span>
</td>
<td style="text-align:center;">
{% if p.comment_count %}
{{p.comment_count}}
{% else %}
-
{% endif %}
</td>
</tr>
{% endfor %}
</tbody>
</table>
{% endmacro %}

View file

@ -0,0 +1,37 @@
{% extends "base.html" %}
{% block content %}
{% from 'proposal/macros/table.html' import proposal_table %}
<div class="container">
{% include 'proposal/macros/navbar.html' %}
<div class="row">
<div class="col-lg-8">
<div class="row">
<div class="col-lg-12">
{% if proposals['proposed'] %}
{{ proposal_table(title='Proposals', _proposals=proposals['proposed']) }}
<hr>
{% else %}
{% endif %}
</div>
</div>
<div class="row">
<div class="col-lg-12">
{% if proposals['funding'] %}
{{ proposal_table(title='Funding required', _proposals=proposals['funding']) }}
{% else %}
No proposals here yet.
{% endif %}
</div>
</div>
</div>
{% include 'sidebar.html' %}
</div>
</div>
<!-- /.container -->
{% endblock %}

View file

@ -9,12 +9,28 @@
<!-- Post Content Column -->
<div class="col-lg-12">
<!-- Title -->
<h1 class="mt-4">{{ proposal.headline }}</h1>
<h1 class="mt-4" style="margin-bottom: 0.1rem;">{{ proposal.headline }}</h1>
<p class="lead">
<p>Posted on {{ proposal.date_added.strftime('%Y-%m-%d') }} by <a href="/user/{{ proposal.user.username }}">{{ proposal.user.username}}</a></p>
<p>
<span style="color:grey;">
Posted on {{ proposal.date_added.strftime('%Y-%m-%d') }} by <a href="/user/{{ proposal.user.username }}">{{ proposal.user.username}}</a>
</span>
<br>
<span>
Status:
{% if proposal.status == 0 %}
<span style="color:red;">Disabled</span>
{% 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 %}
</span>
</p>
<p>
@ -26,9 +42,9 @@
</p>
<hr>
{% if proposal.status >= 2 %}
<div class="row">
<div class="col-md-12">
<!-- Side Widget -->
<div class="card my-4">
<h5 class="card-header">Funds</h5>
<div class="card-body">
@ -74,13 +90,23 @@
<div class="row" style="margin-top:16px;">
<div class="col-lg-12">
Donatation address:
<pre class="proposal_address">{{ proposal.addr_donation }}</pre>
<pre class="proposal_address">{% if proposal.addr_donation %}{{ proposal.addr_donation }}{% else %}<small>None generated yet</small>{% endif %}</pre>
</div>
</div>
</div>
</div>
</div>
</div>
{% elif proposal.status == 0 %}
<div class="row">
<div class="col-lg-12">
<div class="alert alert-danger">
<img src="/static/doge_head.png" style="width: 64px;margin-right: 8px;">
This proposal is disabled.
</div>
</div>
</div>
{% endif %}
<div class="proposal_content">
<!-- Post Content -->