Skip to content
Snippets Groups Projects
Verified Commit a27bab6a authored by ornanovitch's avatar ornanovitch Committed by ornanovitch
Browse files

Merge branch 'feat-moderation' into 'dev'

feat: moderation view

Closes #50

See merge request !79
parent 069b8364
No related branches found
No related tags found
No related merge requests found
......@@ -32,12 +32,13 @@ def create_app_from_config(config):
return dict(config=app.config, utils=utils)
# Import views
from hiboo import account, user, profile, service, application, sso, api
from hiboo import account, user, profile, moderation, service, application, sso, api
app.register_blueprint(account.blueprint, url_prefix='/account')
app.register_blueprint(user.blueprint, url_prefix='/user')
app.register_blueprint(profile.blueprint, url_prefix='/profile')
app.register_blueprint(service.blueprint, url_prefix='/service')
app.register_blueprint(application.blueprint, url_prefix='/application')
app.register_blueprint(moderation.blueprint, url_prefix='/moderation')
app.register_blueprint(sso.blueprint, url_prefix='/sso')
app.register_blueprint(api.blueprint, url_prefix='/api')
......
import flask
blueprint = flask.Blueprint("moderation", __name__, template_folder="templates")
from hiboo.moderation import views
{% extends "base.html" %}
{% block title %}{% trans %}Moderation{% endtrans %}{% endblock %}
{% block content %}
<div class="row">
<div class="col-xl-7 col">
<h4>{% trans %}Pending profiles{% endtrans %}</h4>
<div class="card">
<div class="card-body table-responsive p-0">
<table class="table table-striped table-head-fixed text-nowrap">
<thead>
<tr>
<th>{% trans %}Service{% endtrans %}</th>
<th>{% trans %}Profile username{% endtrans %}</th>
<th>{% trans %}Owned by{% endtrans %}</th>
<th>{% trans %}Created on{% endtrans %}</th>
<th>{% trans %}Status{% endtrans %}</th>
<th>{% trans %}Actions{% endtrans %}</th>
</tr>
</thead>
<tbody>
{% for profile in profiles %}
<tr>
<td>{{ profile.service.name }}</td>
<td><a href="{{ url_for("profile.details", profile_uuid=profile.uuid, service_uuid=profile.service.uuid) }}">{{ profile.username }}</a></td>
{% if profile.user_uuid %}
<td><a href="{{ url_for("user.details", user_uuid=profile.user_uuid) }}">{{ profile.user.username }}</a></td>
{% else %}
<td>-</td>
{% endif %}
<td>{{ profile.created_at.date() }}</td>
<td>{{ macros.profile_status(profile) }}</td>
<td>
{% for action in profile.actions %}
<a href="{{ action.url(profile=profile) }}">{{ action.label | capitalize }}</a>
{% endfor %}
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
</div>
<div class="col-xl-5 col">
<h4>{% trans %}Activity{% endtrans %}</h4>
{{ macros.timeline(events, public_only=False, show_user=True) }}
</div>
</div>
{% endblock %}
from hiboo.moderation import blueprint
from hiboo import security, models
import flask
@blueprint.route("/")
@security.admin_required()
def board():
profiles = models.Profile.query.filter(
models.db.or_(
models.Profile.status==models.Profile.REQUEST,
models.Profile.status==models.Profile.BLOCKED,
models.Profile.status==models.Profile.UNCLAIMED,
)).order_by(models.Profile.status.desc()).all()
events = models.History.query.all()
return flask.render_template("moderation_home.html", events=events,
profiles=profiles)
{% extends "base.html" %}
{% block title %}
{% if service %}
{{ service.name }}
{% elif status %}
{{ status[1] | capitalize }} {% trans %}profiles{% endtrans %}
{% else %}
All profiles
{% endif %}
{{ service.name }}
{% endblock %}
{% block subtitle %}profile list{% endblock %}
......@@ -61,8 +55,6 @@
{% endblock %}
{% block actions %}
{% if service %}
<a href="{{ url_for(".unclaimed_export_for_service", service_uuid=service.uuid) }}" class="btn btn-success" download>{% trans %}Export unclaimed profiles{% endtrans %}</a>
<a href="{{ url_for(".create_for", service_uuid=service.uuid) }}" class="btn btn-success">{% trans %}Create profile{% endtrans %}</a>
{% endif %}
{% endblock %}
......@@ -134,14 +134,6 @@ def claim(service_uuid):
return flask.render_template("profile_claim.html", form=form, service=service)
@blueprint.route("/list/status/<status>")
@security.admin_required()
def list_for_status(status):
profiles = models.Profile.query.filter_by(status=status).all()
return flask.render_template("profile_list.html", profiles=profiles,
status=models.Profile.STATUSES[status])
@blueprint.route("/list/service/<service_uuid>")
@security.admin_required()
def list_for_service(service_uuid):
......
{% set colors = ['indigo', 'green', 'orange', 'teal', 'maroon', 'purple', 'olive'] %}
{% macro timeline(events, public_only=True) %}
<div class="timeline">
{% set dates = [] %}
{% for event in events | sort(attribute='created_at', reverse=True) %}
{% if event.public or not public_only %}
{% if not event.created_at.date() == dates[-1] %}
{% set _ = dates.append(event.created_at.date()) %}
<div class="time-label">
<span class="bg-red">{{ event.created_at.date() }}</span>
</div>
{% endif %}
<div>
<i class="fas fa-{{ {
"signup": "address-card",
"create": "plus",
"transition": "recycle",
"password": "lock",
"mfa": "qrcode"
}[event.category] }} bg-blue"></i>
<div class="timeline-item">
<span class="time"><i class="fas fa-clock"></i> {{ event.created_at.time().strftime("%H:%M") }}</span>
<h3 class="timeline-header">
<strong>{{ event.actor.username or event.user.username }}</strong>
{{ event.description }}
</h3>
{% if event.comment %}
<div class="timeline-body">
{{ event.comment }}
{% macro timeline(events, public_only=True, show_user=False) %}
<div class="card">
<div class="card-body table-responsive">
<div class="timeline">
{% set dates = [] %}
{% for event in events | sort(attribute='created_at', reverse=True) %}
{% if event.public or not public_only %}
{% if not event.created_at.date() == dates[-1] %}
{% set _ = dates.append(event.created_at.date()) %}
<div class="time-label">
<span class="bg-red">{{ event.created_at.date() }}</span>
</div>
{% endif %}
<div>
<i class="fas fa-{{ {
"signup": "address-card",
"create": "plus",
"delete": "user-slash",
"note": "pen",
"status": "user-cog",
"transition": "forward",
"password": "lock",
"mfa": "qrcode"
}[event.category] }} bg-blue"></i>
<div class="timeline-item bg-blue">
<span class="time"><i class="fas fa-clock"></i> {{ event.created_at.time().strftime("%H:%M") }}</span>
{% if show_user and event.user.username %}
<span class="time"><i class="fas fa-user"></i>&nbsp;{{ event.user.username }}</span>
{% endif %}
<div class="timeline{% if event.comment %}-header{% else %}-body{% endif %}">
<strong>{{ event.actor.username or event.user.username }}</strong> {{ event.description }}
</div>
{% if event.comment %}
<div class="timeline-body">
{{ event.comment }}
</div>
{% endif %}
</div>
</div>
{% endif %}
{% endfor %}
</div>
</div>
{% endif %}
{% endfor %}
</div>
{% endmacro %}
......
......@@ -62,13 +62,11 @@
</a>
</li>
<li class="nav-item">
<a class="nav-link" href="{{ url_for("profile.list_for_status", status="request") }}">
<i class="nav-icon fas fa-hourglass-half"></i> <p>{% trans %}Requested profiles{% endtrans %}</p>
</a>
</li>
<li class="nav-item">
<a class="nav-link" href="{{ url_for("profile.list_for_status", status="blocked") }}">
<i class="nav-icon fas fa-minus-circle"></i> <p>{% trans %}Blocked profiles{% endtrans %}</p>
<a class="nav-link" href="{{ url_for("moderation.board") }}">
<i class="nav-icon fas fa-user-shield"></i> <p>{% trans %}Moderation{% endtrans %}&nbsp;
{% if utils.pending_requests() %}
<span class="badge bg-info" style="vertical-align: text-bottom">{{ utils.pending_requests() }}</span>
{% endif %}</p>
</a>
</li>
{% endif %}
......
......@@ -6,6 +6,7 @@ import flask_limiter
import flask_redis
import babel
from hiboo import models
from werkzeug import routing
......@@ -76,6 +77,12 @@ def display_help(identifier):
return result
def pending_requests():
""" Check if profiles requests are pending
"""
return models.Profile.query.filter_by(status=models.Profile.REQUEST).count()
# Request rate limitation
limiter = flask_limiter.Limiter(key_func=lambda: current_user.id)
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment