mirror of
https://git.wownero.com/wownero/wownero-funding-system.git
synced 2024-08-15 00:53:45 +00:00
Admins can change proposal statuses, auto-add comment to the WFS when they do and changed some templates
This commit is contained in:
parent
b34d06d49e
commit
4f92894f79
9 changed files with 222 additions and 23 deletions
|
@ -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:
|
||||
|
|
|
@ -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')
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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">
|
||||
|
|
|
@ -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');
|
||||
|
|
32
wowfunding/templates/proposal/macros/navbar.html
Normal file
32
wowfunding/templates/proposal/macros/navbar.html
Normal 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>
|
44
wowfunding/templates/proposal/macros/table.html
Normal file
44
wowfunding/templates/proposal/macros/table.html
Normal 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 %}
|
37
wowfunding/templates/proposal/overview.html
Normal file
37
wowfunding/templates/proposal/overview.html
Normal 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 %}
|
|
@ -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 -->
|
||||
|
|
Loading…
Reference in a new issue