Commit 5c764bdb authored by buttle's avatar buttle

Added change author

parent 640503c9
......@@ -31,8 +31,8 @@ babel = Babel(app)
csrf = CSRFProtect()
csrf.init_app(app)
app.config['APP_VERSION'] = 28
app.config['SCHEMA_VERSION'] = 12
app.config['APP_VERSION'] = 29
app.config['SCHEMA_VERSION'] = 13
app.config['RESERVED_SLUGS'] = ['static', 'admin', 'admins', 'user', 'users', 'form', 'forms', 'site', 'sites', 'update']
# DPL = Data Protection Law
......
......@@ -22,6 +22,7 @@ from flask_babel import gettext
from GNGforms import app
from GNGforms.persistence import Site
import smtplib, socket
from threading import Thread
def createSmtpObj():
config=g.site.data["smtpConfig"]
......
......@@ -150,5 +150,11 @@ def migrateMongoSchema(schemaVersion):
mongo.db.forms.update_one({"_id": form["_id"]}, {"$set": {"restrictedAccess": False}})
schemaVersion=12
if schemaVersion == 12:
# Add admin prefs. to forms
for form in mongo.db.forms.find():
mongo.db.forms.update_one({"_id": form["_id"]}, {"$set": {"adminPreferences": { "public": True }}})
schemaVersion=13
# this can't be a good migration setup :(
return schemaVersion
......@@ -194,7 +194,8 @@ class User(object):
@property
def forms(self):
return Form().findAll(editor=str(self._id))
#return Form().findAll(editor=str(self._id))
return [Form(_id=form['_id']) for form in Form().findAll(editor=str(self._id))]
@property
def admin(self):
......@@ -340,7 +341,21 @@ class Form(object):
@property
def author(self):
return self.form['author']
@author.setter
def author(self, value):
self.form["author"]=value
def changeAuthor(self, new_author):
if new_author.enabled:
if self.author in self.editors:
del self.editors[self.author]
self.author=str(new_author._id)
if self.addEditor(new_author):
self.save()
return True
return False
@property
def user(self):
return User(_id=self.form['author'])
......@@ -393,15 +408,22 @@ class Form(object):
@property
def enabled(self):
if not self.form['adminPreferences']['public']:
return False
return self.form['enabled']
def newEditorPreferences(cls):
return {'notification': {'newEntry': False, 'expiredForm': True}}
def addEditor(self, editor_id):
def addEditor(self, editor):
if not editor.enabled:
return False
editor_id=str(editor._id)
if not editor_id in self.form['editors']:
self.form['editors'][editor_id]=Form().newEditorPreferences()
mongo.db.forms.update_one({'_id': self.form['_id']}, {"$set": {"editors": self.form['editors']}})
return True
return False
def removeEditor(self, editor_id):
if editor_id == self.author:
......@@ -569,13 +591,18 @@ class Form(object):
return "%s/%s/%s" % (self.url, part, self.form['sharedEntries']['key'])
def toggleEnabled(self):
if self.expired:
if self.expired or self.form['adminPreferences']['public']==False:
return False
else:
self.form['enabled'] = False if self.form['enabled'] else True
mongo.db.forms.save(self.form)
return self.form['enabled']
def toggleAdminFormPublic(self):
self.form['adminPreferences']['public'] = False if self.form['adminPreferences']['public'] else True
mongo.db.forms.save(self.form)
return self.form['adminPreferences']['public']
def toggleSharedEntries(self):
self.form['sharedEntries']['enabled'] = False if self.form['sharedEntries']['enabled'] else True
mongo.db.forms.save(self.form)
......
{% extends "base.html" %}
{% block content %}
<div class="container">
<div class="row col-md-3"></div>
<div class="row col-md-7" style="font-size:1.5em">
<input class="btn-primary btn btn-sm" type="button" value="{%trans%}Return to form{%endtrans%}" onClick="location.href='/forms/view/{{ form._id }}'">
{{ form.slug }}
<hr />
</div>
<div class="row col-md-2"></div>
</div>
<div class="container">
<div class="row col-md-3"></div>
<div class="row col-md-5">
<div style="font-size:1.5em; padding-bottom:1em;">
{%trans%}Change author{%endtrans%}
</div>
<table class="table table-striped table-condensed">
<tr>
<td>{%trans%}Current author{%endtrans%}</td>
<td>{{ form.user.username }}</td>
</tr>
</table>
{%trans%}You are going to change the author of this form.{%endtrans%}<br />
{%trans%}Are you sure?{%endtrans%}
<p>&nbsp;</p>
<form action="/admin/forms/change-author/{{form._id}}" method="POST">
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}" />
<input name="new_author_username" type="text" placeholder="{%trans%}New author's username{%endtrans%}" class="form-control" required />
<p></p>
<input class="btn-primary btn btn-md" type="submit" value="{%trans%}Change author{%endtrans%}" />
</form>
{% if editors|length > 1 %}
<p>&nbsp;</p>
<div style="font-size:1.5em;">
{%trans%}Editors{%endtrans%}
</div>
<div>
{%trans%}Users listed here have the <b>same permissions</b> as the author{%endtrans%}
</div>
<p style="padding-top:1.2em;"></p>
<table class="table table-condensed">
{% for editor in editors %}
<tr id="editor_{{editor._id}}">
<td>{{ editor.username }}</td>
<td>{{ editor.email }}</td>
<td class="text-right">
{% if editor._id|string == form.author %}
({%trans%}Author{%endtrans%})
{% else %}
<input class="btn btn-xs btn-danger" type="button" value="{%trans%}Remove{%endtrans%}" onClick="js:removeEditor('{{editor._id}}');">
{% endif %}
</td>
</tr>
{% endfor %}
</table>
{% endif %}
</div>
<div class="row col-md-4"></div>
</div>
<script>
var csrftoken = "{{ csrf_token() }}";
function removeEditor(editor_id){
$.ajax({
url : "/forms/remove-editor/{{form._id}}/"+editor_id,
type: "POST",
dataType: "json",
beforeSend: function(xhr, settings) {
if (!/^(GET|HEAD|OPTIONS|TRACE)$/i.test(settings.type)) {
xhr.setRequestHeader("X-CSRFToken", csrftoken)
}
},
success: function(data, textStatus, jqXHR)
{
if (data == editor_id) {
$('#editor_'+editor_id).hide();
}
}
});
}
</script>
{% endblock %}
......@@ -11,7 +11,7 @@
{%trans%}Delete user{%endtrans%}
</div>
<hr />
{% set formCount=user.forms.count() %}
{% set formCount=user.forms|length %}
{%trans%}You are going to delete a user{%endtrans%}
{% if formCount %}
{%trans%}and their forms{%endtrans%}
......
......@@ -55,7 +55,7 @@
</td>
</tr>
<tr>
<td>{%trans%}Published{%endtrans%}</td>
<td>{%trans%}Public{%endtrans%}</td>
<td>
{% if form.editors[g.current_user._id|string] is defined %}
<div id="toggle_enabled" class="btn-group btn-toggle">
......@@ -63,10 +63,7 @@
<button id="enabled_false" class="btn btn-xs btn-default {% if not form.isPublic() %}btn-primary{% endif %}">{%trans%}False{%endtrans%}</button>
</div>
{% else %}
{{ form.isPublic() }}
{% if not form.user.enabled %}
<span style="color:red">({%trans%}user disabled{%endtrans%})</span>
{% endif %}
{{ form.isPublic() }}
{% endif %}
</td>
</tr>
......@@ -93,7 +90,12 @@
</td>
</tr>
<tr>
<td>{%trans%}Public URL{%endtrans%}</td>
<td>
{%trans%}Public URL{%endtrans%}
{% if not form.data['adminPreferences']['public'] %}
<span style="color:red">({%trans%}disabled{%endtrans%})</span>
{% endif %}
</td>
<td>
{% if form.isPublic() %}
<a id="formLink" href="{{ form.url }}">{{ form.url }}</a>
......@@ -148,12 +150,19 @@
</tr>
{% endif %}
<tr>
<td>{%trans%}Author{%endtrans%}</td>
<td>
{%trans%}Author{%endtrans%}
{% if not form.user.enabled %}
<span style="color:red">({%trans%}disabled{%endtrans%})</span>
{% endif %}
</td>
<td>
{% if g.isAdmin %}
<td><a href="/admin/users/{{ form.user._id }}">{{ form.user.username }}</a></td>
<a href="/admin/users/{{ form.user._id }}">{{ form.user.username }}</a>
{% else %}
<td>{{ form.user.username }}</td>
{{ form.user.username }}
{% endif %}
</td>
</tr>
<tr>
<td>{%trans%}Created{%endtrans%}</td>
......@@ -178,6 +187,19 @@
<input class="btn-danger btn btn-sm" type="button" value="{%trans%}Delete form and entries{%endtrans%}" onClick="location.href='/forms/delete/{{ form._id }}'">
{% endif %}
{% endif %}
{% if g.isAdmin %}
<div style="font-size:1.5em; padding-top:1em;">
{%trans%}Admin options{%endtrans%}
</div>
<hr />
<input class="btn-primary btn btn-sm" type="button" value="{%trans%}Change author{%endtrans%}" onClick="location.href='/admin/forms/change-author/{{form._id}}'" >
{% if form.data['adminPreferences']['public'] %}
<input class="btn-danger btn btn-sm" type="button" value="{%trans%}Disable form{%endtrans%}" onClick="location.href='/admin/forms/toggle-public/{{form._id}}'" >
{% else %}
<input class="btn-primary btn btn-sm" type="button" value="{%trans%}Enable form{%endtrans%}" onClick="location.href='/admin/forms/toggle-public/{{form._id}}'" >
{% endif %}
{% endif %}
</div>
</div>
......
......@@ -48,7 +48,7 @@
<tr>
<td>{%trans%}Validated email{%endtrans%}</td>
<td> {% if user.data.validatedEmail %}
<span style="color:green">{%trans%}True{%endtrans%}</span>
<span>{%trans%}True{%endtrans%}</span>
{% else %}
<span style="color:red">{%trans%}False{%endtrans%}</span>
{% endif %}
......@@ -65,7 +65,7 @@
</tr>
</table>
{% if g.isAdmin and not user._id == g.current_user._id %}
{% if user.forms.count() %}
{% if user.forms|length %}
<input class="btn-danger btn btn-sm" type="button" value="{%trans%}Delete user and authored forms{%endtrans%}" onClick="location.href='/admin/users/delete/{{user._id}}'">
{% else %}
<input class="btn-danger btn btn-sm" type="button" value="{%trans%}Delete user{%endtrans%}" onClick="location.href='/admin/users/delete/{{user._id}}'">
......@@ -87,7 +87,7 @@
<th>{%trans%}Created{%endtrans%}</th>
<th>{%trans%}Author{%endtrans%}</th>
<th>{%trans%}Editors{%endtrans%}</th>
<th>{%trans%}Enabled{%endtrans%}</th>
<th>{%trans%}Public{%endtrans%}</th>
<th>{%trans%}Entries{%endtrans%}</th>
</tr>
</thead>
......
......@@ -37,7 +37,7 @@
<td>{{user.data.created}}</td>
<td>{{user.enabled}}</td>
<td>{{user.email}}</td>
<td>{{user.forms.count()}}</td>
<td>{{user.forms|length}}</td>
<td>{{user.isAdmin()}}</td>
</tr>
{% endfor %}
......
# Catalan translations for PROJECT.
# Copyright (C) 2019 ORGANIZATION
# This file is distributed under the same license as the PROJECT project.
# FIRST AUTHOR <[email protected]>, 2019.
#
msgid ""
msgstr ""
"Project-Id-Version: PROJECT VERSION\n"
"Report-Msgid-Bugs-To: [email protected]\n"
"POT-Creation-Date: 2019-10-24 21:32+0200\n"
"PO-Revision-Date: 2019-11-01 14:38+0100\n"
"Last-Translator: \n"
"Language: ca\n"
"Language-Team: ca <[email protected]>\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=utf-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Generated-By: Babel 2.3.4\n"
"X-Generator: Poedit 1.8.11\n"
#: email.py:32
msgid "Could not connect to SMTP server"
msgstr "No s'ha pogut connectar amb el servidor SMTP"
#: email.py:49
#, python-format
msgid ""
"Hello %s\n"
"\n"
"Please confirm your email\n"
"\n"
"%s"
msgstr ""
"Hola% s\n"
"\n"
"Confirma el teu correu electrònic\n"
"\n"
"% s"
#: email.py:50
msgid "GNGforms. Confirm email"
msgstr "GNGforms. Confirma el correu electrònic"
#: email.py:62
#, python-format
msgid "GNGforms. Invitation to %s"
msgstr "GNGforms. Invitació a %s"
#: email.py:69
msgid "Please use this link to recover your password"
msgstr "Fes servir aquest enllaç per recuperar la teva contrasenya"
#: email.py:71
msgid "GNGforms. Recover password"
msgstr "GNGforms. Recuperar contrasenya"
#: email.py:77
#, python-format
msgid "New form entry in %s at %s\n"
msgstr "Nova entrada de formulari a %s at %s\n"
#: email.py:83
msgid "GNGforms. New form entry"
msgstr "GNGforms. Nova entrada de formulari"
#: email.py:88
#, python-format
msgid "The form '%s' has expired at %s"
msgstr "El formulari '%s' ha caducat %s"
#: email.py:89
msgid "GNGforms. A form has expired"
msgstr "GNGforms. Aquest formulari ha caducat"
#: email.py:95
#, python-format
msgid "New form '%s' created at %s"
msgstr "Nou formulari '%s' creat a %s"
#: email.py:96
msgid "GNGforms. New form notification"
msgstr "GNGforms. Nova notificació de formulari"
#: email.py:102
#, python-format
msgid "New user '%s' created at %s"
msgstr "Nou usuari '%s' creat a %s"
#: email.py:103
msgid "GNGforms. New user notification"
msgstr "GNGforms. Nova notificació d'usuari"
#: email.py:110
msgid "Congratulations!"
msgstr "Felicitats!"
#: email.py:111
msgid "SMTP test"
msgstr "SMTP test"
#: persistence.py:35
msgid "All fields are required"
msgstr "Tots els camps són obligatoris"
#: persistence.py:38
msgid "Username is not valid"
msgstr "El nom d'usuari no és vàlid"
#: persistence.py:41 persistence.py:45
msgid "Username is not available"
msgstr "El nom d'usuari no està disponible"
#: persistence.py:136 utils.py:260
msgid "Email address is not valid"
msgstr "El correu electrònic no és vàlid"
#: persistence.py:139
msgid "Email address is not available"
msgstr "El correu electrònic no està disponible"
#: utils.py:85
msgid "That's a nasty slug!"
msgstr "Aquest camp és erroni!"
#: utils.py:96
msgid "That's a nasty key!"
msgstr "Aquesta clau és errònia!"
#: utils.py:107
msgid "That's a nasty token!"
msgstr "Aquesta clau és errònia!"
#: utils.py:186
msgid "Passwords do not match"
msgstr "Les contrasenyes no coincideixen"
#: utils.py:189
msgid "Your password is weak"
msgstr "La teva contrasenya és feble"
#: views.py:87
msgid "Can't find that form"
msgstr "No trobo aquest formulari"
#: views.py:93
msgid "That form has expired"
msgstr "Aquest formulari ha caducat"
#: views.py:95
msgid "That form is not public"
msgstr "Aquest formulari no és públic"
#: views.py:202 views.py:616 views.py:629
msgid "No form found"
msgstr "No s'ha trobat cap formulari"
#: views.py:208
msgid "Permission needed to view form"
msgstr "Necessites permís per veure aquest formulari"
#: views.py:233
msgid "Thank you!!"
msgstr "Gràcies!"
#: views.py:243 views.py:257
msgid "Form is not available. 404"
msgstr "El formulari no està disponible. 404"
#: views.py:248
msgid "You can edit the duplicate now"
msgstr "Ara podeu editar el duplicat"
#: views.py:268 views.py:313
msgid "Form is not available"
msgstr "El formulari no està disponible. 404"
#: views.py:271
msgid "We need an email"
msgstr "Necessitem un correu electrònic"
#: views.py:278
msgid "Can't find a user with that email"
msgstr "No trobo un usuari amb aquest correu"
#: views.py:281
#, python-format
msgid "%s is already an editor"
msgstr "%s és ara editor"
#: views.py:285
msgid "New editor added ok"
msgstr "Nou editor afegit correctament"
#: views.py:286
#, python-format
msgid "Added editor %s"
msgstr "Editor afegit %s"
#: views.py:304
#, python-format
msgid "Removed editor %s"
msgstr "Editor %s eliminat"
#: views.py:320
msgid "Date-time is not valid"
msgstr "La data o el tems no són vàlids"
#: views.py:325
#, python-format
msgid "Expiry date set to: %s"
msgstr "Data de caducitat: %s"
#: views.py:331
msgid "Expiry date cancelled"
msgstr "Data de caducitat cancel·lada"
#: views.py:333
msgid "Missing date or time"
msgstr "Data o temps perduts"
#: views.py:384
msgid "You can't edit that form"
msgstr "No pots editar aquest formulari"
#: views.py:394
msgid "Something went wrong. No slug!"
msgstr "Alguna cosa ha sortit malament. No hi ha fitxa!"
#: templates/inspect-form.html:46 templates/inspect-user.html:37
#: templates/inspect-user.html:87 templates/list-forms.html:24
#: templates/list-users.html:24 templates/my-forms.html:27
#: templates/user-settings.html:85 templates/user-settings.html:220 views.py:468
msgid "Created"
msgstr "Creat"
#: views.py:496
msgid "Updated form OK"
msgstr "Formulari actualitzat correctament"
#: views.py:497
msgid "Form edited"
msgstr "Formulari editat"
#: views.py:502
msgid "Slug is missing."
msgstr "La fitxa s'ha perdut"
#: views.py:505
#, python-format
msgid "Slug is not unique. %sslug"
msgstr "La fitxa no és única %sfitxa"
#: views.py:529
msgid "Form created"
msgstr "Formulari creat"
#: views.py:530
msgid "Saved form OK"
msgstr "Formulari guardat"
#: views.py:544 views.py:564 views.py:647
msgid "Form not found"
msgstr "Formulari no trobat"
#: views.py:551
#, python-format
msgid "Deleted '%s' and %s entries"
msgstr "S'han eliminat les entrades de '%s' i %s"
#: views.py:554
msgid "Form name does not match"
msgstr "El nom del formulari no coincideix"
#: views.py:578
#, python-format
msgid "Public set to: %s"
msgstr "Publicat a: %s"
#: views.py:588
#, python-format
msgid "Shared entries set to: %s"
msgstr "Les entrades compartides estan a %s"
#: views.py:654
msgid "We expected a number"
msgstr "Esperàvem un número"
#: views.py:659
#, python-format
msgid "Deleted %s entries"
msgstr "Entrades %s eliminades"
#: views.py:662
msgid "Number of entries does not match"
msgstr "El nombre d'entrades no coincideix"
#: views.py:702 views.py:713
#, python-format
msgid "We've sent an email to %s"
msgstr "Hem enviat un correu a %s"
#: views.py:725
msgid "Language updated OK"
msgstr "Idioma actualitzat correctament"
#: views.py:745
msgid "Invitation not found"
msgstr "No s'ha trobat la invitació"
#: views.py:748 views.py:866 views.py:912
msgid "Your petition has expired"
msgstr "La vostra petició ha expirat"
#: views.py:783
msgid "Opps! An error ocurred when creating the user"
msgstr "Vaja! Hi ha hagut un error quan s'ha creat l'usuari"
#: views.py:797
msgid "Welcome!"
msgstr "Benvingut!"
#: views.py:824
msgid "Bad credentials"
msgstr "Credencials dolentes"
#: views.py:849
msgid "We may have sent you an email"
msgstr "És possible que t'hàgim enviat un correu electrònic"
#: views.py:863
msgid "Couldn't find that token"
msgstr "No s'ha pogut trobar la clau"
#: views.py:871
msgid "Your account has been blocked"
msgstr "El teu compte ha sigut bloquejat"
#: views.py:895
msgid "Password changed OK"
msgstr "Contrasenya canviada correctament"
#: views.py:909
msgid "We couldn't find that petition"
msgstr "No hem pogut trobar aquesta petició"
#: views.py:925
msgid "Your email address is valid"
msgstr "La teva adreça de correu és vàlida"
#: views.py:938
msgid "Text saved OK"
msgstr "Text guardat correctament"
#: views.py:949
msgid "Site email address updated OK"
msgstr "L'espai del correu electrònic s'ha actualitzat correctament"
#: views.py:963
msgid "Site name changed OK"
msgstr "L'espai del nom s'ha canviat correctament"
#: views.py:972
msgid "SMTP config works!"
msgstr "La configuració de SMTP funciona!"
#: views.py:983
msgid "Schema is already up to date. Nothing to do."
msgstr "L’esquema ja està actualitzat. Res a fer."
#: views.py:991
msgid "Updated schema OK!"
msgstr "Actualització de l'esquema correcte!"
#: views.py:1035
msgid "Site not found"
msgstr "Lloc no trobat"
#: views.py:1041
msgid "Cannot delete current site"
msgstr "No es pot eliminar el lloc actual"
#: views.py:1045
#, python-format
msgid "Deleted %s"
msgstr "Eliminiat %s"
#: views.py:1048
msgid "Site name does not match"
msgstr "El nom del lloc no coincideix"
#: views.py:1104
#, python-format
msgid "We've sent an invitation to %s"
msgstr "Hem enviat una invitació a %s"
#: views.py:1122
msgid "Opps! We can't find that invitation"
msgstr "Vaja! No podem trobar aquesta invitació"
#: views.py:1144 views.py:1185
msgid "User not found"
msgstr "Usuari no trobat"
#: views.py:1190
msgid "Cannot delete root user"
msgstr "No es pot eliminar l'usuari arrel"
#: views.py:1193
msgid "Cannot delete yourself"
msgstr "No et pots eliminar a tu mateix"
#: views.py:1197
#, python-format
msgid "Deleted user '%s'"
msgstr "Usuari '%s' eliminat"
#: views.py:1200
msgid "Username does not match"
msgstr "L'usuari no coincideix"
#: templates/base.html:29
msgid "Start"
msgstr "Inici"