Projects overview
* Added projects overview * Added modal for new project * Added error codes and validation for new project path
This commit is contained in:
parent
76cf02a1f0
commit
285a808ee4
@ -6,11 +6,11 @@
|
|||||||
# * _repo : https://git.tuxstash.de/gothseidank/labertasche
|
# * _repo : https://git.tuxstash.de/gothseidank/labertasche
|
||||||
# * _license : This project is under MIT License
|
# * _license : This project is under MIT License
|
||||||
# *********************************************************************************/
|
# *********************************************************************************/
|
||||||
from flask import Blueprint, render_template, request, redirect
|
from flask import Blueprint, render_template, request, redirect, make_response, jsonify
|
||||||
from flask_login import login_required
|
from flask_login import login_required
|
||||||
from labertasche.database import labertasche_db as db
|
from labertasche.database import labertasche_db as db
|
||||||
from labertasche.models import TLocation, TComments, TEmail
|
from labertasche.models import TLocation, TComments, TEmail, TProjects
|
||||||
from labertasche.helper import dates_of_the_week, export_location
|
from labertasche.helper import dates_of_the_week, export_location, get_id_from_project_name
|
||||||
from sqlalchemy import func
|
from sqlalchemy import func
|
||||||
import re
|
import re
|
||||||
|
|
||||||
@ -18,15 +18,48 @@ import re
|
|||||||
bp_dashboard = Blueprint("bp_dashboard", __name__, url_prefix='/dashboard')
|
bp_dashboard = Blueprint("bp_dashboard", __name__, url_prefix='/dashboard')
|
||||||
|
|
||||||
|
|
||||||
@bp_dashboard.route('/')
|
@bp_dashboard.route("/")
|
||||||
@login_required
|
@login_required
|
||||||
def dashboard_index():
|
def dashboard_index():
|
||||||
|
t_projects = db.session.query(TProjects).all()
|
||||||
|
projects = list()
|
||||||
|
for each in t_projects:
|
||||||
|
comments = db.session.query(TComments).filter(TComments.project_id == each.id_project) \
|
||||||
|
.filter(TComments.is_published == True) \
|
||||||
|
.filter(TComments.is_spam == False).count()
|
||||||
|
unpub_comments = db.session.query(TComments).filter(TComments.project_id == each.id_project) \
|
||||||
|
.filter(TComments.is_spam == False) \
|
||||||
|
.filter(TComments.is_published == False).count()
|
||||||
|
spam = db.session.query(TComments).filter(TComments.project_id == each.id_project) \
|
||||||
|
.filter(TComments.is_spam == True).count()
|
||||||
|
|
||||||
|
projects.append(dict({
|
||||||
|
"id_project": each.id_project,
|
||||||
|
"name": each.name,
|
||||||
|
"total_comments": comments,
|
||||||
|
"total_spam": spam,
|
||||||
|
"total_unpublished": unpub_comments
|
||||||
|
}))
|
||||||
|
return render_template('project_overview.html', projects=projects)
|
||||||
|
|
||||||
|
|
||||||
|
@bp_dashboard.route("/project/new", methods=['POST'])
|
||||||
|
@login_required
|
||||||
|
def dashboard_new_project():
|
||||||
|
return make_response(jsonify(status='too-short'), 200)
|
||||||
|
|
||||||
|
|
||||||
|
@bp_dashboard.route('/<project>/')
|
||||||
|
@login_required
|
||||||
|
def dashboard_project_index(project: str):
|
||||||
|
proj_id = get_id_from_project_name(project)
|
||||||
dates = dates_of_the_week()
|
dates = dates_of_the_week()
|
||||||
spam = list()
|
spam = list()
|
||||||
published = list()
|
published = list()
|
||||||
unpublished = list()
|
unpublished = list()
|
||||||
for each in dates:
|
for each in dates:
|
||||||
spam_comments = db.session.query(TComments).filter(func.DATE(TComments.created_on) == each.date())\
|
spam_comments = db.session.query(TComments).filter(TComments.project_id == proj_id)\
|
||||||
|
.filter(func.DATE(TComments.created_on) == each.date())\
|
||||||
.filter(TComments.is_spam == True).all()
|
.filter(TComments.is_spam == True).all()
|
||||||
|
|
||||||
pub_comments = db.session.query(TComments).filter(func.DATE(TComments.created_on) == each.date()) \
|
pub_comments = db.session.query(TComments).filter(func.DATE(TComments.created_on) == each.date()) \
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
# *********************************************************************************/
|
# *********************************************************************************/
|
||||||
import datetime
|
import datetime
|
||||||
import json
|
import json
|
||||||
from labertasche.models import TLocation, TComments
|
from labertasche.models import TLocation, TComments, TProjects
|
||||||
from labertasche.settings import Settings
|
from labertasche.settings import Settings
|
||||||
from labertasche.database import labertasche_db as db
|
from labertasche.database import labertasche_db as db
|
||||||
from functools import wraps
|
from functools import wraps
|
||||||
@ -192,3 +192,13 @@ def dates_of_the_week():
|
|||||||
date_list.append(monday)
|
date_list.append(monday)
|
||||||
date_list.append((monday + datetime.timedelta(days=1, hours=23, minutes=59, seconds=59)))
|
date_list.append((monday + datetime.timedelta(days=1, hours=23, minutes=59, seconds=59)))
|
||||||
return date_list
|
return date_list
|
||||||
|
|
||||||
|
|
||||||
|
def get_id_from_project_name(name: str) -> int:
|
||||||
|
"""
|
||||||
|
Returns the id of a project name
|
||||||
|
:param name: The display name of the project
|
||||||
|
:return: the ID of the project
|
||||||
|
"""
|
||||||
|
proj = db.session.query(TProjects).filter(TProjects.name == name).first()
|
||||||
|
return proj.id_project
|
||||||
|
File diff suppressed because one or more lines are too long
@ -23,7 +23,10 @@ $navbar-burger-color: black;
|
|||||||
$footer-background-color: #393f4d;
|
$footer-background-color: #393f4d;
|
||||||
$footer-color: true;
|
$footer-color: true;
|
||||||
|
|
||||||
$card-header-color: white;
|
$card-header-color: black;
|
||||||
|
$card-header-background-color: #feda6a;
|
||||||
|
$card-footer-background-color: #feda6a;
|
||||||
|
$card-background-color: grey;
|
||||||
|
|
||||||
$table-head-background-color: #feda6a;
|
$table-head-background-color: #feda6a;
|
||||||
$table-body-background-color: white;
|
$table-body-background-color: white;
|
||||||
@ -78,6 +81,11 @@ canvas{
|
|||||||
border: 2px solid #feda6a;
|
border: 2px solid #feda6a;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.brdr-darkslate{
|
||||||
|
border: 2px solid #1d1e22;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
.bg-compliment{
|
.bg-compliment{
|
||||||
background-color: #384667;
|
background-color: #384667;
|
||||||
}
|
}
|
||||||
@ -85,3 +93,9 @@ canvas{
|
|||||||
.fg-yellow{
|
.fg-yellow{
|
||||||
color: #feda6a;
|
color: #feda6a;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.my-shadow-subtle{
|
||||||
|
-webkit-box-shadow: 5px 5px 5px 0 rgba(0,0,0,0.75);
|
||||||
|
-moz-box-shadow: 5px 5px 5px 0 rgba(0,0,0,0.75);
|
||||||
|
box-shadow: 5px 5px 5px 0 rgba(0,0,0,0.75);
|
||||||
|
}
|
||||||
|
@ -19,3 +19,71 @@ function dashboard_mailsearch(search_txt)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function new_project_save() {
|
||||||
|
let modal_ok = document.getElementById('modal-ok');
|
||||||
|
let modal_cancel = document.getElementById('modal-cancel');
|
||||||
|
let short_help = document.getElementById('new-project-too-short');
|
||||||
|
let short_help_invalid = document.getElementById('new-project-invalid-name');
|
||||||
|
let name = document.getElementById('project-name').value
|
||||||
|
|
||||||
|
short_help.classList.add('is-hidden');
|
||||||
|
short_help_invalid.classList.add('is-hidden');
|
||||||
|
|
||||||
|
// Validate input
|
||||||
|
if (name.length === 0) {
|
||||||
|
short_help.classList.remove('is-hidden');
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (/^\w+$/.test(name) === false){
|
||||||
|
short_help_invalid.classList.remove('is-hidden');
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
modal_ok.classList.add('is-loading');
|
||||||
|
modal_cancel.classList.add('is-hidden');
|
||||||
|
fetch(window.location.protocol + "//" + window.location.host + '/dashboard/project/new',
|
||||||
|
{
|
||||||
|
mode: "cors",
|
||||||
|
headers: {
|
||||||
|
'Access-Control-Allow-Origin': '*',
|
||||||
|
'Accept': 'application/json',
|
||||||
|
'Content-Type': 'application/json'
|
||||||
|
},
|
||||||
|
method: "POST",
|
||||||
|
// use real location
|
||||||
|
body: JSON.stringify({
|
||||||
|
"name": name
|
||||||
|
})
|
||||||
|
})
|
||||||
|
.then(async function (response) {
|
||||||
|
let result = await response.json();
|
||||||
|
result = result['status'];
|
||||||
|
modal_ok.classList.remove('is-loading');
|
||||||
|
modal_cancel.classList.remove('is-hidden');
|
||||||
|
if (result === "ok"){
|
||||||
|
hide_modal('modal-new-project');
|
||||||
|
}
|
||||||
|
if (result === "too-short"){
|
||||||
|
short_help.classList.remove('is-hidden');
|
||||||
|
}
|
||||||
|
if (result === "invalid-name"){
|
||||||
|
short_help_invalid.classList.remove('is-hidden');
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch(function (exc) {
|
||||||
|
console.log(exc);
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
function hide_modal(id_name)
|
||||||
|
{
|
||||||
|
let el = document.getElementById(id_name);
|
||||||
|
el.classList.remove("is-active");
|
||||||
|
}
|
||||||
|
|
||||||
|
function show_modal(id_name)
|
||||||
|
{
|
||||||
|
let el = document.getElementById(id_name);
|
||||||
|
el.classList.add("is-active");
|
||||||
|
}
|
||||||
|
120
templates/project_overview.html
Normal file
120
templates/project_overview.html
Normal file
@ -0,0 +1,120 @@
|
|||||||
|
{% extends "base.html" %}
|
||||||
|
{% block main %}
|
||||||
|
<div style="min-height: 100vh;" class="container bg-deepmatte p-6 brdr-yayellow">
|
||||||
|
<h1 class="is-size-2 mb-3 is-uppercase">Select project</h1>
|
||||||
|
<div class="columns is-multiline">
|
||||||
|
<div class="column is-4">
|
||||||
|
<div class="card my-shadow-subtle brdr-darkslate">
|
||||||
|
<div class="card-header">
|
||||||
|
<div class="card-header-title">
|
||||||
|
<p class="is-size-4 is-uppercase">
|
||||||
|
NEW PROJECT
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="card-content has-text-white">
|
||||||
|
<div class="level is-mobile">
|
||||||
|
<div class="level-item has-text-centered">
|
||||||
|
<div>
|
||||||
|
<p class="heading is-capitalized">Comments</p>
|
||||||
|
<p class="is-size-4 has-text-weight-bold has-text-white">n/a</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="level-item has-text-centered">
|
||||||
|
<div>
|
||||||
|
<p class="heading is-capitalized">Unpublished</p>
|
||||||
|
<p class="is-size-4 has-text-weight-bold has-text-white">n/a</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="level-item has-text-centered">
|
||||||
|
<div class="ml-4">
|
||||||
|
<p class="heading is-capitalized">Spam</p>
|
||||||
|
<p class="is-size-4 has-text-weight-bold has-text-white">n/a</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="card-footer">
|
||||||
|
<div class="card-footer-item">
|
||||||
|
<a class="has-text-weight-bold has-text-black is-uppercase"
|
||||||
|
onclick="show_modal('modal-new-project');"
|
||||||
|
href="#">NEW</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% for project in projects %}
|
||||||
|
<div class="column is-4">
|
||||||
|
<div class="card my-shadow-subtle brdr-darkslate">
|
||||||
|
<div class="card-header">
|
||||||
|
<div class="card-header-title">
|
||||||
|
<p class="is-size-4 is-uppercase">
|
||||||
|
{{ project['name'] }}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="card-content has-text-white">
|
||||||
|
<div class="level is-mobile">
|
||||||
|
<div class="level-item has-text-centered">
|
||||||
|
<div>
|
||||||
|
<p class="heading is-capitalized">Comments</p>
|
||||||
|
<p class="is-size-4 has-text-weight-bold has-text-white">{{ project['total_comments'] }}</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="level-item has-text-centered">
|
||||||
|
<div>
|
||||||
|
<p class="heading is-capitalized">Unpublished</p>
|
||||||
|
<p class="is-size-4 has-text-weight-bold has-text-white">{{ project['total_unpublished'] }}</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="level-item has-text-centered">
|
||||||
|
<div class="ml-4">
|
||||||
|
<p class="heading is-capitalized">Spam</p>
|
||||||
|
<p class="is-size-4 has-text-weight-bold has-text-white">{{ project['total_spam'] }}</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="card-footer">
|
||||||
|
<div class="card-footer-item">
|
||||||
|
<a class="has-text-weight-bold has-text-black is-uppercase" href="#">EDIT</a>
|
||||||
|
</div>
|
||||||
|
<div class="card-footer-item">
|
||||||
|
<a class="has-text-weight-bold has-text-black is-uppercase" href="#">DELETE</a>
|
||||||
|
</div>
|
||||||
|
<div class="card-footer-item">
|
||||||
|
<a class="has-text-weight-bold has-text-black is-uppercase"
|
||||||
|
href="{{ url_for('bp_dashboard.dashboard_project_index', project=project['name'])}}">VIEW</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="modal is-active" id="modal-new-project">
|
||||||
|
<div class="modal-background"></div>
|
||||||
|
<div class="modal-card">
|
||||||
|
<header class="modal-card-head">
|
||||||
|
<p class="modal-card-title">New Project</p>
|
||||||
|
<button class="delete" aria-label="close"></button>
|
||||||
|
</header>
|
||||||
|
<section class="modal-card-body">
|
||||||
|
<label for="project-name" class="has-text-black">PROJECT NAME
|
||||||
|
<input class="input is-success"
|
||||||
|
type="text"
|
||||||
|
name="project-name"
|
||||||
|
id="project-name"
|
||||||
|
placeholder="Type a name without special characters.."
|
||||||
|
>
|
||||||
|
</label>
|
||||||
|
<p id="new-project-too-short" class="is-hidden help has-text-danger">Input too short. Needs at least 1 character!</p>
|
||||||
|
<p id="new-project-invalid-name" class="is-hidden help has-text-danger">Input is invalid. Please use only a-z and 0-9.</p>
|
||||||
|
</section>
|
||||||
|
<footer class="modal-card-foot">
|
||||||
|
<button id="modal-ok" onclick="new_project_save()" class="button is-success">Save</button>
|
||||||
|
<button id="modal-cancel" onclick="hide_modal('modal-new-project')" class="button is-danger">Cancel</button>
|
||||||
|
</footer>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endblock %}
|
Loading…
x
Reference in New Issue
Block a user