mirror of
https://github.com/ae-utbm/sith.git
synced 2025-07-09 19:40:19 +00:00
All: Apply Black coding rules
This commit is contained in:
@ -22,4 +22,4 @@
|
||||
#
|
||||
#
|
||||
|
||||
default_app_config = 'core.apps.SithConfig'
|
||||
default_app_config = "core.apps.SithConfig"
|
||||
|
@ -32,30 +32,38 @@ from haystack.admin import SearchModelAdmin
|
||||
admin.site.unregister(AuthGroup)
|
||||
admin.site.register(RealGroup)
|
||||
|
||||
|
||||
class UserAdmin(SearchModelAdmin):
|
||||
list_display = ["first_name", "last_name", "username", "email", "nick_name"]
|
||||
form = make_ajax_form(User, {
|
||||
'godfathers': 'users',
|
||||
'home': 'files', # ManyToManyField
|
||||
'profile_pict': 'files', # ManyToManyField
|
||||
'avatar_pict': 'files', # ManyToManyField
|
||||
'scrub_pict': 'files', # ManyToManyField
|
||||
})
|
||||
form = make_ajax_form(
|
||||
User,
|
||||
{
|
||||
"godfathers": "users",
|
||||
"home": "files", # ManyToManyField
|
||||
"profile_pict": "files", # ManyToManyField
|
||||
"avatar_pict": "files", # ManyToManyField
|
||||
"scrub_pict": "files", # ManyToManyField
|
||||
},
|
||||
)
|
||||
search_fields = ["first_name", "last_name", "username"]
|
||||
|
||||
|
||||
admin.site.register(User, UserAdmin)
|
||||
|
||||
|
||||
@admin.register(Page)
|
||||
class PageAdmin(admin.ModelAdmin):
|
||||
form = make_ajax_form(Page, {
|
||||
'lock_user': 'users',
|
||||
'owner_group': 'groups',
|
||||
'edit_groups': 'groups',
|
||||
'view_groups': 'groups',
|
||||
})
|
||||
form = make_ajax_form(
|
||||
Page,
|
||||
{
|
||||
"lock_user": "users",
|
||||
"owner_group": "groups",
|
||||
"edit_groups": "groups",
|
||||
"view_groups": "groups",
|
||||
},
|
||||
)
|
||||
|
||||
|
||||
@admin.register(SithFile)
|
||||
class SithFileAdmin(admin.ModelAdmin):
|
||||
form = make_ajax_form(SithFile, {
|
||||
'parent': 'files', # ManyToManyField
|
||||
})
|
||||
form = make_ajax_form(SithFile, {"parent": "files"}) # ManyToManyField
|
||||
|
12
core/apps.py
12
core/apps.py
@ -29,7 +29,7 @@ from django.core.signals import request_started
|
||||
|
||||
|
||||
class SithConfig(AppConfig):
|
||||
name = 'core'
|
||||
name = "core"
|
||||
verbose_name = "Core app of the Sith"
|
||||
|
||||
def ready(self):
|
||||
@ -47,6 +47,12 @@ class SithConfig(AppConfig):
|
||||
Forum._club_memberships = {}
|
||||
|
||||
print("Connecting signals!", file=sys.stderr)
|
||||
request_started.connect(clear_cached_groups, weak=False, dispatch_uid="clear_cached_groups")
|
||||
request_started.connect(clear_cached_memberships, weak=False, dispatch_uid="clear_cached_memberships")
|
||||
request_started.connect(
|
||||
clear_cached_groups, weak=False, dispatch_uid="clear_cached_groups"
|
||||
)
|
||||
request_started.connect(
|
||||
clear_cached_memberships,
|
||||
weak=False,
|
||||
dispatch_uid="clear_cached_memberships",
|
||||
)
|
||||
# TODO: there may be a need to add more cache clearing
|
||||
|
@ -33,9 +33,11 @@ from accounting.models import ClubAccount, Company
|
||||
|
||||
|
||||
def check_token(request):
|
||||
return ('counter_token' in request.session.keys() and
|
||||
request.session['counter_token'] and
|
||||
Counter.objects.filter(token=request.session['counter_token']).exists())
|
||||
return (
|
||||
"counter_token" in request.session.keys()
|
||||
and request.session["counter_token"]
|
||||
and Counter.objects.filter(token=request.session["counter_token"]).exists()
|
||||
)
|
||||
|
||||
|
||||
class RightManagedLookupChannel(LookupChannel):
|
||||
@ -44,7 +46,7 @@ class RightManagedLookupChannel(LookupChannel):
|
||||
raise PermissionDenied
|
||||
|
||||
|
||||
@register('users')
|
||||
@register("users")
|
||||
class UsersLookup(RightManagedLookupChannel):
|
||||
model = User
|
||||
|
||||
@ -58,7 +60,7 @@ class UsersLookup(RightManagedLookupChannel):
|
||||
return item.get_display_name()
|
||||
|
||||
|
||||
@register('groups')
|
||||
@register("groups")
|
||||
class GroupsLookup(RightManagedLookupChannel):
|
||||
model = Group
|
||||
|
||||
@ -72,7 +74,7 @@ class GroupsLookup(RightManagedLookupChannel):
|
||||
return item.name
|
||||
|
||||
|
||||
@register('clubs')
|
||||
@register("clubs")
|
||||
class ClubLookup(RightManagedLookupChannel):
|
||||
model = Club
|
||||
|
||||
@ -86,7 +88,7 @@ class ClubLookup(RightManagedLookupChannel):
|
||||
return item.name
|
||||
|
||||
|
||||
@register('counters')
|
||||
@register("counters")
|
||||
class CountersLookup(RightManagedLookupChannel):
|
||||
model = Counter
|
||||
|
||||
@ -97,19 +99,21 @@ class CountersLookup(RightManagedLookupChannel):
|
||||
return item.name
|
||||
|
||||
|
||||
@register('products')
|
||||
@register("products")
|
||||
class ProductsLookup(RightManagedLookupChannel):
|
||||
model = Product
|
||||
|
||||
def get_query(self, q, request):
|
||||
return (self.model.objects.filter(name__icontains=q) |
|
||||
self.model.objects.filter(code__icontains=q)).filter(archived=False)[:50]
|
||||
return (
|
||||
self.model.objects.filter(name__icontains=q)
|
||||
| self.model.objects.filter(code__icontains=q)
|
||||
).filter(archived=False)[:50]
|
||||
|
||||
def format_item_display(self, item):
|
||||
return "%s (%s)" % (item.name, item.code)
|
||||
|
||||
|
||||
@register('files')
|
||||
@register("files")
|
||||
class SithFileLookup(RightManagedLookupChannel):
|
||||
model = SithFile
|
||||
|
||||
@ -117,7 +121,7 @@ class SithFileLookup(RightManagedLookupChannel):
|
||||
return self.model.objects.filter(name__icontains=q)[:50]
|
||||
|
||||
|
||||
@register('club_accounts')
|
||||
@register("club_accounts")
|
||||
class ClubAccountLookup(RightManagedLookupChannel):
|
||||
model = ClubAccount
|
||||
|
||||
@ -128,7 +132,7 @@ class ClubAccountLookup(RightManagedLookupChannel):
|
||||
return item.name
|
||||
|
||||
|
||||
@register('companies')
|
||||
@register("companies")
|
||||
class CompaniesLookup(RightManagedLookupChannel):
|
||||
model = Company
|
||||
|
||||
|
@ -21,4 +21,3 @@
|
||||
# Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
#
|
||||
#
|
||||
|
||||
|
@ -33,10 +33,14 @@ class Command(BaseCommand):
|
||||
help = "Recursively check the file system with respect to the DB"
|
||||
|
||||
def add_arguments(self, parser):
|
||||
parser.add_argument('ids', metavar='ID', type=int, nargs='+', help="The file IDs to process")
|
||||
parser.add_argument(
|
||||
"ids", metavar="ID", type=int, nargs="+", help="The file IDs to process"
|
||||
)
|
||||
|
||||
def handle(self, *args, **options):
|
||||
root_path = os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(__file__))))
|
||||
files = SithFile.objects.filter(id__in=options['ids']).all()
|
||||
root_path = os.path.dirname(
|
||||
os.path.dirname(os.path.dirname(os.path.dirname(__file__)))
|
||||
)
|
||||
files = SithFile.objects.filter(id__in=options["ids"]).all()
|
||||
for f in files:
|
||||
f._check_fs()
|
||||
|
@ -33,15 +33,13 @@ class Command(BaseCommand):
|
||||
"""
|
||||
Compiles scss in static folder for production
|
||||
"""
|
||||
|
||||
help = "Compile scss files from static folder"
|
||||
|
||||
def compile(self, filename):
|
||||
args = {
|
||||
"filename": filename,
|
||||
"include_paths": settings.STATIC_ROOT,
|
||||
}
|
||||
args = {"filename": filename, "include_paths": settings.STATIC_ROOT}
|
||||
if settings.SASS_PRECISION:
|
||||
args['precision'] = settings.SASS_PRECISION
|
||||
args["precision"] = settings.SASS_PRECISION
|
||||
return sass.compile(**args)
|
||||
|
||||
def is_compilable(self, file, ext_list):
|
||||
@ -54,7 +52,7 @@ class Command(BaseCommand):
|
||||
file = os.path.join(folder, file)
|
||||
if os.path.isdir(file):
|
||||
self.exec_on_folder(file, func)
|
||||
elif self.is_compilable(file, ['.scss']):
|
||||
elif self.is_compilable(file, [".scss"]):
|
||||
to_exec.append(file)
|
||||
|
||||
for file in to_exec:
|
||||
@ -62,7 +60,7 @@ class Command(BaseCommand):
|
||||
|
||||
def compilescss(self, file):
|
||||
print("compiling %s" % file)
|
||||
with(open(file.replace('.scss', '.css'), "w")) as newfile:
|
||||
with (open(file.replace(".scss", ".css"), "w")) as newfile:
|
||||
newfile.write(self.compile(file))
|
||||
|
||||
def removescss(self, file):
|
||||
@ -77,4 +75,6 @@ class Command(BaseCommand):
|
||||
print("---- Removing scss files ----")
|
||||
self.exec_on_folder(settings.STATIC_ROOT, self.removescss)
|
||||
else:
|
||||
print("No static folder avalaible, please use collectstatic before compiling scss")
|
||||
print(
|
||||
"No static folder avalaible, please use collectstatic before compiling scss"
|
||||
)
|
||||
|
@ -27,11 +27,14 @@ from django.core.management.base import BaseCommand
|
||||
|
||||
from core.markdown import markdown
|
||||
|
||||
|
||||
class Command(BaseCommand):
|
||||
help = "Output the fully rendered doc/SYNTAX.md file"
|
||||
|
||||
def handle(self, *args, **options):
|
||||
root_path = os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(__file__))))
|
||||
with open(os.path.join(root_path) + '/doc/SYNTAX.md', 'r') as md:
|
||||
root_path = os.path.dirname(
|
||||
os.path.dirname(os.path.dirname(os.path.dirname(__file__)))
|
||||
)
|
||||
with open(os.path.join(root_path) + "/doc/SYNTAX.md", "r") as md:
|
||||
result = markdown(md.read())
|
||||
print(result, end='')
|
||||
print(result, end="")
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -33,10 +33,14 @@ class Command(BaseCommand):
|
||||
help = "Recursively repair the file system with respect to the DB"
|
||||
|
||||
def add_arguments(self, parser):
|
||||
parser.add_argument('ids', metavar='ID', type=int, nargs='+', help="The file IDs to process")
|
||||
parser.add_argument(
|
||||
"ids", metavar="ID", type=int, nargs="+", help="The file IDs to process"
|
||||
)
|
||||
|
||||
def handle(self, *args, **options):
|
||||
root_path = os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(__file__))))
|
||||
files = SithFile.objects.filter(id__in=options['ids']).all()
|
||||
root_path = os.path.dirname(
|
||||
os.path.dirname(os.path.dirname(os.path.dirname(__file__)))
|
||||
)
|
||||
files = SithFile.objects.filter(id__in=options["ids"]).all()
|
||||
for f in files:
|
||||
f._repair_fs()
|
||||
|
@ -31,22 +31,24 @@ class Command(BaseCommand):
|
||||
help = "Set up a new instance of the Sith AE"
|
||||
|
||||
def add_arguments(self, parser):
|
||||
parser.add_argument('--prod', action="store_true")
|
||||
parser.add_argument("--prod", action="store_true")
|
||||
|
||||
def handle(self, *args, **options):
|
||||
root_path = os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(__file__))))
|
||||
root_path = os.path.dirname(
|
||||
os.path.dirname(os.path.dirname(os.path.dirname(__file__)))
|
||||
)
|
||||
try:
|
||||
os.mkdir(os.path.join(root_path) + '/data')
|
||||
os.mkdir(os.path.join(root_path) + "/data")
|
||||
print("Data dir created")
|
||||
except Exception as e:
|
||||
repr(e)
|
||||
try:
|
||||
os.remove(os.path.join(root_path, 'db.sqlite3'))
|
||||
os.remove(os.path.join(root_path, "db.sqlite3"))
|
||||
print("db.sqlite3 deleted")
|
||||
except Exception as e:
|
||||
repr(e)
|
||||
call_command('migrate')
|
||||
if options['prod']:
|
||||
call_command('populate', '--prod')
|
||||
call_command("migrate")
|
||||
if options["prod"]:
|
||||
call_command("populate", "--prod")
|
||||
else:
|
||||
call_command('populate')
|
||||
call_command("populate")
|
||||
|
116
core/markdown.py
116
core/markdown.py
@ -30,7 +30,7 @@ from django.core.urlresolvers import reverse
|
||||
|
||||
class SithRenderer(Renderer):
|
||||
def file_link(self, id, suffix):
|
||||
return reverse('core:file_detail', kwargs={'file_id': id}) + suffix
|
||||
return reverse("core:file_detail", kwargs={"file_id": id}) + suffix
|
||||
|
||||
def exposant(self, text):
|
||||
return """<sup>%s</sup>""" % text
|
||||
@ -48,19 +48,19 @@ class SithRenderer(Renderer):
|
||||
:param text: alt text of the image.
|
||||
"""
|
||||
style = None
|
||||
if '?' in original_src:
|
||||
src, params = original_src.rsplit('?', maxsplit=1)
|
||||
m = re.search(r'(\d+%?)(x(\d+%?))?', params)
|
||||
if "?" in original_src:
|
||||
src, params = original_src.rsplit("?", maxsplit=1)
|
||||
m = re.search(r"(\d+%?)(x(\d+%?))?", params)
|
||||
if not m:
|
||||
src = original_src
|
||||
else:
|
||||
width = m.group(1)
|
||||
if not width.endswith('%'):
|
||||
if not width.endswith("%"):
|
||||
width += "px"
|
||||
style = "width: %s; " % width
|
||||
try:
|
||||
height = m.group(3)
|
||||
if not height.endswith('%'):
|
||||
if not height.endswith("%"):
|
||||
height += "px"
|
||||
style += "height: %s; " % height
|
||||
except:
|
||||
@ -77,67 +77,57 @@ class SithRenderer(Renderer):
|
||||
html = '<img src="%s" alt="%s"' % (src, text)
|
||||
if style:
|
||||
html = '%s style="%s"' % (html, style)
|
||||
if self.options.get('use_xhtml'):
|
||||
return '%s />' % html
|
||||
return '%s>' % html
|
||||
if self.options.get("use_xhtml"):
|
||||
return "%s />" % html
|
||||
return "%s>" % html
|
||||
|
||||
|
||||
class SithInlineGrammar(InlineGrammar):
|
||||
double_emphasis = re.compile(
|
||||
r'^\*{2}([\s\S]+?)\*{2}(?!\*)' # **word**
|
||||
)
|
||||
emphasis = re.compile(
|
||||
r'^\*((?:\*\*|[^\*])+?)\*(?!\*)' # *word*
|
||||
)
|
||||
underline = re.compile(
|
||||
r'^_{2}([\s\S]+?)_{2}(?!_)' # __word__
|
||||
)
|
||||
exposant = re.compile(
|
||||
r'^<sup>([\s\S]+?)</sup>' # <sup>text</sup>
|
||||
)
|
||||
indice = re.compile(
|
||||
r'^<sub>([\s\S]+?)</sub>' # <sub>text</sub>
|
||||
)
|
||||
double_emphasis = re.compile(r"^\*{2}([\s\S]+?)\*{2}(?!\*)") # **word**
|
||||
emphasis = re.compile(r"^\*((?:\*\*|[^\*])+?)\*(?!\*)") # *word*
|
||||
underline = re.compile(r"^_{2}([\s\S]+?)_{2}(?!_)") # __word__
|
||||
exposant = re.compile(r"^<sup>([\s\S]+?)</sup>") # <sup>text</sup>
|
||||
indice = re.compile(r"^<sub>([\s\S]+?)</sub>") # <sub>text</sub>
|
||||
|
||||
|
||||
class SithInlineLexer(InlineLexer):
|
||||
grammar_class = SithInlineGrammar
|
||||
|
||||
default_rules = [
|
||||
'escape',
|
||||
"escape",
|
||||
# 'inline_html',
|
||||
'autolink',
|
||||
'url',
|
||||
'footnote',
|
||||
'link',
|
||||
'reflink',
|
||||
'nolink',
|
||||
'exposant',
|
||||
'double_emphasis',
|
||||
'emphasis',
|
||||
'underline',
|
||||
'indice',
|
||||
'code',
|
||||
'linebreak',
|
||||
'strikethrough',
|
||||
'text',
|
||||
"autolink",
|
||||
"url",
|
||||
"footnote",
|
||||
"link",
|
||||
"reflink",
|
||||
"nolink",
|
||||
"exposant",
|
||||
"double_emphasis",
|
||||
"emphasis",
|
||||
"underline",
|
||||
"indice",
|
||||
"code",
|
||||
"linebreak",
|
||||
"strikethrough",
|
||||
"text",
|
||||
]
|
||||
inline_html_rules = [
|
||||
'escape',
|
||||
'autolink',
|
||||
'url',
|
||||
'link',
|
||||
'reflink',
|
||||
'nolink',
|
||||
'exposant',
|
||||
'double_emphasis',
|
||||
'emphasis',
|
||||
'underline',
|
||||
'indice',
|
||||
'code',
|
||||
'linebreak',
|
||||
'strikethrough',
|
||||
'text',
|
||||
"escape",
|
||||
"autolink",
|
||||
"url",
|
||||
"link",
|
||||
"reflink",
|
||||
"nolink",
|
||||
"exposant",
|
||||
"double_emphasis",
|
||||
"emphasis",
|
||||
"underline",
|
||||
"indice",
|
||||
"code",
|
||||
"linebreak",
|
||||
"strikethrough",
|
||||
"text",
|
||||
]
|
||||
|
||||
def output_underline(self, m):
|
||||
@ -166,22 +156,18 @@ class SithInlineLexer(InlineLexer):
|
||||
|
||||
def _process_link(self, m, link, title=None):
|
||||
try: # Add page:// support for links
|
||||
page = re.compile(
|
||||
r'^page://(\S*)' # page://nom_de_ma_page
|
||||
)
|
||||
page = re.compile(r"^page://(\S*)") # page://nom_de_ma_page
|
||||
match = page.search(link)
|
||||
page = match.group(1) or ""
|
||||
link = reverse('core:page', kwargs={'page_name': page})
|
||||
link = reverse("core:page", kwargs={"page_name": page})
|
||||
except:
|
||||
pass
|
||||
try: # Add file:// support for links
|
||||
file_link = re.compile(
|
||||
r'^file://(\d*)/?(\S*)?' # file://4000/download
|
||||
)
|
||||
file_link = re.compile(r"^file://(\d*)/?(\S*)?") # file://4000/download
|
||||
match = file_link.search(link)
|
||||
id = match.group(1)
|
||||
suffix = match.group(2) or ""
|
||||
link = reverse('core:file_detail', kwargs={'file_id': id}) + suffix
|
||||
link = reverse("core:file_detail", kwargs={"file_id": id}) + suffix
|
||||
except:
|
||||
pass
|
||||
return super(SithInlineLexer, self)._process_link(m, link, title)
|
||||
@ -194,6 +180,6 @@ markdown = Markdown(renderer, inline=inline)
|
||||
|
||||
if __name__ == "__main__":
|
||||
root_path = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
||||
with open(os.path.join(root_path) + '/doc/SYNTAX.md', 'r') as md:
|
||||
with open(os.path.join(root_path) + "/doc/SYNTAX.md", "r") as md:
|
||||
result = markdown(md.read())
|
||||
print(result, end='')
|
||||
print(result, end="")
|
||||
|
@ -26,14 +26,16 @@ import importlib
|
||||
from django.conf import settings
|
||||
from django.utils.functional import SimpleLazyObject
|
||||
from django.contrib.auth import get_user
|
||||
from django.contrib.auth.middleware import AuthenticationMiddleware as DjangoAuthenticationMiddleware
|
||||
from django.contrib.auth.middleware import (
|
||||
AuthenticationMiddleware as DjangoAuthenticationMiddleware,
|
||||
)
|
||||
|
||||
module, klass = settings.AUTH_ANONYMOUS_MODEL.rsplit('.', 1)
|
||||
module, klass = settings.AUTH_ANONYMOUS_MODEL.rsplit(".", 1)
|
||||
AnonymousUser = getattr(importlib.import_module(module), klass)
|
||||
|
||||
|
||||
def get_cached_user(request):
|
||||
if not hasattr(request, '_cached_user'):
|
||||
if not hasattr(request, "_cached_user"):
|
||||
user = get_user(request)
|
||||
if user.is_anonymous():
|
||||
user = AnonymousUser(request)
|
||||
@ -45,7 +47,7 @@ def get_cached_user(request):
|
||||
|
||||
class AuthenticationMiddleware(DjangoAuthenticationMiddleware):
|
||||
def process_request(self, request):
|
||||
assert hasattr(request, 'session'), (
|
||||
assert hasattr(request, "session"), (
|
||||
"The Django authentication middleware requires session middleware "
|
||||
"to be installed. Edit your MIDDLEWARE_CLASSES setting to insert "
|
||||
"'django.contrib.sessions.middleware.SessionMiddleware' before "
|
||||
|
@ -12,169 +12,559 @@ from django.conf import settings
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('auth', '0006_require_contenttypes_0002'),
|
||||
]
|
||||
dependencies = [("auth", "0006_require_contenttypes_0002")]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='User',
|
||||
name="User",
|
||||
fields=[
|
||||
('id', models.AutoField(primary_key=True, serialize=False, verbose_name='ID', auto_created=True)),
|
||||
('password', models.CharField(max_length=128, verbose_name='password')),
|
||||
('last_login', models.DateTimeField(null=True, verbose_name='last login', blank=True)),
|
||||
('username', models.CharField(help_text='Required. 254 characters or fewer. Letters, digits and @/./+/-/_ only.', unique=True, max_length=254, error_messages={'unique': 'A user with that username already exists.'}, verbose_name='username', validators=[django.core.validators.RegexValidator('^[\\w.@+-]+$', 'Enter a valid username. This value may contain only letters, numbers and @/./+/-/_ characters.')])),
|
||||
('first_name', models.CharField(max_length=64, verbose_name='first name')),
|
||||
('last_name', models.CharField(max_length=64, verbose_name='last name')),
|
||||
('email', models.EmailField(unique=True, max_length=254, verbose_name='email address')),
|
||||
('date_of_birth', models.DateField(null=True, verbose_name='date of birth', blank=True)),
|
||||
('nick_name', models.CharField(max_length=64, null=True, verbose_name='nick name', blank=True)),
|
||||
('is_staff', models.BooleanField(help_text='Designates whether the user can log into this admin site.', verbose_name='staff status', default=False)),
|
||||
('is_active', models.BooleanField(help_text='Designates whether this user should be treated as active. Unselect this instead of deleting accounts.', verbose_name='active', default=True)),
|
||||
('date_joined', models.DateField(auto_now_add=True, verbose_name='date joined')),
|
||||
('last_update', models.DateField(verbose_name='last update', auto_now=True)),
|
||||
('is_superuser', models.BooleanField(help_text='Designates whether this user is a superuser. ', verbose_name='superuser', default=False)),
|
||||
('sex', models.CharField(choices=[('MAN', 'Man'), ('WOMAN', 'Woman')], max_length=10, default='MAN', verbose_name='sex')),
|
||||
('tshirt_size', models.CharField(choices=[('-', '-'), ('XS', 'XS'), ('S', 'S'), ('M', 'M'), ('L', 'L'), ('XL', 'XL'), ('XXL', 'XXL'), ('XXXL', 'XXXL')], max_length=5, default='-', verbose_name='tshirt size')),
|
||||
('role', models.CharField(choices=[('STUDENT', 'Student'), ('ADMINISTRATIVE', 'Administrative agent'), ('TEACHER', 'Teacher'), ('AGENT', 'Agent'), ('DOCTOR', 'Doctor'), ('FORMER STUDENT', 'Former student'), ('SERVICE', 'Service')], max_length=15, blank=True, verbose_name='role', default='')),
|
||||
('department', models.CharField(choices=[('TC', 'TC'), ('IMSI', 'IMSI'), ('IMAP', 'IMAP'), ('INFO', 'INFO'), ('GI', 'GI'), ('E', 'E'), ('EE', 'EE'), ('GESC', 'GESC'), ('GMC', 'GMC'), ('MC', 'MC'), ('EDIM', 'EDIM'), ('HUMA', 'Humanities'), ('NA', 'N/A')], max_length=15, blank=True, verbose_name='department', default='NA')),
|
||||
('dpt_option', models.CharField(max_length=32, blank=True, verbose_name='dpt option', default='')),
|
||||
('semester', models.CharField(max_length=5, blank=True, verbose_name='semester', default='')),
|
||||
('quote', models.CharField(max_length=256, blank=True, verbose_name='quote', default='')),
|
||||
('school', models.CharField(max_length=80, blank=True, verbose_name='school', default='')),
|
||||
('promo', models.IntegerField(null=True, verbose_name='promo', validators=[core.models.validate_promo], blank=True)),
|
||||
('forum_signature', models.TextField(max_length=256, blank=True, verbose_name='forum signature', default='')),
|
||||
('second_email', models.EmailField(max_length=254, null=True, verbose_name='second email address', blank=True)),
|
||||
('phone', phonenumber_field.modelfields.PhoneNumberField(max_length=128, null=True, verbose_name='phone', blank=True)),
|
||||
('parent_phone', phonenumber_field.modelfields.PhoneNumberField(max_length=128, null=True, verbose_name='parent phone', blank=True)),
|
||||
('address', models.CharField(max_length=128, blank=True, verbose_name='address', default='')),
|
||||
('parent_address', models.CharField(max_length=128, blank=True, verbose_name='parent address', default='')),
|
||||
('is_subscriber_viewable', models.BooleanField(verbose_name='is subscriber viewable', default=True)),
|
||||
],
|
||||
options={
|
||||
'abstract': False,
|
||||
},
|
||||
managers=[
|
||||
('objects', django.contrib.auth.models.UserManager()),
|
||||
(
|
||||
"id",
|
||||
models.AutoField(
|
||||
primary_key=True,
|
||||
serialize=False,
|
||||
verbose_name="ID",
|
||||
auto_created=True,
|
||||
),
|
||||
),
|
||||
("password", models.CharField(max_length=128, verbose_name="password")),
|
||||
(
|
||||
"last_login",
|
||||
models.DateTimeField(
|
||||
null=True, verbose_name="last login", blank=True
|
||||
),
|
||||
),
|
||||
(
|
||||
"username",
|
||||
models.CharField(
|
||||
help_text="Required. 254 characters or fewer. Letters, digits and @/./+/-/_ only.",
|
||||
unique=True,
|
||||
max_length=254,
|
||||
error_messages={
|
||||
"unique": "A user with that username already exists."
|
||||
},
|
||||
verbose_name="username",
|
||||
validators=[
|
||||
django.core.validators.RegexValidator(
|
||||
"^[\\w.@+-]+$",
|
||||
"Enter a valid username. This value may contain only letters, numbers and @/./+/-/_ characters.",
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
(
|
||||
"first_name",
|
||||
models.CharField(max_length=64, verbose_name="first name"),
|
||||
),
|
||||
(
|
||||
"last_name",
|
||||
models.CharField(max_length=64, verbose_name="last name"),
|
||||
),
|
||||
(
|
||||
"email",
|
||||
models.EmailField(
|
||||
unique=True, max_length=254, verbose_name="email address"
|
||||
),
|
||||
),
|
||||
(
|
||||
"date_of_birth",
|
||||
models.DateField(
|
||||
null=True, verbose_name="date of birth", blank=True
|
||||
),
|
||||
),
|
||||
(
|
||||
"nick_name",
|
||||
models.CharField(
|
||||
max_length=64, null=True, verbose_name="nick name", blank=True
|
||||
),
|
||||
),
|
||||
(
|
||||
"is_staff",
|
||||
models.BooleanField(
|
||||
help_text="Designates whether the user can log into this admin site.",
|
||||
verbose_name="staff status",
|
||||
default=False,
|
||||
),
|
||||
),
|
||||
(
|
||||
"is_active",
|
||||
models.BooleanField(
|
||||
help_text="Designates whether this user should be treated as active. Unselect this instead of deleting accounts.",
|
||||
verbose_name="active",
|
||||
default=True,
|
||||
),
|
||||
),
|
||||
(
|
||||
"date_joined",
|
||||
models.DateField(auto_now_add=True, verbose_name="date joined"),
|
||||
),
|
||||
(
|
||||
"last_update",
|
||||
models.DateField(verbose_name="last update", auto_now=True),
|
||||
),
|
||||
(
|
||||
"is_superuser",
|
||||
models.BooleanField(
|
||||
help_text="Designates whether this user is a superuser. ",
|
||||
verbose_name="superuser",
|
||||
default=False,
|
||||
),
|
||||
),
|
||||
(
|
||||
"sex",
|
||||
models.CharField(
|
||||
choices=[("MAN", "Man"), ("WOMAN", "Woman")],
|
||||
max_length=10,
|
||||
default="MAN",
|
||||
verbose_name="sex",
|
||||
),
|
||||
),
|
||||
(
|
||||
"tshirt_size",
|
||||
models.CharField(
|
||||
choices=[
|
||||
("-", "-"),
|
||||
("XS", "XS"),
|
||||
("S", "S"),
|
||||
("M", "M"),
|
||||
("L", "L"),
|
||||
("XL", "XL"),
|
||||
("XXL", "XXL"),
|
||||
("XXXL", "XXXL"),
|
||||
],
|
||||
max_length=5,
|
||||
default="-",
|
||||
verbose_name="tshirt size",
|
||||
),
|
||||
),
|
||||
(
|
||||
"role",
|
||||
models.CharField(
|
||||
choices=[
|
||||
("STUDENT", "Student"),
|
||||
("ADMINISTRATIVE", "Administrative agent"),
|
||||
("TEACHER", "Teacher"),
|
||||
("AGENT", "Agent"),
|
||||
("DOCTOR", "Doctor"),
|
||||
("FORMER STUDENT", "Former student"),
|
||||
("SERVICE", "Service"),
|
||||
],
|
||||
max_length=15,
|
||||
blank=True,
|
||||
verbose_name="role",
|
||||
default="",
|
||||
),
|
||||
),
|
||||
(
|
||||
"department",
|
||||
models.CharField(
|
||||
choices=[
|
||||
("TC", "TC"),
|
||||
("IMSI", "IMSI"),
|
||||
("IMAP", "IMAP"),
|
||||
("INFO", "INFO"),
|
||||
("GI", "GI"),
|
||||
("E", "E"),
|
||||
("EE", "EE"),
|
||||
("GESC", "GESC"),
|
||||
("GMC", "GMC"),
|
||||
("MC", "MC"),
|
||||
("EDIM", "EDIM"),
|
||||
("HUMA", "Humanities"),
|
||||
("NA", "N/A"),
|
||||
],
|
||||
max_length=15,
|
||||
blank=True,
|
||||
verbose_name="department",
|
||||
default="NA",
|
||||
),
|
||||
),
|
||||
(
|
||||
"dpt_option",
|
||||
models.CharField(
|
||||
max_length=32, blank=True, verbose_name="dpt option", default=""
|
||||
),
|
||||
),
|
||||
(
|
||||
"semester",
|
||||
models.CharField(
|
||||
max_length=5, blank=True, verbose_name="semester", default=""
|
||||
),
|
||||
),
|
||||
(
|
||||
"quote",
|
||||
models.CharField(
|
||||
max_length=256, blank=True, verbose_name="quote", default=""
|
||||
),
|
||||
),
|
||||
(
|
||||
"school",
|
||||
models.CharField(
|
||||
max_length=80, blank=True, verbose_name="school", default=""
|
||||
),
|
||||
),
|
||||
(
|
||||
"promo",
|
||||
models.IntegerField(
|
||||
null=True,
|
||||
verbose_name="promo",
|
||||
validators=[core.models.validate_promo],
|
||||
blank=True,
|
||||
),
|
||||
),
|
||||
(
|
||||
"forum_signature",
|
||||
models.TextField(
|
||||
max_length=256,
|
||||
blank=True,
|
||||
verbose_name="forum signature",
|
||||
default="",
|
||||
),
|
||||
),
|
||||
(
|
||||
"second_email",
|
||||
models.EmailField(
|
||||
max_length=254,
|
||||
null=True,
|
||||
verbose_name="second email address",
|
||||
blank=True,
|
||||
),
|
||||
),
|
||||
(
|
||||
"phone",
|
||||
phonenumber_field.modelfields.PhoneNumberField(
|
||||
max_length=128, null=True, verbose_name="phone", blank=True
|
||||
),
|
||||
),
|
||||
(
|
||||
"parent_phone",
|
||||
phonenumber_field.modelfields.PhoneNumberField(
|
||||
max_length=128,
|
||||
null=True,
|
||||
verbose_name="parent phone",
|
||||
blank=True,
|
||||
),
|
||||
),
|
||||
(
|
||||
"address",
|
||||
models.CharField(
|
||||
max_length=128, blank=True, verbose_name="address", default=""
|
||||
),
|
||||
),
|
||||
(
|
||||
"parent_address",
|
||||
models.CharField(
|
||||
max_length=128,
|
||||
blank=True,
|
||||
verbose_name="parent address",
|
||||
default="",
|
||||
),
|
||||
),
|
||||
(
|
||||
"is_subscriber_viewable",
|
||||
models.BooleanField(
|
||||
verbose_name="is subscriber viewable", default=True
|
||||
),
|
||||
),
|
||||
],
|
||||
options={"abstract": False},
|
||||
managers=[("objects", django.contrib.auth.models.UserManager())],
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='Group',
|
||||
name="Group",
|
||||
fields=[
|
||||
('group_ptr', models.OneToOneField(primary_key=True, parent_link=True, serialize=False, to='auth.Group', auto_created=True)),
|
||||
('is_meta', models.BooleanField(help_text='Whether a group is a meta group or not', verbose_name='meta group status', default=False)),
|
||||
('description', models.CharField(max_length=60, verbose_name='description')),
|
||||
(
|
||||
"group_ptr",
|
||||
models.OneToOneField(
|
||||
primary_key=True,
|
||||
parent_link=True,
|
||||
serialize=False,
|
||||
to="auth.Group",
|
||||
auto_created=True,
|
||||
),
|
||||
),
|
||||
(
|
||||
"is_meta",
|
||||
models.BooleanField(
|
||||
help_text="Whether a group is a meta group or not",
|
||||
verbose_name="meta group status",
|
||||
default=False,
|
||||
),
|
||||
),
|
||||
(
|
||||
"description",
|
||||
models.CharField(max_length=60, verbose_name="description"),
|
||||
),
|
||||
],
|
||||
bases=('auth.group',),
|
||||
bases=("auth.group",),
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='Page',
|
||||
name="Page",
|
||||
fields=[
|
||||
('id', models.AutoField(primary_key=True, serialize=False, verbose_name='ID', auto_created=True)),
|
||||
('name', models.CharField(max_length=30, verbose_name='page name')),
|
||||
('_full_name', models.CharField(max_length=255, blank=True, verbose_name='page name')),
|
||||
('edit_groups', models.ManyToManyField(related_name='editable_page', to='core.Group', blank=True, verbose_name='edit group')),
|
||||
('owner_group', models.ForeignKey(default=1, related_name='owned_page', verbose_name='owner group', to='core.Group')),
|
||||
('parent', models.ForeignKey(on_delete=django.db.models.deletion.SET_NULL, null=True, related_name='children', verbose_name='parent', to='core.Page', blank=True)),
|
||||
('view_groups', models.ManyToManyField(related_name='viewable_page', to='core.Group', blank=True, verbose_name='view group')),
|
||||
(
|
||||
"id",
|
||||
models.AutoField(
|
||||
primary_key=True,
|
||||
serialize=False,
|
||||
verbose_name="ID",
|
||||
auto_created=True,
|
||||
),
|
||||
),
|
||||
("name", models.CharField(max_length=30, verbose_name="page name")),
|
||||
(
|
||||
"_full_name",
|
||||
models.CharField(
|
||||
max_length=255, blank=True, verbose_name="page name"
|
||||
),
|
||||
),
|
||||
(
|
||||
"edit_groups",
|
||||
models.ManyToManyField(
|
||||
related_name="editable_page",
|
||||
to="core.Group",
|
||||
blank=True,
|
||||
verbose_name="edit group",
|
||||
),
|
||||
),
|
||||
(
|
||||
"owner_group",
|
||||
models.ForeignKey(
|
||||
default=1,
|
||||
related_name="owned_page",
|
||||
verbose_name="owner group",
|
||||
to="core.Group",
|
||||
),
|
||||
),
|
||||
(
|
||||
"parent",
|
||||
models.ForeignKey(
|
||||
on_delete=django.db.models.deletion.SET_NULL,
|
||||
null=True,
|
||||
related_name="children",
|
||||
verbose_name="parent",
|
||||
to="core.Page",
|
||||
blank=True,
|
||||
),
|
||||
),
|
||||
(
|
||||
"view_groups",
|
||||
models.ManyToManyField(
|
||||
related_name="viewable_page",
|
||||
to="core.Group",
|
||||
blank=True,
|
||||
verbose_name="view group",
|
||||
),
|
||||
),
|
||||
],
|
||||
options={
|
||||
'permissions': (('change_prop_page', "Can change the page's properties (groups, ...)"), ('view_page', 'Can view the page')),
|
||||
"permissions": (
|
||||
(
|
||||
"change_prop_page",
|
||||
"Can change the page's properties (groups, ...)",
|
||||
),
|
||||
("view_page", "Can view the page"),
|
||||
)
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='PageRev',
|
||||
name="PageRev",
|
||||
fields=[
|
||||
('id', models.AutoField(primary_key=True, serialize=False, verbose_name='ID', auto_created=True)),
|
||||
('revision', models.IntegerField(verbose_name='revision')),
|
||||
('title', models.CharField(max_length=255, blank=True, verbose_name='page title')),
|
||||
('content', models.TextField(blank=True, verbose_name='page content')),
|
||||
('date', models.DateTimeField(verbose_name='date', auto_now=True)),
|
||||
('author', models.ForeignKey(to=settings.AUTH_USER_MODEL, related_name='page_rev')),
|
||||
('page', models.ForeignKey(to='core.Page', related_name='revisions')),
|
||||
(
|
||||
"id",
|
||||
models.AutoField(
|
||||
primary_key=True,
|
||||
serialize=False,
|
||||
verbose_name="ID",
|
||||
auto_created=True,
|
||||
),
|
||||
),
|
||||
("revision", models.IntegerField(verbose_name="revision")),
|
||||
(
|
||||
"title",
|
||||
models.CharField(
|
||||
max_length=255, blank=True, verbose_name="page title"
|
||||
),
|
||||
),
|
||||
("content", models.TextField(blank=True, verbose_name="page content")),
|
||||
("date", models.DateTimeField(verbose_name="date", auto_now=True)),
|
||||
(
|
||||
"author",
|
||||
models.ForeignKey(
|
||||
to=settings.AUTH_USER_MODEL, related_name="page_rev"
|
||||
),
|
||||
),
|
||||
("page", models.ForeignKey(to="core.Page", related_name="revisions")),
|
||||
],
|
||||
options={
|
||||
'ordering': ['date'],
|
||||
},
|
||||
options={"ordering": ["date"]},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='Preferences',
|
||||
name="Preferences",
|
||||
fields=[
|
||||
('id', models.AutoField(primary_key=True, serialize=False, verbose_name='ID', auto_created=True)),
|
||||
('show_my_stats', models.BooleanField(help_text='Show your account statistics to others', verbose_name='define if we show a users stats', default=False)),
|
||||
('user', models.OneToOneField(to=settings.AUTH_USER_MODEL, related_name='preferences')),
|
||||
(
|
||||
"id",
|
||||
models.AutoField(
|
||||
primary_key=True,
|
||||
serialize=False,
|
||||
verbose_name="ID",
|
||||
auto_created=True,
|
||||
),
|
||||
),
|
||||
(
|
||||
"show_my_stats",
|
||||
models.BooleanField(
|
||||
help_text="Show your account statistics to others",
|
||||
verbose_name="define if we show a users stats",
|
||||
default=False,
|
||||
),
|
||||
),
|
||||
(
|
||||
"user",
|
||||
models.OneToOneField(
|
||||
to=settings.AUTH_USER_MODEL, related_name="preferences"
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='SithFile',
|
||||
name="SithFile",
|
||||
fields=[
|
||||
('id', models.AutoField(primary_key=True, serialize=False, verbose_name='ID', auto_created=True)),
|
||||
('name', models.CharField(max_length=30, verbose_name='file name')),
|
||||
('file', models.FileField(upload_to=core.models.get_directory, null=True, verbose_name='file', blank=True)),
|
||||
('is_folder', models.BooleanField(verbose_name='is folder', default=True)),
|
||||
('mime_type', models.CharField(max_length=30, verbose_name='mime type')),
|
||||
('size', models.IntegerField(default=0, verbose_name='size')),
|
||||
('date', models.DateTimeField(verbose_name='date', auto_now=True)),
|
||||
('edit_groups', models.ManyToManyField(related_name='editable_files', to='core.Group', blank=True, verbose_name='edit group')),
|
||||
('owner', models.ForeignKey(verbose_name='owner', to=settings.AUTH_USER_MODEL, related_name='owned_files')),
|
||||
('parent', models.ForeignKey(null=True, related_name='children', verbose_name='parent', to='core.SithFile', blank=True)),
|
||||
('view_groups', models.ManyToManyField(related_name='viewable_files', to='core.Group', blank=True, verbose_name='view group')),
|
||||
(
|
||||
"id",
|
||||
models.AutoField(
|
||||
primary_key=True,
|
||||
serialize=False,
|
||||
verbose_name="ID",
|
||||
auto_created=True,
|
||||
),
|
||||
),
|
||||
("name", models.CharField(max_length=30, verbose_name="file name")),
|
||||
(
|
||||
"file",
|
||||
models.FileField(
|
||||
upload_to=core.models.get_directory,
|
||||
null=True,
|
||||
verbose_name="file",
|
||||
blank=True,
|
||||
),
|
||||
),
|
||||
(
|
||||
"is_folder",
|
||||
models.BooleanField(verbose_name="is folder", default=True),
|
||||
),
|
||||
(
|
||||
"mime_type",
|
||||
models.CharField(max_length=30, verbose_name="mime type"),
|
||||
),
|
||||
("size", models.IntegerField(default=0, verbose_name="size")),
|
||||
("date", models.DateTimeField(verbose_name="date", auto_now=True)),
|
||||
(
|
||||
"edit_groups",
|
||||
models.ManyToManyField(
|
||||
related_name="editable_files",
|
||||
to="core.Group",
|
||||
blank=True,
|
||||
verbose_name="edit group",
|
||||
),
|
||||
),
|
||||
(
|
||||
"owner",
|
||||
models.ForeignKey(
|
||||
verbose_name="owner",
|
||||
to=settings.AUTH_USER_MODEL,
|
||||
related_name="owned_files",
|
||||
),
|
||||
),
|
||||
(
|
||||
"parent",
|
||||
models.ForeignKey(
|
||||
null=True,
|
||||
related_name="children",
|
||||
verbose_name="parent",
|
||||
to="core.SithFile",
|
||||
blank=True,
|
||||
),
|
||||
),
|
||||
(
|
||||
"view_groups",
|
||||
models.ManyToManyField(
|
||||
related_name="viewable_files",
|
||||
to="core.Group",
|
||||
blank=True,
|
||||
verbose_name="view group",
|
||||
),
|
||||
),
|
||||
],
|
||||
options={
|
||||
'verbose_name': 'file',
|
||||
},
|
||||
options={"verbose_name": "file"},
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='user',
|
||||
name='avatar_pict',
|
||||
field=models.OneToOneField(blank=True, on_delete=django.db.models.deletion.SET_NULL, null=True, related_name='avatar_of', verbose_name='avatar', to='core.SithFile'),
|
||||
model_name="user",
|
||||
name="avatar_pict",
|
||||
field=models.OneToOneField(
|
||||
blank=True,
|
||||
on_delete=django.db.models.deletion.SET_NULL,
|
||||
null=True,
|
||||
related_name="avatar_of",
|
||||
verbose_name="avatar",
|
||||
to="core.SithFile",
|
||||
),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='user',
|
||||
name='home',
|
||||
field=models.OneToOneField(blank=True, null=True, related_name='home_of', verbose_name='home', to='core.SithFile'),
|
||||
model_name="user",
|
||||
name="home",
|
||||
field=models.OneToOneField(
|
||||
blank=True,
|
||||
null=True,
|
||||
related_name="home_of",
|
||||
verbose_name="home",
|
||||
to="core.SithFile",
|
||||
),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='user',
|
||||
name='profile_pict',
|
||||
field=models.OneToOneField(blank=True, on_delete=django.db.models.deletion.SET_NULL, null=True, related_name='profile_of', verbose_name='profile', to='core.SithFile'),
|
||||
model_name="user",
|
||||
name="profile_pict",
|
||||
field=models.OneToOneField(
|
||||
blank=True,
|
||||
on_delete=django.db.models.deletion.SET_NULL,
|
||||
null=True,
|
||||
related_name="profile_of",
|
||||
verbose_name="profile",
|
||||
to="core.SithFile",
|
||||
),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='user',
|
||||
name='scrub_pict',
|
||||
field=models.OneToOneField(blank=True, on_delete=django.db.models.deletion.SET_NULL, null=True, related_name='scrub_of', verbose_name='scrub', to='core.SithFile'),
|
||||
model_name="user",
|
||||
name="scrub_pict",
|
||||
field=models.OneToOneField(
|
||||
blank=True,
|
||||
on_delete=django.db.models.deletion.SET_NULL,
|
||||
null=True,
|
||||
related_name="scrub_of",
|
||||
verbose_name="scrub",
|
||||
to="core.SithFile",
|
||||
),
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='MetaGroup',
|
||||
fields=[
|
||||
],
|
||||
options={
|
||||
'proxy': True,
|
||||
},
|
||||
bases=('core.group',),
|
||||
managers=[
|
||||
('objects', core.models.MetaGroupManager()),
|
||||
],
|
||||
name="MetaGroup",
|
||||
fields=[],
|
||||
options={"proxy": True},
|
||||
bases=("core.group",),
|
||||
managers=[("objects", core.models.MetaGroupManager())],
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='RealGroup',
|
||||
fields=[
|
||||
],
|
||||
options={
|
||||
'proxy': True,
|
||||
},
|
||||
bases=('core.group',),
|
||||
managers=[
|
||||
('objects', core.models.RealGroupManager()),
|
||||
],
|
||||
name="RealGroup",
|
||||
fields=[],
|
||||
options={"proxy": True},
|
||||
bases=("core.group",),
|
||||
managers=[("objects", core.models.RealGroupManager())],
|
||||
),
|
||||
migrations.AlterUniqueTogether(
|
||||
name='page',
|
||||
unique_together=set([('name', 'parent')]),
|
||||
name="page", unique_together=set([("name", "parent")])
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='user',
|
||||
name='groups',
|
||||
field=models.ManyToManyField(to='core.RealGroup', blank=True, related_name='users'),
|
||||
model_name="user",
|
||||
name="groups",
|
||||
field=models.ManyToManyField(
|
||||
to="core.RealGroup", blank=True, related_name="users"
|
||||
),
|
||||
),
|
||||
]
|
||||
|
@ -6,14 +6,12 @@ from django.db import migrations, models
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('core', '0001_initial'),
|
||||
]
|
||||
dependencies = [("core", "0001_initial")]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='sithfile',
|
||||
name='name',
|
||||
field=models.CharField(verbose_name='file name', max_length=256),
|
||||
),
|
||||
model_name="sithfile",
|
||||
name="name",
|
||||
field=models.CharField(verbose_name="file name", max_length=256),
|
||||
)
|
||||
]
|
||||
|
@ -7,14 +7,24 @@ import django.core.validators
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('core', '0002_auto_20160831_0144'),
|
||||
]
|
||||
dependencies = [("core", "0002_auto_20160831_0144")]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='user',
|
||||
name='username',
|
||||
field=models.CharField(error_messages={'unique': 'A user with that username already exists.'}, max_length=254, unique=True, validators=[django.core.validators.RegexValidator('^[\\w.+-]+$', 'Enter a valid username. This value may contain only letters, numbers and ./+/-/_ characters.')], help_text='Required. 254 characters or fewer. Letters, digits and ./+/-/_ only.', verbose_name='username'),
|
||||
),
|
||||
model_name="user",
|
||||
name="username",
|
||||
field=models.CharField(
|
||||
error_messages={"unique": "A user with that username already exists."},
|
||||
max_length=254,
|
||||
unique=True,
|
||||
validators=[
|
||||
django.core.validators.RegexValidator(
|
||||
"^[\\w.+-]+$",
|
||||
"Enter a valid username. This value may contain only letters, numbers and ./+/-/_ characters.",
|
||||
)
|
||||
],
|
||||
help_text="Required. 254 characters or fewer. Letters, digits and ./+/-/_ only.",
|
||||
verbose_name="username",
|
||||
),
|
||||
)
|
||||
]
|
||||
|
@ -7,14 +7,14 @@ from django.conf import settings
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('core', '0003_auto_20160902_1914'),
|
||||
]
|
||||
dependencies = [("core", "0003_auto_20160902_1914")]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='user',
|
||||
name='godfathers',
|
||||
field=models.ManyToManyField(to=settings.AUTH_USER_MODEL, related_name='godchildren', blank=True),
|
||||
),
|
||||
model_name="user",
|
||||
name="godfathers",
|
||||
field=models.ManyToManyField(
|
||||
to=settings.AUTH_USER_MODEL, related_name="godchildren", blank=True
|
||||
),
|
||||
)
|
||||
]
|
||||
|
@ -7,19 +7,26 @@ from django.conf import settings
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('core', '0004_user_godfathers'),
|
||||
]
|
||||
dependencies = [("core", "0004_user_godfathers")]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='page',
|
||||
name='lock_timeout',
|
||||
field=models.DateTimeField(verbose_name='lock_timeout', null=True, blank=True, default=None),
|
||||
model_name="page",
|
||||
name="lock_timeout",
|
||||
field=models.DateTimeField(
|
||||
verbose_name="lock_timeout", null=True, blank=True, default=None
|
||||
),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='page',
|
||||
name='lock_user',
|
||||
field=models.ForeignKey(verbose_name='lock user', default=None, blank=True, to=settings.AUTH_USER_MODEL, null=True, related_name='locked_pages'),
|
||||
model_name="page",
|
||||
name="lock_user",
|
||||
field=models.ForeignKey(
|
||||
verbose_name="lock user",
|
||||
default=None,
|
||||
blank=True,
|
||||
to=settings.AUTH_USER_MODEL,
|
||||
null=True,
|
||||
related_name="locked_pages",
|
||||
),
|
||||
),
|
||||
]
|
||||
|
@ -6,14 +6,12 @@ from django.db import migrations, models
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('core', '0005_auto_20161105_1035'),
|
||||
]
|
||||
dependencies = [("core", "0005_auto_20161105_1035")]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='sithfile',
|
||||
name='is_moderated',
|
||||
field=models.BooleanField(verbose_name='is moderated', default=False),
|
||||
),
|
||||
model_name="sithfile",
|
||||
name="is_moderated",
|
||||
field=models.BooleanField(verbose_name="is moderated", default=False),
|
||||
)
|
||||
]
|
||||
|
@ -6,14 +6,12 @@ from django.db import migrations, models
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('core', '0006_auto_20161108_1703'),
|
||||
]
|
||||
dependencies = [("core", "0006_auto_20161108_1703")]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='sithfile',
|
||||
name='asked_for_removal',
|
||||
field=models.BooleanField(default=False, verbose_name='asked for removal'),
|
||||
),
|
||||
model_name="sithfile",
|
||||
name="asked_for_removal",
|
||||
field=models.BooleanField(default=False, verbose_name="asked for removal"),
|
||||
)
|
||||
]
|
||||
|
@ -8,24 +8,39 @@ import core.models
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('core', '0008_sithfile_asked_for_removal'),
|
||||
]
|
||||
dependencies = [("core", "0008_sithfile_asked_for_removal")]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='sithfile',
|
||||
name='compressed',
|
||||
field=models.FileField(upload_to=core.models.get_compressed_directory, null=True, verbose_name='compressed file', blank=True),
|
||||
model_name="sithfile",
|
||||
name="compressed",
|
||||
field=models.FileField(
|
||||
upload_to=core.models.get_compressed_directory,
|
||||
null=True,
|
||||
verbose_name="compressed file",
|
||||
blank=True,
|
||||
),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='sithfile',
|
||||
name='thumbnail',
|
||||
field=models.FileField(upload_to=core.models.get_thumbnail_directory, null=True, verbose_name='thumbnail', blank=True),
|
||||
model_name="sithfile",
|
||||
name="thumbnail",
|
||||
field=models.FileField(
|
||||
upload_to=core.models.get_thumbnail_directory,
|
||||
null=True,
|
||||
verbose_name="thumbnail",
|
||||
blank=True,
|
||||
),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='user',
|
||||
name='home',
|
||||
field=models.OneToOneField(verbose_name='home', related_name='home_of', on_delete=django.db.models.deletion.SET_NULL, null=True, to='core.SithFile', blank=True),
|
||||
model_name="user",
|
||||
name="home",
|
||||
field=models.OneToOneField(
|
||||
verbose_name="home",
|
||||
related_name="home_of",
|
||||
on_delete=django.db.models.deletion.SET_NULL,
|
||||
null=True,
|
||||
to="core.SithFile",
|
||||
blank=True,
|
||||
),
|
||||
),
|
||||
]
|
||||
|
@ -6,14 +6,12 @@ from django.db import migrations, models
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('core', '0009_auto_20161120_1155'),
|
||||
]
|
||||
dependencies = [("core", "0009_auto_20161120_1155")]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='sithfile',
|
||||
name='is_in_sas',
|
||||
field=models.BooleanField(verbose_name='is in the SAS', default=False),
|
||||
),
|
||||
model_name="sithfile",
|
||||
name="is_in_sas",
|
||||
field=models.BooleanField(verbose_name="is in the SAS", default=False),
|
||||
)
|
||||
]
|
||||
|
@ -8,29 +8,47 @@ import core.models
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('core', '0010_sithfile_is_in_sas'),
|
||||
]
|
||||
dependencies = [("core", "0010_sithfile_is_in_sas")]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='sithfile',
|
||||
name='compressed',
|
||||
field=models.FileField(verbose_name='compressed file', upload_to=core.models.get_compressed_directory, null=True, blank=True, max_length=256),
|
||||
model_name="sithfile",
|
||||
name="compressed",
|
||||
field=models.FileField(
|
||||
verbose_name="compressed file",
|
||||
upload_to=core.models.get_compressed_directory,
|
||||
null=True,
|
||||
blank=True,
|
||||
max_length=256,
|
||||
),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='sithfile',
|
||||
name='date',
|
||||
field=models.DateTimeField(verbose_name='date', default=django.utils.timezone.now),
|
||||
model_name="sithfile",
|
||||
name="date",
|
||||
field=models.DateTimeField(
|
||||
verbose_name="date", default=django.utils.timezone.now
|
||||
),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='sithfile',
|
||||
name='file',
|
||||
field=models.FileField(verbose_name='file', upload_to=core.models.get_directory, null=True, blank=True, max_length=256),
|
||||
model_name="sithfile",
|
||||
name="file",
|
||||
field=models.FileField(
|
||||
verbose_name="file",
|
||||
upload_to=core.models.get_directory,
|
||||
null=True,
|
||||
blank=True,
|
||||
max_length=256,
|
||||
),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='sithfile',
|
||||
name='thumbnail',
|
||||
field=models.FileField(verbose_name='thumbnail', upload_to=core.models.get_thumbnail_directory, null=True, blank=True, max_length=256),
|
||||
model_name="sithfile",
|
||||
name="thumbnail",
|
||||
field=models.FileField(
|
||||
verbose_name="thumbnail",
|
||||
upload_to=core.models.get_thumbnail_directory,
|
||||
null=True,
|
||||
blank=True,
|
||||
max_length=256,
|
||||
),
|
||||
),
|
||||
]
|
||||
|
@ -8,20 +8,49 @@ import django.utils.timezone
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('core', '0011_auto_20161124_0848'),
|
||||
]
|
||||
dependencies = [("core", "0011_auto_20161124_0848")]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='Notification',
|
||||
name="Notification",
|
||||
fields=[
|
||||
('id', models.AutoField(primary_key=True, verbose_name='ID', auto_created=True, serialize=False)),
|
||||
('url', models.CharField(max_length=255, verbose_name='url')),
|
||||
('text', models.CharField(max_length=512, verbose_name='text')),
|
||||
('type', models.CharField(max_length=16, choices=[('FILE_MODERATION', 'File moderation'), ('SAS_MODERATION', 'SAS moderation'), ('NEW_PICTURES', 'New pictures')], verbose_name='text', null=True, blank=True)),
|
||||
('date', models.DateTimeField(verbose_name='date', default=django.utils.timezone.now)),
|
||||
('user', models.ForeignKey(related_name='notifications', to=settings.AUTH_USER_MODEL)),
|
||||
(
|
||||
"id",
|
||||
models.AutoField(
|
||||
primary_key=True,
|
||||
verbose_name="ID",
|
||||
auto_created=True,
|
||||
serialize=False,
|
||||
),
|
||||
),
|
||||
("url", models.CharField(max_length=255, verbose_name="url")),
|
||||
("text", models.CharField(max_length=512, verbose_name="text")),
|
||||
(
|
||||
"type",
|
||||
models.CharField(
|
||||
max_length=16,
|
||||
choices=[
|
||||
("FILE_MODERATION", "File moderation"),
|
||||
("SAS_MODERATION", "SAS moderation"),
|
||||
("NEW_PICTURES", "New pictures"),
|
||||
],
|
||||
verbose_name="text",
|
||||
null=True,
|
||||
blank=True,
|
||||
),
|
||||
),
|
||||
(
|
||||
"date",
|
||||
models.DateTimeField(
|
||||
verbose_name="date", default=django.utils.timezone.now
|
||||
),
|
||||
),
|
||||
(
|
||||
"user",
|
||||
models.ForeignKey(
|
||||
related_name="notifications", to=settings.AUTH_USER_MODEL
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
)
|
||||
]
|
||||
|
@ -6,23 +6,18 @@ from django.db import migrations, models
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('core', '0012_notification'),
|
||||
]
|
||||
dependencies = [("core", "0012_notification")]
|
||||
|
||||
operations = [
|
||||
migrations.RemoveField(
|
||||
model_name='notification',
|
||||
name='text',
|
||||
migrations.RemoveField(model_name="notification", name="text"),
|
||||
migrations.AddField(
|
||||
model_name="notification",
|
||||
name="param",
|
||||
field=models.CharField(verbose_name="param", default="", max_length=128),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='notification',
|
||||
name='param',
|
||||
field=models.CharField(verbose_name='param', default='', max_length=128),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='notification',
|
||||
name='viewed',
|
||||
field=models.BooleanField(verbose_name='viewed', default=False),
|
||||
model_name="notification",
|
||||
name="viewed",
|
||||
field=models.BooleanField(verbose_name="viewed", default=False),
|
||||
),
|
||||
]
|
||||
|
@ -6,14 +6,24 @@ from django.db import migrations, models
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('core', '0013_auto_20161209_2338'),
|
||||
]
|
||||
dependencies = [("core", "0013_auto_20161209_2338")]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='notification',
|
||||
name='type',
|
||||
field=models.CharField(verbose_name='type', max_length=32, default='GENERIC', choices=[('FILE_MODERATION', 'New files to be moderated'), ('SAS_MODERATION', 'New pictures/album to be moderated in the SAS'), ('NEW_PICTURES', "You've been identified on some pictures"), ('REFILLING', 'You just refilled of %s €'), ('SELLING', 'You just bought %s'), ('GENERIC', 'You have a notification')]),
|
||||
),
|
||||
model_name="notification",
|
||||
name="type",
|
||||
field=models.CharField(
|
||||
verbose_name="type",
|
||||
max_length=32,
|
||||
default="GENERIC",
|
||||
choices=[
|
||||
("FILE_MODERATION", "New files to be moderated"),
|
||||
("SAS_MODERATION", "New pictures/album to be moderated in the SAS"),
|
||||
("NEW_PICTURES", "You've been identified on some pictures"),
|
||||
("REFILLING", "You just refilled of %s €"),
|
||||
("SELLING", "You just bought %s"),
|
||||
("GENERIC", "You have a notification"),
|
||||
],
|
||||
),
|
||||
)
|
||||
]
|
||||
|
@ -7,15 +7,18 @@ from django.conf import settings
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('core', '0014_auto_20161210_0009'),
|
||||
]
|
||||
dependencies = [("core", "0014_auto_20161210_0009")]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='sithfile',
|
||||
name='moderator',
|
||||
field=models.ForeignKey(related_name='moderated_files', verbose_name='owner', default=0, to=settings.AUTH_USER_MODEL),
|
||||
model_name="sithfile",
|
||||
name="moderator",
|
||||
field=models.ForeignKey(
|
||||
related_name="moderated_files",
|
||||
verbose_name="owner",
|
||||
default=0,
|
||||
to=settings.AUTH_USER_MODEL,
|
||||
),
|
||||
preserve_default=False,
|
||||
),
|
||||
)
|
||||
]
|
||||
|
@ -7,14 +7,18 @@ from django.conf import settings
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('core', '0015_sithfile_moderator'),
|
||||
]
|
||||
dependencies = [("core", "0015_sithfile_moderator")]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='sithfile',
|
||||
name='moderator',
|
||||
field=models.ForeignKey(related_name='moderated_files', blank=True, null=True, to=settings.AUTH_USER_MODEL, verbose_name='owner'),
|
||||
),
|
||||
model_name="sithfile",
|
||||
name="moderator",
|
||||
field=models.ForeignKey(
|
||||
related_name="moderated_files",
|
||||
blank=True,
|
||||
null=True,
|
||||
to=settings.AUTH_USER_MODEL,
|
||||
verbose_name="owner",
|
||||
),
|
||||
)
|
||||
]
|
||||
|
@ -6,14 +6,12 @@ from django.db import migrations, models
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('core', '0016_auto_20161212_1922'),
|
||||
]
|
||||
dependencies = [("core", "0016_auto_20161212_1922")]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='user',
|
||||
name='last_update',
|
||||
field=models.DateTimeField(verbose_name='last update', auto_now=True),
|
||||
),
|
||||
model_name="user",
|
||||
name="last_update",
|
||||
field=models.DateTimeField(verbose_name="last update", auto_now=True),
|
||||
)
|
||||
]
|
||||
|
@ -6,14 +6,25 @@ from django.db import migrations, models
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('core', '0017_auto_20161220_1626'),
|
||||
]
|
||||
dependencies = [("core", "0017_auto_20161220_1626")]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='notification',
|
||||
name='type',
|
||||
field=models.CharField(choices=[('NEWS_MODERATION', 'A fresh new to be moderated'), ('FILE_MODERATION', 'New files to be moderated'), ('SAS_MODERATION', 'New pictures/album to be moderated in the SAS'), ('NEW_PICTURES', "You've been identified on some pictures"), ('REFILLING', 'You just refilled of %s €'), ('SELLING', 'You just bought %s'), ('GENERIC', 'You have a notification')], default='GENERIC', max_length=32, verbose_name='type'),
|
||||
),
|
||||
model_name="notification",
|
||||
name="type",
|
||||
field=models.CharField(
|
||||
choices=[
|
||||
("NEWS_MODERATION", "A fresh new to be moderated"),
|
||||
("FILE_MODERATION", "New files to be moderated"),
|
||||
("SAS_MODERATION", "New pictures/album to be moderated in the SAS"),
|
||||
("NEW_PICTURES", "You've been identified on some pictures"),
|
||||
("REFILLING", "You just refilled of %s €"),
|
||||
("SELLING", "You just bought %s"),
|
||||
("GENERIC", "You have a notification"),
|
||||
],
|
||||
default="GENERIC",
|
||||
max_length=32,
|
||||
verbose_name="type",
|
||||
),
|
||||
)
|
||||
]
|
||||
|
@ -6,14 +6,14 @@ from django.db import migrations, models
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('core', '0018_auto_20161224_0211'),
|
||||
]
|
||||
dependencies = [("core", "0018_auto_20161224_0211")]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='preferences',
|
||||
name='receive_weekmail',
|
||||
field=models.BooleanField(default=False, verbose_name='do you want to receive the weekmail'),
|
||||
),
|
||||
model_name="preferences",
|
||||
name="receive_weekmail",
|
||||
field=models.BooleanField(
|
||||
default=False, verbose_name="do you want to receive the weekmail"
|
||||
),
|
||||
)
|
||||
]
|
||||
|
@ -7,18 +7,22 @@ import django.core.validators
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('core', '0019_preferences_receive_weekmail'),
|
||||
]
|
||||
dependencies = [("core", "0019_preferences_receive_weekmail")]
|
||||
|
||||
operations = [
|
||||
migrations.AlterModelOptions(
|
||||
name='group',
|
||||
options={'ordering': ['name']},
|
||||
),
|
||||
migrations.AlterModelOptions(name="group", options={"ordering": ["name"]}),
|
||||
migrations.AlterField(
|
||||
model_name='page',
|
||||
name='name',
|
||||
field=models.CharField(validators=[django.core.validators.RegexValidator('^[A-z.+-]+$', 'Enter a valid page name. This value may contain only unaccented letters, numbers and ./+/-/_ characters.')], max_length=30, verbose_name='page unix name'),
|
||||
model_name="page",
|
||||
name="name",
|
||||
field=models.CharField(
|
||||
validators=[
|
||||
django.core.validators.RegexValidator(
|
||||
"^[A-z.+-]+$",
|
||||
"Enter a valid page name. This value may contain only unaccented letters, numbers and ./+/-/_ characters.",
|
||||
)
|
||||
],
|
||||
max_length=30,
|
||||
verbose_name="page unix name",
|
||||
),
|
||||
),
|
||||
]
|
||||
|
@ -6,14 +6,26 @@ from django.db import migrations, models
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('core', '0020_auto_20170324_0917'),
|
||||
]
|
||||
dependencies = [("core", "0020_auto_20170324_0917")]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='notification',
|
||||
name='type',
|
||||
field=models.CharField(verbose_name='type', default='GENERIC', max_length=32, choices=[('MAILING_MODERATION', 'A new mailing list neet to be moderated'), ('NEWS_MODERATION', 'A fresh new to be moderated'), ('FILE_MODERATION', 'New files to be moderated'), ('SAS_MODERATION', 'New pictures/album to be moderated in the SAS'), ('NEW_PICTURES', "You've been identified on some pictures"), ('REFILLING', 'You just refilled of %s €'), ('SELLING', 'You just bought %s'), ('GENERIC', 'You have a notification')]),
|
||||
),
|
||||
model_name="notification",
|
||||
name="type",
|
||||
field=models.CharField(
|
||||
verbose_name="type",
|
||||
default="GENERIC",
|
||||
max_length=32,
|
||||
choices=[
|
||||
("MAILING_MODERATION", "A new mailing list neet to be moderated"),
|
||||
("NEWS_MODERATION", "A fresh new to be moderated"),
|
||||
("FILE_MODERATION", "New files to be moderated"),
|
||||
("SAS_MODERATION", "New pictures/album to be moderated in the SAS"),
|
||||
("NEW_PICTURES", "You've been identified on some pictures"),
|
||||
("REFILLING", "You just refilled of %s €"),
|
||||
("SELLING", "You just bought %s"),
|
||||
("GENERIC", "You have a notification"),
|
||||
],
|
||||
),
|
||||
)
|
||||
]
|
||||
|
@ -6,14 +6,26 @@ from django.db import migrations, models
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('core', '0021_auto_20170822_1529'),
|
||||
]
|
||||
dependencies = [("core", "0021_auto_20170822_1529")]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='notification',
|
||||
name='type',
|
||||
field=models.CharField(choices=[('MAILING_MODERATION', 'A new mailing list needs to be moderated'), ('NEWS_MODERATION', 'A fresh new to be moderated'), ('FILE_MODERATION', 'New files to be moderated'), ('SAS_MODERATION', 'New pictures/album to be moderated in the SAS'), ('NEW_PICTURES', "You've been identified on some pictures"), ('REFILLING', 'You just refilled of %s €'), ('SELLING', 'You just bought %s'), ('GENERIC', 'You have a notification')], default='GENERIC', max_length=32, verbose_name='type'),
|
||||
),
|
||||
model_name="notification",
|
||||
name="type",
|
||||
field=models.CharField(
|
||||
choices=[
|
||||
("MAILING_MODERATION", "A new mailing list needs to be moderated"),
|
||||
("NEWS_MODERATION", "A fresh new to be moderated"),
|
||||
("FILE_MODERATION", "New files to be moderated"),
|
||||
("SAS_MODERATION", "New pictures/album to be moderated in the SAS"),
|
||||
("NEW_PICTURES", "You've been identified on some pictures"),
|
||||
("REFILLING", "You just refilled of %s €"),
|
||||
("SELLING", "You just bought %s"),
|
||||
("GENERIC", "You have a notification"),
|
||||
],
|
||||
default="GENERIC",
|
||||
max_length=32,
|
||||
verbose_name="type",
|
||||
),
|
||||
)
|
||||
]
|
||||
|
@ -7,29 +7,35 @@ from django.conf import settings
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('core', '0022_auto_20170822_2232'),
|
||||
]
|
||||
dependencies = [("core", "0022_auto_20170822_2232")]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='preferences',
|
||||
name='notify_on_click',
|
||||
field=models.BooleanField(verbose_name='get a notification for every click', default=False),
|
||||
model_name="preferences",
|
||||
name="notify_on_click",
|
||||
field=models.BooleanField(
|
||||
verbose_name="get a notification for every click", default=False
|
||||
),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='preferences',
|
||||
name='notify_on_refill',
|
||||
field=models.BooleanField(verbose_name='get a notification for every refilling', default=False),
|
||||
model_name="preferences",
|
||||
name="notify_on_refill",
|
||||
field=models.BooleanField(
|
||||
verbose_name="get a notification for every refilling", default=False
|
||||
),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='preferences',
|
||||
name='show_my_stats',
|
||||
field=models.BooleanField(verbose_name='show your stats to others', default=False),
|
||||
model_name="preferences",
|
||||
name="show_my_stats",
|
||||
field=models.BooleanField(
|
||||
verbose_name="show your stats to others", default=False
|
||||
),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='preferences',
|
||||
name='user',
|
||||
field=models.OneToOneField(related_name='_preferences', to=settings.AUTH_USER_MODEL),
|
||||
model_name="preferences",
|
||||
name="user",
|
||||
field=models.OneToOneField(
|
||||
related_name="_preferences", to=settings.AUTH_USER_MODEL
|
||||
),
|
||||
),
|
||||
]
|
||||
|
@ -6,14 +6,26 @@ from django.db import migrations, models
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('core', '0023_auto_20170902_1226'),
|
||||
]
|
||||
dependencies = [("core", "0023_auto_20170902_1226")]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='notification',
|
||||
name='type',
|
||||
field=models.CharField(choices=[('MAILING_MODERATION', 'A new mailing list needs to be moderated'), ('NEWS_MODERATION', 'There are %s fresh news to be moderated'), ('FILE_MODERATION', 'New files to be moderated'), ('SAS_MODERATION', 'New pictures/album to be moderated in the SAS'), ('NEW_PICTURES', "You've been identified on some pictures"), ('REFILLING', 'You just refilled of %s €'), ('SELLING', 'You just bought %s'), ('GENERIC', 'You have a notification')], verbose_name='type', default='GENERIC', max_length=32),
|
||||
),
|
||||
model_name="notification",
|
||||
name="type",
|
||||
field=models.CharField(
|
||||
choices=[
|
||||
("MAILING_MODERATION", "A new mailing list needs to be moderated"),
|
||||
("NEWS_MODERATION", "There are %s fresh news to be moderated"),
|
||||
("FILE_MODERATION", "New files to be moderated"),
|
||||
("SAS_MODERATION", "New pictures/album to be moderated in the SAS"),
|
||||
("NEW_PICTURES", "You've been identified on some pictures"),
|
||||
("REFILLING", "You just refilled of %s €"),
|
||||
("SELLING", "You just bought %s"),
|
||||
("GENERIC", "You have a notification"),
|
||||
],
|
||||
verbose_name="type",
|
||||
default="GENERIC",
|
||||
max_length=32,
|
||||
),
|
||||
)
|
||||
]
|
||||
|
@ -7,14 +7,21 @@ import django.core.validators
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('core', '0024_auto_20170906_1317'),
|
||||
]
|
||||
dependencies = [("core", "0024_auto_20170906_1317")]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='page',
|
||||
name='name',
|
||||
field=models.CharField(max_length=30, verbose_name='page unix name', validators=[django.core.validators.RegexValidator('^[a-zA-Z0-9][a-zA-Z0-9._-]*[a-zA-Z0-9]$', 'Enter a valid page name. This value may contain only unaccented letters, numbers and ./+/-/_ characters.')]),
|
||||
),
|
||||
model_name="page",
|
||||
name="name",
|
||||
field=models.CharField(
|
||||
max_length=30,
|
||||
verbose_name="page unix name",
|
||||
validators=[
|
||||
django.core.validators.RegexValidator(
|
||||
"^[a-zA-Z0-9][a-zA-Z0-9._-]*[a-zA-Z0-9]$",
|
||||
"Enter a valid page name. This value may contain only unaccented letters, numbers and ./+/-/_ characters.",
|
||||
)
|
||||
],
|
||||
),
|
||||
)
|
||||
]
|
||||
|
@ -6,14 +6,29 @@ from django.db import migrations, models
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('core', '0025_auto_20170919_1521'),
|
||||
]
|
||||
dependencies = [("core", "0025_auto_20170919_1521")]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='notification',
|
||||
name='type',
|
||||
field=models.CharField(choices=[('MAILING_MODERATION', 'A new mailing list needs to be moderated'), ('NEWS_MODERATION', 'There are %s fresh news to be moderated'), ('FILE_MODERATION', 'New files to be moderated'), ('SAS_MODERATION', 'There are %s pictures to be moderated in the SAS'), ('NEW_PICTURES', "You've been identified on some pictures"), ('REFILLING', 'You just refilled of %s €'), ('SELLING', 'You just bought %s'), ('GENERIC', 'You have a notification')], verbose_name='type', max_length=32, default='GENERIC'),
|
||||
),
|
||||
model_name="notification",
|
||||
name="type",
|
||||
field=models.CharField(
|
||||
choices=[
|
||||
("MAILING_MODERATION", "A new mailing list needs to be moderated"),
|
||||
("NEWS_MODERATION", "There are %s fresh news to be moderated"),
|
||||
("FILE_MODERATION", "New files to be moderated"),
|
||||
(
|
||||
"SAS_MODERATION",
|
||||
"There are %s pictures to be moderated in the SAS",
|
||||
),
|
||||
("NEW_PICTURES", "You've been identified on some pictures"),
|
||||
("REFILLING", "You just refilled of %s €"),
|
||||
("SELLING", "You just bought %s"),
|
||||
("GENERIC", "You have a notification"),
|
||||
],
|
||||
verbose_name="type",
|
||||
max_length=32,
|
||||
default="GENERIC",
|
||||
),
|
||||
)
|
||||
]
|
||||
|
@ -8,18 +8,34 @@ import django.utils.timezone
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('core', '0026_auto_20170926_1512'),
|
||||
]
|
||||
dependencies = [("core", "0026_auto_20170926_1512")]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='Gift',
|
||||
name="Gift",
|
||||
fields=[
|
||||
('id', models.AutoField(primary_key=True, auto_created=True, verbose_name='ID', serialize=False)),
|
||||
('label', models.CharField(max_length=255, verbose_name='label')),
|
||||
('date', models.DateTimeField(default=django.utils.timezone.now, verbose_name='date')),
|
||||
('user', models.ForeignKey(related_name='gifts', to=settings.AUTH_USER_MODEL)),
|
||||
(
|
||||
"id",
|
||||
models.AutoField(
|
||||
primary_key=True,
|
||||
auto_created=True,
|
||||
verbose_name="ID",
|
||||
serialize=False,
|
||||
),
|
||||
),
|
||||
("label", models.CharField(max_length=255, verbose_name="label")),
|
||||
(
|
||||
"date",
|
||||
models.DateTimeField(
|
||||
default=django.utils.timezone.now, verbose_name="date"
|
||||
),
|
||||
),
|
||||
(
|
||||
"user",
|
||||
models.ForeignKey(
|
||||
related_name="gifts", to=settings.AUTH_USER_MODEL
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
)
|
||||
]
|
||||
|
@ -6,14 +6,30 @@ from django.db import migrations, models
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('core', '0027_gift'),
|
||||
]
|
||||
dependencies = [("core", "0027_gift")]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='notification',
|
||||
name='type',
|
||||
field=models.CharField(default='GENERIC', verbose_name='type', max_length=32, choices=[('POSTER_MODERATION', 'A new poster needs to be moderated'), ('MAILING_MODERATION', 'A new mailing list needs to be moderated'), ('NEWS_MODERATION', 'There are %s fresh news to be moderated'), ('FILE_MODERATION', 'New files to be moderated'), ('SAS_MODERATION', 'There are %s pictures to be moderated in the SAS'), ('NEW_PICTURES', "You've been identified on some pictures"), ('REFILLING', 'You just refilled of %s €'), ('SELLING', 'You just bought %s'), ('GENERIC', 'You have a notification')]),
|
||||
),
|
||||
model_name="notification",
|
||||
name="type",
|
||||
field=models.CharField(
|
||||
default="GENERIC",
|
||||
verbose_name="type",
|
||||
max_length=32,
|
||||
choices=[
|
||||
("POSTER_MODERATION", "A new poster needs to be moderated"),
|
||||
("MAILING_MODERATION", "A new mailing list needs to be moderated"),
|
||||
("NEWS_MODERATION", "There are %s fresh news to be moderated"),
|
||||
("FILE_MODERATION", "New files to be moderated"),
|
||||
(
|
||||
"SAS_MODERATION",
|
||||
"There are %s pictures to be moderated in the SAS",
|
||||
),
|
||||
("NEW_PICTURES", "You've been identified on some pictures"),
|
||||
("REFILLING", "You just refilled of %s €"),
|
||||
("SELLING", "You just bought %s"),
|
||||
("GENERIC", "You have a notification"),
|
||||
],
|
||||
),
|
||||
)
|
||||
]
|
||||
|
@ -7,14 +7,17 @@ import core.models
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('core', '0028_auto_20171216_2044'),
|
||||
]
|
||||
dependencies = [("core", "0028_auto_20171216_2044")]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='page',
|
||||
name='owner_group',
|
||||
field=models.ForeignKey(verbose_name='owner group', default=core.models.Page.get_default_owner_group, related_name='owned_page', to='core.Group'),
|
||||
),
|
||||
model_name="page",
|
||||
name="owner_group",
|
||||
field=models.ForeignKey(
|
||||
verbose_name="owner group",
|
||||
default=core.models.Page.get_default_owner_group,
|
||||
related_name="owned_page",
|
||||
to="core.Group",
|
||||
),
|
||||
)
|
||||
]
|
||||
|
640
core/models.py
640
core/models.py
File diff suppressed because it is too large
Load Diff
@ -46,5 +46,5 @@ class PsqlRunOnly(migrations.RunSQL):
|
||||
"""
|
||||
|
||||
def _run_sql(self, schema_editor, sqls):
|
||||
if connection.vendor == 'postgresql':
|
||||
if connection.vendor == "postgresql":
|
||||
super(PsqlRunOnly, self)._run_sql(schema_editor, sqls)
|
||||
|
@ -34,21 +34,20 @@ class ScssFinder(FileSystemFinder):
|
||||
"""
|
||||
Find static *.css files compiled on the fly
|
||||
"""
|
||||
|
||||
locations = []
|
||||
|
||||
def __init__(self, apps=None, *args, **kwargs):
|
||||
location = settings.STATIC_ROOT
|
||||
if not os.path.isdir(location):
|
||||
return
|
||||
self.locations = [
|
||||
('', location),
|
||||
]
|
||||
self.locations = [("", location)]
|
||||
self.storages = OrderedDict()
|
||||
filesystem_storage = FileSystemStorage(location=location)
|
||||
filesystem_storage.prefix = self.locations[0][0]
|
||||
self.storages[location] = filesystem_storage
|
||||
|
||||
def find(self, path, all=False):
|
||||
if path.endswith('.css'):
|
||||
if path.endswith(".css"):
|
||||
return super(ScssFinder, self).find(path, all)
|
||||
return []
|
||||
|
@ -39,7 +39,8 @@ class ScssProcessor(object):
|
||||
Else : give the path of the corresponding css supposed to already be compiled
|
||||
Don't forget to use compilestatics to compile scss for production
|
||||
"""
|
||||
prefix = iri_to_uri(getattr(settings, 'STATIC_URL', '/static/'))
|
||||
|
||||
prefix = iri_to_uri(getattr(settings, "STATIC_URL", "/static/"))
|
||||
storage = ScssFileStorage()
|
||||
scss_extensions = [".scss"]
|
||||
|
||||
@ -63,7 +64,7 @@ class ScssProcessor(object):
|
||||
"include_paths": settings.SASS_INCLUDE_FOLDERS,
|
||||
}
|
||||
if settings.SASS_PRECISION:
|
||||
compile_args['precision'] = settings.SASS_PRECISION
|
||||
compile_args["precision"] = settings.SASS_PRECISION
|
||||
content = sass.compile(**compile_args)
|
||||
content = force_bytes(content)
|
||||
|
||||
|
@ -21,4 +21,3 @@
|
||||
# Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
#
|
||||
#
|
||||
|
||||
|
@ -38,11 +38,11 @@ register = template.Library()
|
||||
@register.filter(is_safe=False)
|
||||
@stringfilter
|
||||
def markdown(text):
|
||||
return mark_safe("<div class=\"markdown\">%s</div>" % md(text))
|
||||
return mark_safe('<div class="markdown">%s</div>' % md(text))
|
||||
|
||||
@register.filter(name='phonenumber')
|
||||
def phonenumber(value, country='FR',
|
||||
format=phonenumbers.PhoneNumberFormat.NATIONAL):
|
||||
|
||||
@register.filter(name="phonenumber")
|
||||
def phonenumber(value, country="FR", format=phonenumbers.PhoneNumberFormat.NATIONAL):
|
||||
"""
|
||||
This filter is kindly borrowed from https://github.com/foundertherapy/django-phonenumber-filter
|
||||
"""
|
||||
@ -53,13 +53,37 @@ def phonenumber(value, country='FR',
|
||||
except phonenumbers.NumberParseException as e:
|
||||
return value
|
||||
|
||||
|
||||
@register.filter()
|
||||
@stringfilter
|
||||
def datetime_format_python_to_PHP(python_format_string):
|
||||
"""
|
||||
Given a python datetime format string, attempts to convert it to the nearest PHP datetime format string possible.
|
||||
"""
|
||||
python2PHP = {"%a": "D", "%a": "D", "%A": "l", "%b": "M", "%B": "F", "%c": "", "%d": "d", "%H": "H", "%I": "h", "%j": "z", "%m": "m", "%M": "i", "%p": "A", "%S": "s", "%U": "", "%w": "w", "%W": "W", "%x": "", "%X": "", "%y": "y", "%Y": "Y", "%Z": "e"}
|
||||
python2PHP = {
|
||||
"%a": "D",
|
||||
"%a": "D",
|
||||
"%A": "l",
|
||||
"%b": "M",
|
||||
"%B": "F",
|
||||
"%c": "",
|
||||
"%d": "d",
|
||||
"%H": "H",
|
||||
"%I": "h",
|
||||
"%j": "z",
|
||||
"%m": "m",
|
||||
"%M": "i",
|
||||
"%p": "A",
|
||||
"%S": "s",
|
||||
"%U": "",
|
||||
"%w": "w",
|
||||
"%W": "W",
|
||||
"%x": "",
|
||||
"%X": "",
|
||||
"%y": "y",
|
||||
"%Y": "Y",
|
||||
"%Z": "e",
|
||||
}
|
||||
|
||||
php_format_string = python_format_string
|
||||
for py, php in python2PHP.items():
|
||||
|
398
core/tests.py
398
core/tests.py
@ -49,203 +49,261 @@ class UserRegistrationTest(TestCase):
|
||||
Should register a user correctly
|
||||
"""
|
||||
c = Client()
|
||||
response = c.post(reverse('core:register'), {'first_name': 'Guy',
|
||||
'last_name': 'Carlier',
|
||||
'email': 'guy@git.an',
|
||||
'date_of_birth': '12/6/1942',
|
||||
'password1': 'plop',
|
||||
'password2': 'plop',
|
||||
'captcha_0': 'dummy-value',
|
||||
'captcha_1': 'PASSED'
|
||||
})
|
||||
response = c.post(
|
||||
reverse("core:register"),
|
||||
{
|
||||
"first_name": "Guy",
|
||||
"last_name": "Carlier",
|
||||
"email": "guy@git.an",
|
||||
"date_of_birth": "12/6/1942",
|
||||
"password1": "plop",
|
||||
"password2": "plop",
|
||||
"captcha_0": "dummy-value",
|
||||
"captcha_1": "PASSED",
|
||||
},
|
||||
)
|
||||
self.assertTrue(response.status_code == 200)
|
||||
self.assertTrue('TEST_REGISTER_USER_FORM_OK' in str(response.content))
|
||||
self.assertTrue("TEST_REGISTER_USER_FORM_OK" in str(response.content))
|
||||
|
||||
def test_register_user_form_fail_password(self):
|
||||
"""
|
||||
Should not register a user correctly
|
||||
"""
|
||||
c = Client()
|
||||
response = c.post(reverse('core:register'), {'first_name': 'Guy',
|
||||
'last_name': 'Carlier',
|
||||
'email': 'bibou@git.an',
|
||||
'date_of_birth': '12/6/1942',
|
||||
'password1': 'plop',
|
||||
'password2': 'plop2',
|
||||
'captcha_0': 'dummy-value',
|
||||
'captcha_1': 'PASSED'
|
||||
})
|
||||
response = c.post(
|
||||
reverse("core:register"),
|
||||
{
|
||||
"first_name": "Guy",
|
||||
"last_name": "Carlier",
|
||||
"email": "bibou@git.an",
|
||||
"date_of_birth": "12/6/1942",
|
||||
"password1": "plop",
|
||||
"password2": "plop2",
|
||||
"captcha_0": "dummy-value",
|
||||
"captcha_1": "PASSED",
|
||||
},
|
||||
)
|
||||
self.assertTrue(response.status_code == 200)
|
||||
self.assertTrue('TEST_REGISTER_USER_FORM_FAIL' in str(response.content))
|
||||
self.assertTrue("TEST_REGISTER_USER_FORM_FAIL" in str(response.content))
|
||||
|
||||
def test_register_user_form_fail_email(self):
|
||||
"""
|
||||
Should not register a user correctly
|
||||
"""
|
||||
c = Client()
|
||||
response = c.post(reverse('core:register'), {'first_name': 'Guy',
|
||||
'last_name': 'Carlier',
|
||||
'email': 'bibou.git.an',
|
||||
'date_of_birth': '12/6/1942',
|
||||
'password1': 'plop',
|
||||
'password2': 'plop',
|
||||
'captcha_0': 'dummy-value',
|
||||
'captcha_1': 'PASSED'
|
||||
})
|
||||
response = c.post(
|
||||
reverse("core:register"),
|
||||
{
|
||||
"first_name": "Guy",
|
||||
"last_name": "Carlier",
|
||||
"email": "bibou.git.an",
|
||||
"date_of_birth": "12/6/1942",
|
||||
"password1": "plop",
|
||||
"password2": "plop",
|
||||
"captcha_0": "dummy-value",
|
||||
"captcha_1": "PASSED",
|
||||
},
|
||||
)
|
||||
self.assertTrue(response.status_code == 200)
|
||||
self.assertTrue('TEST_REGISTER_USER_FORM_FAIL' in str(response.content))
|
||||
self.assertTrue("TEST_REGISTER_USER_FORM_FAIL" in str(response.content))
|
||||
|
||||
def test_register_user_form_fail_missing_name(self):
|
||||
"""
|
||||
Should not register a user correctly
|
||||
"""
|
||||
c = Client()
|
||||
response = c.post(reverse('core:register'), {'first_name': 'Guy',
|
||||
'last_name': '',
|
||||
'email': 'bibou@git.an',
|
||||
'date_of_birth': '12/6/1942',
|
||||
'password1': 'plop',
|
||||
'password2': 'plop',
|
||||
'captcha_0': 'dummy-value',
|
||||
'captcha_1': 'PASSED'
|
||||
})
|
||||
response = c.post(
|
||||
reverse("core:register"),
|
||||
{
|
||||
"first_name": "Guy",
|
||||
"last_name": "",
|
||||
"email": "bibou@git.an",
|
||||
"date_of_birth": "12/6/1942",
|
||||
"password1": "plop",
|
||||
"password2": "plop",
|
||||
"captcha_0": "dummy-value",
|
||||
"captcha_1": "PASSED",
|
||||
},
|
||||
)
|
||||
self.assertTrue(response.status_code == 200)
|
||||
self.assertTrue('TEST_REGISTER_USER_FORM_FAIL' in str(response.content))
|
||||
self.assertTrue("TEST_REGISTER_USER_FORM_FAIL" in str(response.content))
|
||||
|
||||
def test_register_user_form_fail_missing_date_of_birth(self):
|
||||
"""
|
||||
Should not register a user correctly
|
||||
"""
|
||||
c = Client()
|
||||
response = c.post(reverse('core:register'), {'first_name': '',
|
||||
'last_name': 'Carlier',
|
||||
'email': 'bibou@git.an',
|
||||
'date_of_birth': '',
|
||||
'password1': 'plop',
|
||||
'password2': 'plop',
|
||||
'captcha_0': 'dummy-value',
|
||||
'captcha_1': 'PASSED'
|
||||
})
|
||||
response = c.post(
|
||||
reverse("core:register"),
|
||||
{
|
||||
"first_name": "",
|
||||
"last_name": "Carlier",
|
||||
"email": "bibou@git.an",
|
||||
"date_of_birth": "",
|
||||
"password1": "plop",
|
||||
"password2": "plop",
|
||||
"captcha_0": "dummy-value",
|
||||
"captcha_1": "PASSED",
|
||||
},
|
||||
)
|
||||
self.assertTrue(response.status_code == 200)
|
||||
self.assertTrue('TEST_REGISTER_USER_FORM_FAIL' in str(response.content))
|
||||
self.assertTrue("TEST_REGISTER_USER_FORM_FAIL" in str(response.content))
|
||||
|
||||
def test_register_user_form_fail_missing_first_name(self):
|
||||
"""
|
||||
Should not register a user correctly
|
||||
"""
|
||||
c = Client()
|
||||
response = c.post(reverse('core:register'), {'first_name': '',
|
||||
'last_name': 'Carlier',
|
||||
'email': 'bibou@git.an',
|
||||
'date_of_birth': '12/6/1942',
|
||||
'password1': 'plop',
|
||||
'password2': 'plop',
|
||||
'captcha_0': 'dummy-value',
|
||||
'captcha_1': 'PASSED'
|
||||
})
|
||||
response = c.post(
|
||||
reverse("core:register"),
|
||||
{
|
||||
"first_name": "",
|
||||
"last_name": "Carlier",
|
||||
"email": "bibou@git.an",
|
||||
"date_of_birth": "12/6/1942",
|
||||
"password1": "plop",
|
||||
"password2": "plop",
|
||||
"captcha_0": "dummy-value",
|
||||
"captcha_1": "PASSED",
|
||||
},
|
||||
)
|
||||
self.assertTrue(response.status_code == 200)
|
||||
self.assertTrue('TEST_REGISTER_USER_FORM_FAIL' in str(response.content))
|
||||
self.assertTrue("TEST_REGISTER_USER_FORM_FAIL" in str(response.content))
|
||||
|
||||
def test_register_user_form_fail_wrong_captcha(self):
|
||||
"""
|
||||
Should not register a user correctly
|
||||
"""
|
||||
c = Client()
|
||||
response = c.post(reverse('core:register'), {'first_name': 'Bibou',
|
||||
'last_name': 'Carlier',
|
||||
'email': 'bibou@git.an',
|
||||
'date_of_birth': '12/6/1942',
|
||||
'password1': 'plop',
|
||||
'password2': 'plop',
|
||||
'captcha_0': 'dummy-value',
|
||||
'captcha_1': 'WRONG_CAPTCHA'
|
||||
})
|
||||
response = c.post(
|
||||
reverse("core:register"),
|
||||
{
|
||||
"first_name": "Bibou",
|
||||
"last_name": "Carlier",
|
||||
"email": "bibou@git.an",
|
||||
"date_of_birth": "12/6/1942",
|
||||
"password1": "plop",
|
||||
"password2": "plop",
|
||||
"captcha_0": "dummy-value",
|
||||
"captcha_1": "WRONG_CAPTCHA",
|
||||
},
|
||||
)
|
||||
self.assertTrue(response.status_code == 200)
|
||||
self.assertTrue('TEST_REGISTER_USER_FORM_FAIL' in str(response.content))
|
||||
self.assertTrue("TEST_REGISTER_USER_FORM_FAIL" in str(response.content))
|
||||
|
||||
def test_register_user_form_fail_already_exists(self):
|
||||
"""
|
||||
Should not register a user correctly
|
||||
"""
|
||||
c = Client()
|
||||
c.post(reverse('core:register'), {'first_name': 'Guy',
|
||||
'last_name': 'Carlier',
|
||||
'email': 'bibou@git.an',
|
||||
'date_of_birth': '12/6/1942',
|
||||
'password1': 'plop',
|
||||
'password2': 'plop',
|
||||
'captcha_0': 'dummy-value',
|
||||
'captcha_1': 'PASSED'
|
||||
})
|
||||
response = c.post(reverse('core:register'), {'first_name': 'Bibou',
|
||||
'last_name': 'Carlier',
|
||||
'email': 'bibou@git.an',
|
||||
'date_of_birth': '12/6/1942',
|
||||
'password1': 'plop',
|
||||
'password2': 'plop',
|
||||
'captcha_0': 'dummy-value',
|
||||
'captcha_1': 'PASSED'
|
||||
})
|
||||
c.post(
|
||||
reverse("core:register"),
|
||||
{
|
||||
"first_name": "Guy",
|
||||
"last_name": "Carlier",
|
||||
"email": "bibou@git.an",
|
||||
"date_of_birth": "12/6/1942",
|
||||
"password1": "plop",
|
||||
"password2": "plop",
|
||||
"captcha_0": "dummy-value",
|
||||
"captcha_1": "PASSED",
|
||||
},
|
||||
)
|
||||
response = c.post(
|
||||
reverse("core:register"),
|
||||
{
|
||||
"first_name": "Bibou",
|
||||
"last_name": "Carlier",
|
||||
"email": "bibou@git.an",
|
||||
"date_of_birth": "12/6/1942",
|
||||
"password1": "plop",
|
||||
"password2": "plop",
|
||||
"captcha_0": "dummy-value",
|
||||
"captcha_1": "PASSED",
|
||||
},
|
||||
)
|
||||
self.assertTrue(response.status_code == 200)
|
||||
self.assertTrue('TEST_REGISTER_USER_FORM_FAIL' in str(response.content))
|
||||
self.assertTrue("TEST_REGISTER_USER_FORM_FAIL" in str(response.content))
|
||||
|
||||
def test_login_success(self):
|
||||
"""
|
||||
Should login a user correctly
|
||||
"""
|
||||
c = Client()
|
||||
c.post(reverse('core:register'), {'first_name': 'Guy',
|
||||
'last_name': 'Carlier',
|
||||
'email': 'bibou@git.an',
|
||||
'date_of_birth': '12/6/1942',
|
||||
'password1': 'plop',
|
||||
'password2': 'plop',
|
||||
'captcha_0': 'dummy-value',
|
||||
'captcha_1': 'PASSED'
|
||||
})
|
||||
response = c.post(reverse('core:login'), {'username': 'gcarlier', 'password': 'plop'})
|
||||
c.post(
|
||||
reverse("core:register"),
|
||||
{
|
||||
"first_name": "Guy",
|
||||
"last_name": "Carlier",
|
||||
"email": "bibou@git.an",
|
||||
"date_of_birth": "12/6/1942",
|
||||
"password1": "plop",
|
||||
"password2": "plop",
|
||||
"captcha_0": "dummy-value",
|
||||
"captcha_1": "PASSED",
|
||||
},
|
||||
)
|
||||
response = c.post(
|
||||
reverse("core:login"), {"username": "gcarlier", "password": "plop"}
|
||||
)
|
||||
self.assertTrue(response.status_code == 302)
|
||||
#self.assertTrue('Hello, world' in str(response.content))
|
||||
# self.assertTrue('Hello, world' in str(response.content))
|
||||
|
||||
def test_login_fail(self):
|
||||
"""
|
||||
Should not login a user correctly
|
||||
"""
|
||||
c = Client()
|
||||
c.post(reverse('core:register'), {'first_name': 'Guy',
|
||||
'last_name': 'Carlier',
|
||||
'email': 'bibou@git.an',
|
||||
'date_of_birth': '12/6/1942',
|
||||
'password1': 'plop',
|
||||
'password2': 'plop',
|
||||
'captcha_0': 'dummy-value',
|
||||
'captcha_1': 'PASSED'
|
||||
})
|
||||
response = c.post(reverse('core:login'), {'username': 'gcarlier', 'password': 'guy'})
|
||||
c.post(
|
||||
reverse("core:register"),
|
||||
{
|
||||
"first_name": "Guy",
|
||||
"last_name": "Carlier",
|
||||
"email": "bibou@git.an",
|
||||
"date_of_birth": "12/6/1942",
|
||||
"password1": "plop",
|
||||
"password2": "plop",
|
||||
"captcha_0": "dummy-value",
|
||||
"captcha_1": "PASSED",
|
||||
},
|
||||
)
|
||||
response = c.post(
|
||||
reverse("core:login"), {"username": "gcarlier", "password": "guy"}
|
||||
)
|
||||
self.assertTrue(response.status_code == 200)
|
||||
self.assertTrue("""<p>Votre nom d\\'utilisateur et votre mot de passe ne correspondent pas. Merci de r\\xc3\\xa9essayer.</p>""" in str(response.content))
|
||||
self.assertTrue(
|
||||
"""<p>Votre nom d\\'utilisateur et votre mot de passe ne correspondent pas. Merci de r\\xc3\\xa9essayer.</p>"""
|
||||
in str(response.content)
|
||||
)
|
||||
|
||||
|
||||
class MarkdownTest(TestCase):
|
||||
def test_full_markdown_syntax(self):
|
||||
root_path = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
||||
with open(os.path.join(root_path) + '/doc/SYNTAX.md', 'r') as md_file:
|
||||
with open(os.path.join(root_path) + "/doc/SYNTAX.md", "r") as md_file:
|
||||
md = md_file.read()
|
||||
with open(os.path.join(root_path) + '/doc/SYNTAX.html', 'r') as html_file:
|
||||
with open(os.path.join(root_path) + "/doc/SYNTAX.html", "r") as html_file:
|
||||
html = html_file.read()
|
||||
result = markdown(md)
|
||||
self.assertTrue(result == html)
|
||||
|
||||
|
||||
class PageHandlingTest(TestCase):
|
||||
def setUp(self):
|
||||
try:
|
||||
Group.objects.create(name="root")
|
||||
u = User(username='root', last_name="", first_name="Bibou",
|
||||
email="ae.info@utbm.fr",
|
||||
date_of_birth="1942-06-12",
|
||||
is_superuser=True, is_staff=True)
|
||||
u = User(
|
||||
username="root",
|
||||
last_name="",
|
||||
first_name="Bibou",
|
||||
email="ae.info@utbm.fr",
|
||||
date_of_birth="1942-06-12",
|
||||
is_superuser=True,
|
||||
is_staff=True,
|
||||
)
|
||||
u.set_password("plop")
|
||||
u.save()
|
||||
self.client.login(username='root', password='plop')
|
||||
self.client.login(username="root", password="plop")
|
||||
except Exception as e:
|
||||
print(e)
|
||||
|
||||
@ -253,12 +311,10 @@ class PageHandlingTest(TestCase):
|
||||
"""
|
||||
Should create a page correctly
|
||||
"""
|
||||
self.client.post(reverse('core:page_new'), {
|
||||
'parent': '',
|
||||
'name': 'guy',
|
||||
'owner_group': 1,
|
||||
})
|
||||
response = self.client.get(reverse('core:page', kwargs={'page_name': 'guy'}))
|
||||
self.client.post(
|
||||
reverse("core:page_new"), {"parent": "", "name": "guy", "owner_group": 1}
|
||||
)
|
||||
response = self.client.get(reverse("core:page", kwargs={"page_name": "guy"}))
|
||||
self.assertTrue(response.status_code == 200)
|
||||
self.assertTrue('<a href="/page/guy/hist">' in str(response.content))
|
||||
|
||||
@ -266,17 +322,16 @@ class PageHandlingTest(TestCase):
|
||||
"""
|
||||
Should create a page correctly
|
||||
"""
|
||||
self.client.post(reverse('core:page_new'), {
|
||||
'parent': '',
|
||||
'name': 'guy',
|
||||
'owner_group': '1',
|
||||
})
|
||||
response = self.client.post(reverse('core:page_new'), {
|
||||
'parent': '1',
|
||||
'name': 'bibou',
|
||||
'owner_group': '1',
|
||||
})
|
||||
response = self.client.get(reverse('core:page', kwargs={'page_name': 'guy/bibou'}))
|
||||
self.client.post(
|
||||
reverse("core:page_new"), {"parent": "", "name": "guy", "owner_group": "1"}
|
||||
)
|
||||
response = self.client.post(
|
||||
reverse("core:page_new"),
|
||||
{"parent": "1", "name": "bibou", "owner_group": "1"},
|
||||
)
|
||||
response = self.client.get(
|
||||
reverse("core:page", kwargs={"page_name": "guy/bibou"})
|
||||
)
|
||||
self.assertTrue(response.status_code == 200)
|
||||
self.assertTrue('<a href="/page/guy/bibou/">' in str(response.content))
|
||||
|
||||
@ -286,17 +341,24 @@ class PageHandlingTest(TestCase):
|
||||
"""
|
||||
parent = Page(name="guy", owner_group=Group.objects.filter(id=1).first())
|
||||
parent.save(force_lock=True)
|
||||
page = Page(name="bibou", owner_group=Group.objects.filter(id=1).first(), parent=parent)
|
||||
page = Page(
|
||||
name="bibou", owner_group=Group.objects.filter(id=1).first(), parent=parent
|
||||
)
|
||||
page.save(force_lock=True)
|
||||
response = self.client.get(reverse('core:page', kwargs={'page_name': 'guy/bibou'}))
|
||||
response = self.client.get(
|
||||
reverse("core:page", kwargs={"page_name": "guy/bibou"})
|
||||
)
|
||||
self.assertTrue(response.status_code == 200)
|
||||
self.assertTrue('<a href="/page/guy/bibou/edit">\\xc3\\x89diter</a>' in str(response.content))
|
||||
self.assertTrue(
|
||||
'<a href="/page/guy/bibou/edit">\\xc3\\x89diter</a>'
|
||||
in str(response.content)
|
||||
)
|
||||
|
||||
def test_access_page_not_found(self):
|
||||
"""
|
||||
Should not display a page correctly
|
||||
"""
|
||||
response = self.client.get(reverse('core:page', kwargs={'page_name': 'swagg'}))
|
||||
response = self.client.get(reverse("core:page", kwargs={"page_name": "swagg"}))
|
||||
response = self.client.get("/page/swagg/")
|
||||
self.assertTrue(response.status_code == 200)
|
||||
self.assertTrue('<a href="/page/create?page=swagg">' in str(response.content))
|
||||
@ -305,15 +367,14 @@ class PageHandlingTest(TestCase):
|
||||
"""
|
||||
Should format the markdown and escape html correctly
|
||||
"""
|
||||
self.client.post(reverse('core:page_new'), {
|
||||
'parent': '',
|
||||
'name': 'guy',
|
||||
'owner_group': '1',
|
||||
})
|
||||
self.client.post(reverse('core:page_edit', kwargs={'page_name': 'guy'}), {
|
||||
'title': 'Bibou',
|
||||
'content':
|
||||
'''Guy *bibou*
|
||||
self.client.post(
|
||||
reverse("core:page_new"), {"parent": "", "name": "guy", "owner_group": "1"}
|
||||
)
|
||||
self.client.post(
|
||||
reverse("core:page_edit", kwargs={"page_name": "guy"}),
|
||||
{
|
||||
"title": "Bibou",
|
||||
"content": """Guy *bibou*
|
||||
|
||||
http://git.an
|
||||
|
||||
@ -322,13 +383,18 @@ http://git.an
|
||||
<guy>Bibou</guy>
|
||||
|
||||
<script>alert('Guy');</script>
|
||||
''',
|
||||
})
|
||||
response = self.client.get(reverse('core:page', kwargs={'page_name': 'guy'}))
|
||||
""",
|
||||
},
|
||||
)
|
||||
response = self.client.get(reverse("core:page", kwargs={"page_name": "guy"}))
|
||||
self.assertTrue(response.status_code == 200)
|
||||
self.assertTrue('<p>Guy <em>bibou</em></p>\\n<p><a href="http://git.an">http://git.an</a></p>\\n' +
|
||||
'<h1>Swag</h1>\\n<guy>Bibou</guy>' +
|
||||
"<script>alert(\\'Guy\\');</script>" in str(response.content))
|
||||
self.assertTrue(
|
||||
'<p>Guy <em>bibou</em></p>\\n<p><a href="http://git.an">http://git.an</a></p>\\n'
|
||||
+ "<h1>Swag</h1>\\n<guy>Bibou</guy>"
|
||||
+ "<script>alert(\\'Guy\\');</script>"
|
||||
in str(response.content)
|
||||
)
|
||||
|
||||
|
||||
# TODO: many tests on the pages:
|
||||
# - renaming a page
|
||||
@ -341,23 +407,33 @@ class FileHandlingTest(TestCase):
|
||||
try:
|
||||
call_command("populate")
|
||||
self.subscriber = User.objects.filter(username="subscriber").first()
|
||||
self.client.login(username='subscriber', password='plop')
|
||||
self.client.login(username="subscriber", password="plop")
|
||||
except Exception as e:
|
||||
print(e)
|
||||
|
||||
def test_create_folder_home(self):
|
||||
response = self.client.post(reverse("core:file_detail", kwargs={"file_id": self.subscriber.home.id}),
|
||||
{"folder_name": "GUY_folder_test"})
|
||||
response = self.client.post(
|
||||
reverse("core:file_detail", kwargs={"file_id": self.subscriber.home.id}),
|
||||
{"folder_name": "GUY_folder_test"},
|
||||
)
|
||||
self.assertTrue(response.status_code == 302)
|
||||
response = self.client.get(reverse("core:file_detail", kwargs={"file_id": self.subscriber.home.id}))
|
||||
response = self.client.get(
|
||||
reverse("core:file_detail", kwargs={"file_id": self.subscriber.home.id})
|
||||
)
|
||||
self.assertTrue(response.status_code == 200)
|
||||
self.assertTrue("GUY_folder_test</a>" in str(response.content))
|
||||
|
||||
def test_upload_file_home(self):
|
||||
with open("/bin/ls", "rb") as f:
|
||||
response = self.client.post(reverse("core:file_detail", kwargs={"file_id": self.subscriber.home.id}),
|
||||
{"file_field": f})
|
||||
response = self.client.post(
|
||||
reverse(
|
||||
"core:file_detail", kwargs={"file_id": self.subscriber.home.id}
|
||||
),
|
||||
{"file_field": f},
|
||||
)
|
||||
self.assertTrue(response.status_code == 302)
|
||||
response = self.client.get(reverse("core:file_detail", kwargs={"file_id": self.subscriber.home.id}))
|
||||
response = self.client.get(
|
||||
reverse("core:file_detail", kwargs={"file_id": self.subscriber.home.id})
|
||||
)
|
||||
self.assertTrue(response.status_code == 200)
|
||||
self.assertTrue("ls</a>" in str(response.content))
|
||||
|
232
core/urls.py
232
core/urls.py
@ -28,73 +28,181 @@ from django.conf.urls import url
|
||||
from core.views import *
|
||||
|
||||
urlpatterns = [
|
||||
url(r'^$', index, name='index'),
|
||||
url(r'^to_markdown$', ToMarkdownView.as_view(), name='to_markdown'),
|
||||
url(r'^notifications$', NotificationList.as_view(), name='notification_list'),
|
||||
url(r'^notification/(?P<notif_id>[0-9]+)$', notification, name='notification'),
|
||||
|
||||
url(r"^$", index, name="index"),
|
||||
url(r"^to_markdown$", ToMarkdownView.as_view(), name="to_markdown"),
|
||||
url(r"^notifications$", NotificationList.as_view(), name="notification_list"),
|
||||
url(r"^notification/(?P<notif_id>[0-9]+)$", notification, name="notification"),
|
||||
# Search
|
||||
url(r'^search/$', search_view, name='search'),
|
||||
url(r'^search_json/$', search_json, name='search_json'),
|
||||
url(r'^search_user/$', search_user_json, name='search_user'),
|
||||
|
||||
url(r"^search/$", search_view, name="search"),
|
||||
url(r"^search_json/$", search_json, name="search_json"),
|
||||
url(r"^search_user/$", search_user_json, name="search_user"),
|
||||
# Login and co
|
||||
url(r'^login/$', login, name='login'),
|
||||
url(r'^logout/$', logout, name='logout'),
|
||||
url(r'^password_change/$', password_change, name='password_change'),
|
||||
url(r'^password_change/(?P<user_id>[0-9]+)$', password_root_change, name='password_root_change'),
|
||||
url(r'^password_change/done$', password_change_done, name='password_change_done'),
|
||||
url(r'^password_reset/$', password_reset, name='password_reset'),
|
||||
url(r'^password_reset/done$', password_reset_done, name='password_reset_done'),
|
||||
url(r'^reset/(?P<uidb64>[0-9A-Za-z_\-]+)/(?P<token>[0-9A-Za-z]{1,13}-[0-9A-Za-z]{1,20})/$', password_reset_confirm, name='password_reset_confirm'),
|
||||
url(r'^reset/done/$', password_reset_complete, name='password_reset_complete'),
|
||||
url(r'^register$', register, name='register'),
|
||||
|
||||
url(r"^login/$", login, name="login"),
|
||||
url(r"^logout/$", logout, name="logout"),
|
||||
url(r"^password_change/$", password_change, name="password_change"),
|
||||
url(
|
||||
r"^password_change/(?P<user_id>[0-9]+)$",
|
||||
password_root_change,
|
||||
name="password_root_change",
|
||||
),
|
||||
url(r"^password_change/done$", password_change_done, name="password_change_done"),
|
||||
url(r"^password_reset/$", password_reset, name="password_reset"),
|
||||
url(r"^password_reset/done$", password_reset_done, name="password_reset_done"),
|
||||
url(
|
||||
r"^reset/(?P<uidb64>[0-9A-Za-z_\-]+)/(?P<token>[0-9A-Za-z]{1,13}-[0-9A-Za-z]{1,20})/$",
|
||||
password_reset_confirm,
|
||||
name="password_reset_confirm",
|
||||
),
|
||||
url(r"^reset/done/$", password_reset_complete, name="password_reset_complete"),
|
||||
url(r"^register$", register, name="register"),
|
||||
# Group handling
|
||||
url(r'^group/$', GroupListView.as_view(), name='group_list'),
|
||||
url(r'^group/new$', GroupCreateView.as_view(), name='group_new'),
|
||||
url(r'^group/(?P<group_id>[0-9]+)/$', GroupEditView.as_view(), name='group_edit'),
|
||||
url(r'^group/(?P<group_id>[0-9]+)/delete$', GroupDeleteView.as_view(), name='group_delete'),
|
||||
|
||||
url(r"^group/$", GroupListView.as_view(), name="group_list"),
|
||||
url(r"^group/new$", GroupCreateView.as_view(), name="group_new"),
|
||||
url(r"^group/(?P<group_id>[0-9]+)/$", GroupEditView.as_view(), name="group_edit"),
|
||||
url(
|
||||
r"^group/(?P<group_id>[0-9]+)/delete$",
|
||||
GroupDeleteView.as_view(),
|
||||
name="group_delete",
|
||||
),
|
||||
# User views
|
||||
url(r'^user/$', UserListView.as_view(), name='user_list'),
|
||||
url(r'^user/(?P<user_id>[0-9]+)/mini$', UserMiniView.as_view(), name='user_profile_mini'),
|
||||
url(r'^user/(?P<user_id>[0-9]+)/$', UserView.as_view(), name='user_profile'),
|
||||
url(r'^user/(?P<user_id>[0-9]+)/pictures$', UserPicturesView.as_view(), name='user_pictures'),
|
||||
url(r'^user/(?P<user_id>[0-9]+)/godfathers$', UserGodfathersView.as_view(), name='user_godfathers'),
|
||||
url(r'^user/(?P<user_id>[0-9]+)/godfathers/tree$', UserGodfathersTreeView.as_view(), name='user_godfathers_tree'),
|
||||
url(r'^user/(?P<user_id>[0-9]+)/godfathers/tree/pict$', UserGodfathersTreePictureView.as_view(), name='user_godfathers_tree_pict'),
|
||||
url(r'^user/(?P<user_id>[0-9]+)/godfathers/(?P<godfather_id>[0-9]+)/(?P<is_father>(True)|(False))/delete$', DeleteUserGodfathers, name='user_godfathers_delete'),
|
||||
url(r'^user/(?P<user_id>[0-9]+)/edit$', UserUpdateProfileView.as_view(), name='user_edit'),
|
||||
url(r'^user/(?P<user_id>[0-9]+)/profile_upload$', UserUploadProfilePictView.as_view(), name='user_profile_upload'),
|
||||
url(r'^user/(?P<user_id>[0-9]+)/clubs$', UserClubView.as_view(), name='user_clubs'),
|
||||
url(r'^user/(?P<user_id>[0-9]+)/prefs$', UserPreferencesView.as_view(), name='user_prefs'),
|
||||
url(r'^user/(?P<user_id>[0-9]+)/groups$', UserUpdateGroupView.as_view(), name='user_groups'),
|
||||
url(r'^user/tools/$', UserToolsView.as_view(), name='user_tools'),
|
||||
url(r'^user/(?P<user_id>[0-9]+)/account$', UserAccountView.as_view(), name='user_account'),
|
||||
url(r'^user/(?P<user_id>[0-9]+)/account/(?P<year>[0-9]+)/(?P<month>[0-9]+)$', UserAccountDetailView.as_view(), name='user_account_detail'),
|
||||
url(r'^user/(?P<user_id>[0-9]+)/stats$', UserStatsView.as_view(), name='user_stats'),
|
||||
url(r'^user/(?P<user_id>[0-9]+)/gift/create$', GiftCreateView.as_view(), name='user_gift_create'),
|
||||
url(r'^user/(?P<user_id>[0-9]+)/gift/delete/(?P<gift_id>[0-9]+)/$', GiftDeleteView.as_view(), name='user_gift_delete'),
|
||||
|
||||
url(r"^user/$", UserListView.as_view(), name="user_list"),
|
||||
url(
|
||||
r"^user/(?P<user_id>[0-9]+)/mini$",
|
||||
UserMiniView.as_view(),
|
||||
name="user_profile_mini",
|
||||
),
|
||||
url(r"^user/(?P<user_id>[0-9]+)/$", UserView.as_view(), name="user_profile"),
|
||||
url(
|
||||
r"^user/(?P<user_id>[0-9]+)/pictures$",
|
||||
UserPicturesView.as_view(),
|
||||
name="user_pictures",
|
||||
),
|
||||
url(
|
||||
r"^user/(?P<user_id>[0-9]+)/godfathers$",
|
||||
UserGodfathersView.as_view(),
|
||||
name="user_godfathers",
|
||||
),
|
||||
url(
|
||||
r"^user/(?P<user_id>[0-9]+)/godfathers/tree$",
|
||||
UserGodfathersTreeView.as_view(),
|
||||
name="user_godfathers_tree",
|
||||
),
|
||||
url(
|
||||
r"^user/(?P<user_id>[0-9]+)/godfathers/tree/pict$",
|
||||
UserGodfathersTreePictureView.as_view(),
|
||||
name="user_godfathers_tree_pict",
|
||||
),
|
||||
url(
|
||||
r"^user/(?P<user_id>[0-9]+)/godfathers/(?P<godfather_id>[0-9]+)/(?P<is_father>(True)|(False))/delete$",
|
||||
DeleteUserGodfathers,
|
||||
name="user_godfathers_delete",
|
||||
),
|
||||
url(
|
||||
r"^user/(?P<user_id>[0-9]+)/edit$",
|
||||
UserUpdateProfileView.as_view(),
|
||||
name="user_edit",
|
||||
),
|
||||
url(
|
||||
r"^user/(?P<user_id>[0-9]+)/profile_upload$",
|
||||
UserUploadProfilePictView.as_view(),
|
||||
name="user_profile_upload",
|
||||
),
|
||||
url(r"^user/(?P<user_id>[0-9]+)/clubs$", UserClubView.as_view(), name="user_clubs"),
|
||||
url(
|
||||
r"^user/(?P<user_id>[0-9]+)/prefs$",
|
||||
UserPreferencesView.as_view(),
|
||||
name="user_prefs",
|
||||
),
|
||||
url(
|
||||
r"^user/(?P<user_id>[0-9]+)/groups$",
|
||||
UserUpdateGroupView.as_view(),
|
||||
name="user_groups",
|
||||
),
|
||||
url(r"^user/tools/$", UserToolsView.as_view(), name="user_tools"),
|
||||
url(
|
||||
r"^user/(?P<user_id>[0-9]+)/account$",
|
||||
UserAccountView.as_view(),
|
||||
name="user_account",
|
||||
),
|
||||
url(
|
||||
r"^user/(?P<user_id>[0-9]+)/account/(?P<year>[0-9]+)/(?P<month>[0-9]+)$",
|
||||
UserAccountDetailView.as_view(),
|
||||
name="user_account_detail",
|
||||
),
|
||||
url(
|
||||
r"^user/(?P<user_id>[0-9]+)/stats$", UserStatsView.as_view(), name="user_stats"
|
||||
),
|
||||
url(
|
||||
r"^user/(?P<user_id>[0-9]+)/gift/create$",
|
||||
GiftCreateView.as_view(),
|
||||
name="user_gift_create",
|
||||
),
|
||||
url(
|
||||
r"^user/(?P<user_id>[0-9]+)/gift/delete/(?P<gift_id>[0-9]+)/$",
|
||||
GiftDeleteView.as_view(),
|
||||
name="user_gift_delete",
|
||||
),
|
||||
# File views
|
||||
# url(r'^file/add/(?P<popup>popup)?$', FileCreateView.as_view(), name='file_new'),
|
||||
url(r'^file/(?P<popup>popup)?$', FileListView.as_view(), name='file_list'),
|
||||
url(r'^file/(?P<file_id>[0-9]+)/(?P<popup>popup)?$', FileView.as_view(), name='file_detail'),
|
||||
url(r'^file/(?P<file_id>[0-9]+)/edit/(?P<popup>popup)?$', FileEditView.as_view(), name='file_edit'),
|
||||
url(r'^file/(?P<file_id>[0-9]+)/prop/(?P<popup>popup)?$', FileEditPropView.as_view(), name='file_prop'),
|
||||
url(r'^file/(?P<file_id>[0-9]+)/delete/(?P<popup>popup)?$', FileDeleteView.as_view(), name='file_delete'),
|
||||
url(r'^file/moderation$', FileModerationView.as_view(), name='file_moderation'),
|
||||
url(r'^file/(?P<file_id>[0-9]+)/moderate$', FileModerateView.as_view(), name='file_moderate'),
|
||||
url(r'^file/(?P<file_id>[0-9]+)/download$', send_file, name='download'),
|
||||
|
||||
url(r"^file/(?P<popup>popup)?$", FileListView.as_view(), name="file_list"),
|
||||
url(
|
||||
r"^file/(?P<file_id>[0-9]+)/(?P<popup>popup)?$",
|
||||
FileView.as_view(),
|
||||
name="file_detail",
|
||||
),
|
||||
url(
|
||||
r"^file/(?P<file_id>[0-9]+)/edit/(?P<popup>popup)?$",
|
||||
FileEditView.as_view(),
|
||||
name="file_edit",
|
||||
),
|
||||
url(
|
||||
r"^file/(?P<file_id>[0-9]+)/prop/(?P<popup>popup)?$",
|
||||
FileEditPropView.as_view(),
|
||||
name="file_prop",
|
||||
),
|
||||
url(
|
||||
r"^file/(?P<file_id>[0-9]+)/delete/(?P<popup>popup)?$",
|
||||
FileDeleteView.as_view(),
|
||||
name="file_delete",
|
||||
),
|
||||
url(r"^file/moderation$", FileModerationView.as_view(), name="file_moderation"),
|
||||
url(
|
||||
r"^file/(?P<file_id>[0-9]+)/moderate$",
|
||||
FileModerateView.as_view(),
|
||||
name="file_moderate",
|
||||
),
|
||||
url(r"^file/(?P<file_id>[0-9]+)/download$", send_file, name="download"),
|
||||
# Page views
|
||||
url(r'^page/$', PageListView.as_view(), name='page_list'),
|
||||
url(r'^page/create$', PageCreateView.as_view(), name='page_new'),
|
||||
url(r'^page/(?P<page_id>[0-9]*)/delete$', PageDeleteView.as_view(), name='page_delete'),
|
||||
url(r'^page/(?P<page_name>([/a-zA-Z0-9][a-zA-Z0-9._-]*[a-zA-Z0-9])+)/edit$', PageEditView.as_view(), name='page_edit'),
|
||||
url(r'^page/(?P<page_name>([/a-zA-Z0-9][a-zA-Z0-9._-]*[a-zA-Z0-9])+)/prop$', PagePropView.as_view(), name='page_prop'),
|
||||
url(r'^page/(?P<page_name>([/a-zA-Z0-9][a-zA-Z0-9._-]*[a-zA-Z0-9])+)/hist$', PageHistView.as_view(), name='page_hist'),
|
||||
url(r'^page/(?P<page_name>([/a-zA-Z0-9][a-zA-Z0-9._-]*[a-zA-Z0-9])+)/rev/(?P<rev>[0-9]+)/', PageRevView.as_view(), name='page_rev'),
|
||||
url(r'^page/(?P<page_name>([/a-zA-Z0-9][a-zA-Z0-9._-]*[a-zA-Z0-9])+)/$', PageView.as_view(), name='page'),
|
||||
url(r"^page/$", PageListView.as_view(), name="page_list"),
|
||||
url(r"^page/create$", PageCreateView.as_view(), name="page_new"),
|
||||
url(
|
||||
r"^page/(?P<page_id>[0-9]*)/delete$",
|
||||
PageDeleteView.as_view(),
|
||||
name="page_delete",
|
||||
),
|
||||
url(
|
||||
r"^page/(?P<page_name>([/a-zA-Z0-9][a-zA-Z0-9._-]*[a-zA-Z0-9])+)/edit$",
|
||||
PageEditView.as_view(),
|
||||
name="page_edit",
|
||||
),
|
||||
url(
|
||||
r"^page/(?P<page_name>([/a-zA-Z0-9][a-zA-Z0-9._-]*[a-zA-Z0-9])+)/prop$",
|
||||
PagePropView.as_view(),
|
||||
name="page_prop",
|
||||
),
|
||||
url(
|
||||
r"^page/(?P<page_name>([/a-zA-Z0-9][a-zA-Z0-9._-]*[a-zA-Z0-9])+)/hist$",
|
||||
PageHistView.as_view(),
|
||||
name="page_hist",
|
||||
),
|
||||
url(
|
||||
r"^page/(?P<page_name>([/a-zA-Z0-9][a-zA-Z0-9._-]*[a-zA-Z0-9])+)/rev/(?P<rev>[0-9]+)/",
|
||||
PageRevView.as_view(),
|
||||
name="page_rev",
|
||||
),
|
||||
url(
|
||||
r"^page/(?P<page_name>([/a-zA-Z0-9][a-zA-Z0-9._-]*[a-zA-Z0-9])+)/$",
|
||||
PageView.as_view(),
|
||||
name="page",
|
||||
),
|
||||
]
|
||||
|
151
core/utils.py
151
core/utils.py
@ -30,6 +30,7 @@ from io import BytesIO
|
||||
from datetime import date
|
||||
|
||||
from PIL import ExifTags
|
||||
|
||||
# from exceptions import IOError
|
||||
import PIL
|
||||
|
||||
@ -71,9 +72,9 @@ def get_semester(d=date.today()):
|
||||
|
||||
def scale_dimension(width, height, long_edge):
|
||||
if width > height:
|
||||
ratio = long_edge * 1. / width
|
||||
ratio = long_edge * 1.0 / width
|
||||
else:
|
||||
ratio = long_edge * 1. / height
|
||||
ratio = long_edge * 1.0 / height
|
||||
return int(width * ratio), int(height * ratio)
|
||||
|
||||
|
||||
@ -83,16 +84,28 @@ def resize_image(im, edge, format):
|
||||
content = BytesIO()
|
||||
im = im.resize((width, height), PIL.Image.ANTIALIAS)
|
||||
try:
|
||||
im.save(fp=content, format=format.upper(), quality=90, optimize=True, progressive=True)
|
||||
im.save(
|
||||
fp=content,
|
||||
format=format.upper(),
|
||||
quality=90,
|
||||
optimize=True,
|
||||
progressive=True,
|
||||
)
|
||||
except IOError:
|
||||
PIL.ImageFile.MAXBLOCK = im.size[0] * im.size[1]
|
||||
im.save(fp=content, format=format.upper(), quality=90, optimize=True, progressive=True)
|
||||
im.save(
|
||||
fp=content,
|
||||
format=format.upper(),
|
||||
quality=90,
|
||||
optimize=True,
|
||||
progressive=True,
|
||||
)
|
||||
return ContentFile(content.getvalue())
|
||||
|
||||
|
||||
def exif_auto_rotate(image):
|
||||
for orientation in ExifTags.TAGS.keys():
|
||||
if ExifTags.TAGS[orientation] == 'Orientation':
|
||||
if ExifTags.TAGS[orientation] == "Orientation":
|
||||
break
|
||||
exif = dict(image._getexif().items())
|
||||
|
||||
@ -108,54 +121,66 @@ def exif_auto_rotate(image):
|
||||
|
||||
def doku_to_markdown(text):
|
||||
"""This is a quite correct doku translator"""
|
||||
text = re.sub(r'([^:]|^)\/\/(.*?)\/\/', r'*\2*', text) # Italic (prevents protocol:// conflict)
|
||||
text = re.sub(r'<del>(.*?)<\/del>', r'~~\1~~', text, flags=re.DOTALL) # Strike (may be multiline)
|
||||
text = re.sub(r'<sup>(.*?)<\/sup>', r'^\1^', text) # Superscript (multiline not supported, because almost never used)
|
||||
text = re.sub(r'<sub>(.*?)<\/sub>', r'_\1_', text) # Subscript (idem)
|
||||
text = re.sub(
|
||||
r"([^:]|^)\/\/(.*?)\/\/", r"*\2*", text
|
||||
) # Italic (prevents protocol:// conflict)
|
||||
text = re.sub(
|
||||
r"<del>(.*?)<\/del>", r"~~\1~~", text, flags=re.DOTALL
|
||||
) # Strike (may be multiline)
|
||||
text = re.sub(
|
||||
r"<sup>(.*?)<\/sup>", r"^\1^", text
|
||||
) # Superscript (multiline not supported, because almost never used)
|
||||
text = re.sub(r"<sub>(.*?)<\/sub>", r"_\1_", text) # Subscript (idem)
|
||||
|
||||
text = re.sub(r'^======(.*?)======', r'#\1', text, flags=re.MULTILINE) # Titles
|
||||
text = re.sub(r'^=====(.*?)=====', r'##\1', text, flags=re.MULTILINE)
|
||||
text = re.sub(r'^====(.*?)====', r'###\1', text, flags=re.MULTILINE)
|
||||
text = re.sub(r'^===(.*?)===', r'####\1', text, flags=re.MULTILINE)
|
||||
text = re.sub(r'^==(.*?)==', r'#####\1', text, flags=re.MULTILINE)
|
||||
text = re.sub(r'^=(.*?)=', r'######\1', text, flags=re.MULTILINE)
|
||||
text = re.sub(r"^======(.*?)======", r"#\1", text, flags=re.MULTILINE) # Titles
|
||||
text = re.sub(r"^=====(.*?)=====", r"##\1", text, flags=re.MULTILINE)
|
||||
text = re.sub(r"^====(.*?)====", r"###\1", text, flags=re.MULTILINE)
|
||||
text = re.sub(r"^===(.*?)===", r"####\1", text, flags=re.MULTILINE)
|
||||
text = re.sub(r"^==(.*?)==", r"#####\1", text, flags=re.MULTILINE)
|
||||
text = re.sub(r"^=(.*?)=", r"######\1", text, flags=re.MULTILINE)
|
||||
|
||||
text = re.sub(r'<nowiki>', r'<nosyntax>', text)
|
||||
text = re.sub(r'</nowiki>', r'</nosyntax>', text)
|
||||
text = re.sub(r'<code>', r'```\n', text)
|
||||
text = re.sub(r'</code>', r'\n```', text)
|
||||
text = re.sub(r'article://', r'page://', text)
|
||||
text = re.sub(r'dfile://', r'file://', text)
|
||||
text = re.sub(r"<nowiki>", r"<nosyntax>", text)
|
||||
text = re.sub(r"</nowiki>", r"</nosyntax>", text)
|
||||
text = re.sub(r"<code>", r"```\n", text)
|
||||
text = re.sub(r"</code>", r"\n```", text)
|
||||
text = re.sub(r"article://", r"page://", text)
|
||||
text = re.sub(r"dfile://", r"file://", text)
|
||||
|
||||
i = 1
|
||||
for fn in re.findall(r'\(\((.*?)\)\)', text): # Footnotes
|
||||
text = re.sub(r'\(\((.*?)\)\)', r'[^%s]' % i, text, count=1)
|
||||
for fn in re.findall(r"\(\((.*?)\)\)", text): # Footnotes
|
||||
text = re.sub(r"\(\((.*?)\)\)", r"[^%s]" % i, text, count=1)
|
||||
text += "\n[^%s]: %s\n" % (i, fn)
|
||||
i += 1
|
||||
|
||||
text = re.sub(r'\\{2,}[\s]', r' \n', text) # Carriage return
|
||||
text = re.sub(r"\\{2,}[\s]", r" \n", text) # Carriage return
|
||||
|
||||
text = re.sub(r'\[\[(.*?)\|(.*?)\]\]', r'[\2](\1)', text) # Links
|
||||
text = re.sub(r'\[\[(.*?)\]\]', r'[\1](\1)', text) # Links 2
|
||||
text = re.sub(r'{{(.*?)\|(.*?)}}', r'', text) # Images
|
||||
text = re.sub(r'{{(.*?)(\|(.*?))?}}', r'', text) # Images 2
|
||||
text = re.sub(r'{\[(.*?)(\|(.*?))?\]}', r'[\1](\1)', text) # Video (transform to classic links, since we can't integrate them)
|
||||
text = re.sub(r"\[\[(.*?)\|(.*?)\]\]", r"[\2](\1)", text) # Links
|
||||
text = re.sub(r"\[\[(.*?)\]\]", r"[\1](\1)", text) # Links 2
|
||||
text = re.sub(r"{{(.*?)\|(.*?)}}", r'', text) # Images
|
||||
text = re.sub(r"{{(.*?)(\|(.*?))?}}", r'', text) # Images 2
|
||||
text = re.sub(
|
||||
r"{\[(.*?)(\|(.*?))?\]}", r"[\1](\1)", text
|
||||
) # Video (transform to classic links, since we can't integrate them)
|
||||
|
||||
text = re.sub(r'###(\d*?)###', r'[[[\1]]]', text) # Progress bar
|
||||
text = re.sub(r"###(\d*?)###", r"[[[\1]]]", text) # Progress bar
|
||||
|
||||
text = re.sub(r'(\n +[^* -][^\n]*(\n +[^* -][^\n]*)*)', r'```\1\n```', text, flags=re.DOTALL) # Block code without lists
|
||||
text = re.sub(
|
||||
r"(\n +[^* -][^\n]*(\n +[^* -][^\n]*)*)", r"```\1\n```", text, flags=re.DOTALL
|
||||
) # Block code without lists
|
||||
|
||||
text = re.sub(r'( +)-(.*)', r'1.\2', text) # Ordered lists
|
||||
text = re.sub(r"( +)-(.*)", r"1.\2", text) # Ordered lists
|
||||
|
||||
new_text = []
|
||||
quote_level = 0
|
||||
for line in text.splitlines(): # Tables and quotes
|
||||
enter = re.finditer(r'\[quote(=(.+?))?\]', line)
|
||||
quit = re.finditer(r'\[/quote\]', line)
|
||||
if re.search(r'\A\s*\^(([^\^]*?)\^)*', line): # Table part
|
||||
line = line.replace('^', '|')
|
||||
enter = re.finditer(r"\[quote(=(.+?))?\]", line)
|
||||
quit = re.finditer(r"\[/quote\]", line)
|
||||
if re.search(r"\A\s*\^(([^\^]*?)\^)*", line): # Table part
|
||||
line = line.replace("^", "|")
|
||||
new_text.append("> " * quote_level + line)
|
||||
new_text.append("> " * quote_level + "|---|") # Don't keep the text alignement in tables it's really too complex for what it's worth
|
||||
new_text.append(
|
||||
"> " * quote_level + "|---|"
|
||||
) # Don't keep the text alignement in tables it's really too complex for what it's worth
|
||||
elif enter or quit: # Quote part
|
||||
for quote in enter: # Enter quotes (support multiple at a time)
|
||||
quote_level += 1
|
||||
@ -163,16 +188,20 @@ def doku_to_markdown(text):
|
||||
new_text.append("> " * quote_level + "##### " + quote.group(2))
|
||||
except:
|
||||
new_text.append("> " * quote_level)
|
||||
line = line.replace(quote.group(0), '')
|
||||
final_quote_level = quote_level # Store quote_level to use at the end, since it will be modified during quit iteration
|
||||
line = line.replace(quote.group(0), "")
|
||||
final_quote_level = (
|
||||
quote_level
|
||||
) # Store quote_level to use at the end, since it will be modified during quit iteration
|
||||
final_newline = False
|
||||
for quote in quit: # Quit quotes (support multiple at a time)
|
||||
line = line.replace(quote.group(0), '')
|
||||
line = line.replace(quote.group(0), "")
|
||||
quote_level -= 1
|
||||
final_newline = True
|
||||
new_text.append("> " * final_quote_level + line) # Finally append the line
|
||||
if final_newline:
|
||||
new_text.append("\n") # Add a new line to ensure the separation between the quote and the following text
|
||||
new_text.append(
|
||||
"\n"
|
||||
) # Add a new line to ensure the separation between the quote and the following text
|
||||
else:
|
||||
new_text.append(line)
|
||||
|
||||
@ -181,24 +210,28 @@ def doku_to_markdown(text):
|
||||
|
||||
def bbcode_to_markdown(text):
|
||||
"""This is a very basic BBcode translator"""
|
||||
text = re.sub(r'\[b\](.*?)\[\/b\]', r'**\1**', text, flags=re.DOTALL) # Bold
|
||||
text = re.sub(r'\[i\](.*?)\[\/i\]', r'*\1*', text, flags=re.DOTALL) # Italic
|
||||
text = re.sub(r'\[u\](.*?)\[\/u\]', r'__\1__', text, flags=re.DOTALL) # Underline
|
||||
text = re.sub(r'\[s\](.*?)\[\/s\]', r'~~\1~~', text, flags=re.DOTALL) # Strike (may be multiline)
|
||||
text = re.sub(r'\[strike\](.*?)\[\/strike\]', r'~~\1~~', text, flags=re.DOTALL) # Strike 2
|
||||
text = re.sub(r"\[b\](.*?)\[\/b\]", r"**\1**", text, flags=re.DOTALL) # Bold
|
||||
text = re.sub(r"\[i\](.*?)\[\/i\]", r"*\1*", text, flags=re.DOTALL) # Italic
|
||||
text = re.sub(r"\[u\](.*?)\[\/u\]", r"__\1__", text, flags=re.DOTALL) # Underline
|
||||
text = re.sub(
|
||||
r"\[s\](.*?)\[\/s\]", r"~~\1~~", text, flags=re.DOTALL
|
||||
) # Strike (may be multiline)
|
||||
text = re.sub(
|
||||
r"\[strike\](.*?)\[\/strike\]", r"~~\1~~", text, flags=re.DOTALL
|
||||
) # Strike 2
|
||||
|
||||
text = re.sub(r'article://', r'page://', text)
|
||||
text = re.sub(r'dfile://', r'file://', text)
|
||||
text = re.sub(r"article://", r"page://", text)
|
||||
text = re.sub(r"dfile://", r"file://", text)
|
||||
|
||||
text = re.sub(r'\[url=(.*?)\](.*)\[\/url\]', r'[\2](\1)', text) # Links
|
||||
text = re.sub(r'\[url\](.*)\[\/url\]', r'\1', text) # Links 2
|
||||
text = re.sub(r'\[img\](.*)\[\/img\]', r'', text) # Images
|
||||
text = re.sub(r"\[url=(.*?)\](.*)\[\/url\]", r"[\2](\1)", text) # Links
|
||||
text = re.sub(r"\[url\](.*)\[\/url\]", r"\1", text) # Links 2
|
||||
text = re.sub(r"\[img\](.*)\[\/img\]", r'', text) # Images
|
||||
|
||||
new_text = []
|
||||
quote_level = 0
|
||||
for line in text.splitlines(): # Tables and quotes
|
||||
enter = re.finditer(r'\[quote(=(.+?))?\]', line)
|
||||
quit = re.finditer(r'\[/quote\]', line)
|
||||
enter = re.finditer(r"\[quote(=(.+?))?\]", line)
|
||||
quit = re.finditer(r"\[/quote\]", line)
|
||||
if enter or quit: # Quote part
|
||||
for quote in enter: # Enter quotes (support multiple at a time)
|
||||
quote_level += 1
|
||||
@ -206,16 +239,20 @@ def bbcode_to_markdown(text):
|
||||
new_text.append("> " * quote_level + "##### " + quote.group(2))
|
||||
except:
|
||||
new_text.append("> " * quote_level)
|
||||
line = line.replace(quote.group(0), '')
|
||||
final_quote_level = quote_level # Store quote_level to use at the end, since it will be modified during quit iteration
|
||||
line = line.replace(quote.group(0), "")
|
||||
final_quote_level = (
|
||||
quote_level
|
||||
) # Store quote_level to use at the end, since it will be modified during quit iteration
|
||||
final_newline = False
|
||||
for quote in quit: # Quit quotes (support multiple at a time)
|
||||
line = line.replace(quote.group(0), '')
|
||||
line = line.replace(quote.group(0), "")
|
||||
quote_level -= 1
|
||||
final_newline = True
|
||||
new_text.append("> " * final_quote_level + line) # Finally append the line
|
||||
if final_newline:
|
||||
new_text.append("\n") # Add a new line to ensure the separation between the quote and the following text
|
||||
new_text.append(
|
||||
"\n"
|
||||
) # Add a new line to ensure the separation between the quote and the following text
|
||||
else:
|
||||
new_text.append(line)
|
||||
|
||||
|
@ -26,43 +26,69 @@ import types
|
||||
|
||||
from django.shortcuts import render
|
||||
from django.http import HttpResponseForbidden, HttpResponseNotFound
|
||||
from django.core.exceptions import PermissionDenied, ObjectDoesNotExist, ImproperlyConfigured
|
||||
from django.core.exceptions import (
|
||||
PermissionDenied,
|
||||
ObjectDoesNotExist,
|
||||
ImproperlyConfigured,
|
||||
)
|
||||
from django.views.generic.base import View
|
||||
from django.db.models import Count
|
||||
|
||||
from core.models import Group
|
||||
from core.views.forms import LoginForm
|
||||
|
||||
|
||||
def forbidden(request):
|
||||
try:
|
||||
return HttpResponseForbidden(render(request, "core/403.jinja", context={'next': request.path, 'form':
|
||||
LoginForm(), 'popup': request.resolver_match.kwargs['popup'] or ""}))
|
||||
return HttpResponseForbidden(
|
||||
render(
|
||||
request,
|
||||
"core/403.jinja",
|
||||
context={
|
||||
"next": request.path,
|
||||
"form": LoginForm(),
|
||||
"popup": request.resolver_match.kwargs["popup"] or "",
|
||||
},
|
||||
)
|
||||
)
|
||||
except:
|
||||
return HttpResponseForbidden(render(request, "core/403.jinja", context={'next': request.path, 'form': LoginForm()}))
|
||||
return HttpResponseForbidden(
|
||||
render(
|
||||
request,
|
||||
"core/403.jinja",
|
||||
context={"next": request.path, "form": LoginForm()},
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
def not_found(request):
|
||||
return HttpResponseNotFound(render(request, "core/404.jinja"))
|
||||
|
||||
|
||||
def can_edit_prop(obj, user):
|
||||
if obj is None or user.is_owner(obj):
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
def can_edit(obj, user):
|
||||
if obj is None or user.can_edit(obj):
|
||||
return True
|
||||
return can_edit_prop(obj, user)
|
||||
|
||||
|
||||
def can_view(obj, user):
|
||||
if obj is None or user.can_view(obj):
|
||||
return True
|
||||
return can_edit(obj, user)
|
||||
|
||||
|
||||
class CanCreateMixin(View):
|
||||
"""
|
||||
This view is made to protect any child view that would create an object, and thus, that can not be protected by any
|
||||
of the following mixin
|
||||
"""
|
||||
|
||||
def dispatch(self, request, *arg, **kwargs):
|
||||
res = super(CanCreateMixin, self).dispatch(request, *arg, **kwargs)
|
||||
if not request.user.is_authenticated():
|
||||
@ -75,6 +101,7 @@ class CanCreateMixin(View):
|
||||
return super(CanCreateMixin, self).form_valid(form)
|
||||
raise PermissionDenied
|
||||
|
||||
|
||||
class CanEditPropMixin(View):
|
||||
"""
|
||||
This view is made to protect any child view that would be showing some properties of an object that are restricted
|
||||
@ -82,64 +109,78 @@ class CanEditPropMixin(View):
|
||||
In other word, you can make a view with this view as parent, and it would be retricted to the users that are in the
|
||||
object's owner_group
|
||||
"""
|
||||
|
||||
def dispatch(self, request, *arg, **kwargs):
|
||||
try:
|
||||
self.object = self.get_object()
|
||||
if can_edit_prop(self.object, request.user):
|
||||
return super(CanEditPropMixin, self).dispatch(request, *arg, **kwargs)
|
||||
return forbidden(request)
|
||||
except: pass
|
||||
except:
|
||||
pass
|
||||
# If we get here, it's a ListView
|
||||
l_id = [o.id for o in self.get_queryset() if can_edit_prop(o, request.user)]
|
||||
if not l_id and self.get_queryset().count() != 0:
|
||||
raise PermissionDenied
|
||||
self._get_queryset = self.get_queryset
|
||||
|
||||
def get_qs(self2):
|
||||
return self2._get_queryset().filter(id__in=l_id)
|
||||
|
||||
self.get_queryset = types.MethodType(get_qs, self)
|
||||
return super(CanEditPropMixin, self).dispatch(request, *arg, **kwargs)
|
||||
|
||||
|
||||
class CanEditMixin(View):
|
||||
"""
|
||||
This view makes exactly the same thing as its direct parent, but checks the group on the edit_groups field of the
|
||||
object
|
||||
"""
|
||||
|
||||
def dispatch(self, request, *arg, **kwargs):
|
||||
try:
|
||||
self.object = self.get_object()
|
||||
if can_edit(self.object, request.user):
|
||||
return super(CanEditMixin, self).dispatch(request, *arg, **kwargs)
|
||||
return forbidden(request)
|
||||
except: pass
|
||||
except:
|
||||
pass
|
||||
# If we get here, it's a ListView
|
||||
l_id = [o.id for o in self.get_queryset() if can_edit(o, request.user)]
|
||||
if not l_id and self.get_queryset().count() != 0:
|
||||
raise PermissionDenied
|
||||
self._get_queryset = self.get_queryset
|
||||
|
||||
def get_qs(self2):
|
||||
return self2._get_queryset().filter(id__in=l_id)
|
||||
|
||||
self.get_queryset = types.MethodType(get_qs, self)
|
||||
return super(CanEditMixin, self).dispatch(request, *arg, **kwargs)
|
||||
|
||||
|
||||
class CanViewMixin(View):
|
||||
"""
|
||||
This view still makes exactly the same thing as its direct parent, but checks the group on the view_groups field of
|
||||
the object
|
||||
"""
|
||||
|
||||
def dispatch(self, request, *arg, **kwargs):
|
||||
try:
|
||||
self.object = self.get_object()
|
||||
if can_view(self.object, request.user):
|
||||
return super(CanViewMixin, self).dispatch(request, *arg, **kwargs)
|
||||
return forbidden(request)
|
||||
except: pass
|
||||
except:
|
||||
pass
|
||||
# If we get here, it's a ListView
|
||||
l_id = [o.id for o in self.get_queryset() if can_view(o, request.user)]
|
||||
if not l_id and self.get_queryset().count() != 0:
|
||||
raise PermissionDenied
|
||||
self._get_queryset = self.get_queryset
|
||||
|
||||
def get_qs(self2):
|
||||
return self2._get_queryset().filter(id__in=l_id)
|
||||
|
||||
self.get_queryset = types.MethodType(get_qs, self)
|
||||
return super(CanViewMixin, self).dispatch(request, *arg, **kwargs)
|
||||
|
||||
@ -148,6 +189,7 @@ class FormerSubscriberMixin(View):
|
||||
"""
|
||||
This view check if the user was at least an old subscriber
|
||||
"""
|
||||
|
||||
def dispatch(self, request, *args, **kwargs):
|
||||
if not request.user.was_subscribed:
|
||||
raise PermissionDenied
|
||||
@ -158,6 +200,7 @@ class TabedViewMixin(View):
|
||||
"""
|
||||
This view provide the basic functions for displaying tabs in the template
|
||||
"""
|
||||
|
||||
def get_tabs_title(self):
|
||||
try:
|
||||
return self.tabs_title
|
||||
@ -178,38 +221,42 @@ class TabedViewMixin(View):
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
kwargs = super(TabedViewMixin, self).get_context_data(**kwargs)
|
||||
kwargs['tabs_title'] = self.get_tabs_title()
|
||||
kwargs['current_tab'] = self.get_current_tab()
|
||||
kwargs['list_of_tabs'] = self.get_list_of_tabs()
|
||||
kwargs["tabs_title"] = self.get_tabs_title()
|
||||
kwargs["current_tab"] = self.get_current_tab()
|
||||
kwargs["list_of_tabs"] = self.get_list_of_tabs()
|
||||
return kwargs
|
||||
|
||||
|
||||
class QuickNotifMixin:
|
||||
quick_notif_list = []
|
||||
|
||||
def dispatch(self, request, *arg, **kwargs):
|
||||
self.quick_notif_list = [] # In some cases, the class can stay instanciated, so we need to reset the list
|
||||
self.quick_notif_list = (
|
||||
[]
|
||||
) # In some cases, the class can stay instanciated, so we need to reset the list
|
||||
return super(QuickNotifMixin, self).dispatch(request, *arg, **kwargs)
|
||||
|
||||
def get_success_url(self):
|
||||
ret = super(QuickNotifMixin, self).get_success_url()
|
||||
try:
|
||||
if '?' in ret:
|
||||
ret += '&' + self.quick_notif_url_arg
|
||||
if "?" in ret:
|
||||
ret += "&" + self.quick_notif_url_arg
|
||||
else:
|
||||
ret += '?' + self.quick_notif_url_arg
|
||||
except: pass
|
||||
ret += "?" + self.quick_notif_url_arg
|
||||
except:
|
||||
pass
|
||||
return ret
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
"""Add quick notifications to context"""
|
||||
kwargs = super(QuickNotifMixin, self).get_context_data(**kwargs)
|
||||
kwargs['quick_notifs'] = []
|
||||
kwargs["quick_notifs"] = []
|
||||
for n in self.quick_notif_list:
|
||||
kwargs['quick_notifs'].append(settings.SITH_QUICK_NOTIF[n])
|
||||
for k,v in settings.SITH_QUICK_NOTIF.items():
|
||||
kwargs["quick_notifs"].append(settings.SITH_QUICK_NOTIF[n])
|
||||
for k, v in settings.SITH_QUICK_NOTIF.items():
|
||||
for gk in self.request.GET.keys():
|
||||
if k == gk:
|
||||
kwargs['quick_notifs'].append(v)
|
||||
kwargs["quick_notifs"].append(v)
|
||||
return kwargs
|
||||
|
||||
|
||||
@ -218,5 +265,3 @@ from .page import *
|
||||
from .files import *
|
||||
from .site import *
|
||||
from .group import *
|
||||
|
||||
|
||||
|
@ -54,55 +54,93 @@ def send_file(request, file_id, file_class=SithFile, file_attr="file"):
|
||||
f = file_class.objects.filter(id=file_id).first()
|
||||
if f is None or not f.file:
|
||||
return not_found(request)
|
||||
if not (can_view(f, request.user) or
|
||||
('counter_token' in request.session.keys() and
|
||||
request.session['counter_token'] and # check if not null for counters that have no token set
|
||||
Counter.objects.filter(token=request.session['counter_token']).exists())
|
||||
):
|
||||
if not (
|
||||
can_view(f, request.user)
|
||||
or (
|
||||
"counter_token" in request.session.keys()
|
||||
and request.session["counter_token"]
|
||||
and Counter.objects.filter( # check if not null for counters that have no token set
|
||||
token=request.session["counter_token"]
|
||||
).exists()
|
||||
)
|
||||
):
|
||||
raise PermissionDenied
|
||||
name = f.__getattribute__(file_attr).name
|
||||
filepath = os.path.join(settings.MEDIA_ROOT, name)
|
||||
with open(filepath.encode('utf-8'), 'rb') as filename:
|
||||
with open(filepath.encode("utf-8"), "rb") as filename:
|
||||
wrapper = FileWrapper(filename)
|
||||
response = HttpResponse(wrapper, content_type=f.mime_type)
|
||||
response['Content-Length'] = os.path.getsize(filepath.encode('utf-8'))
|
||||
response['Content-Disposition'] = ('inline; filename="%s"' % f.name).encode('utf-8')
|
||||
response["Content-Length"] = os.path.getsize(filepath.encode("utf-8"))
|
||||
response["Content-Disposition"] = ('inline; filename="%s"' % f.name).encode(
|
||||
"utf-8"
|
||||
)
|
||||
return response
|
||||
|
||||
|
||||
class AddFilesForm(forms.Form):
|
||||
folder_name = forms.CharField(label=_("Add a new folder"), max_length=30, required=False)
|
||||
file_field = forms.FileField(widget=forms.ClearableFileInput(attrs={'multiple': True}), label=_("Files"),
|
||||
required=False)
|
||||
folder_name = forms.CharField(
|
||||
label=_("Add a new folder"), max_length=30, required=False
|
||||
)
|
||||
file_field = forms.FileField(
|
||||
widget=forms.ClearableFileInput(attrs={"multiple": True}),
|
||||
label=_("Files"),
|
||||
required=False,
|
||||
)
|
||||
|
||||
def process(self, parent, owner, files):
|
||||
notif = False
|
||||
try:
|
||||
if self.cleaned_data['folder_name'] != "":
|
||||
folder = SithFile(parent=parent, name=self.cleaned_data['folder_name'], owner=owner)
|
||||
if self.cleaned_data["folder_name"] != "":
|
||||
folder = SithFile(
|
||||
parent=parent, name=self.cleaned_data["folder_name"], owner=owner
|
||||
)
|
||||
folder.clean()
|
||||
folder.save()
|
||||
notif = True
|
||||
except Exception as e:
|
||||
self.add_error(None, _("Error creating folder %(folder_name)s: %(msg)s") %
|
||||
{'folder_name': self.cleaned_data['folder_name'], 'msg': repr(e)})
|
||||
self.add_error(
|
||||
None,
|
||||
_("Error creating folder %(folder_name)s: %(msg)s")
|
||||
% {"folder_name": self.cleaned_data["folder_name"], "msg": repr(e)},
|
||||
)
|
||||
for f in files:
|
||||
new_file = SithFile(parent=parent, name=f.name, file=f, owner=owner, is_folder=False,
|
||||
mime_type=f.content_type, size=f._size)
|
||||
new_file = SithFile(
|
||||
parent=parent,
|
||||
name=f.name,
|
||||
file=f,
|
||||
owner=owner,
|
||||
is_folder=False,
|
||||
mime_type=f.content_type,
|
||||
size=f._size,
|
||||
)
|
||||
try:
|
||||
new_file.clean()
|
||||
new_file.save()
|
||||
notif = True
|
||||
except Exception as e:
|
||||
self.add_error(None, _("Error uploading file %(file_name)s: %(msg)s") % {'file_name': f, 'msg': repr(e)})
|
||||
self.add_error(
|
||||
None,
|
||||
_("Error uploading file %(file_name)s: %(msg)s")
|
||||
% {"file_name": f, "msg": repr(e)},
|
||||
)
|
||||
if notif:
|
||||
for u in RealGroup.objects.filter(id=settings.SITH_GROUP_COM_ADMIN_ID).first().users.all():
|
||||
if not u.notifications.filter(type="FILE_MODERATION", viewed=False).exists():
|
||||
Notification(user=u, url=reverse("core:file_moderation"), type="FILE_MODERATION").save()
|
||||
for u in (
|
||||
RealGroup.objects.filter(id=settings.SITH_GROUP_COM_ADMIN_ID)
|
||||
.first()
|
||||
.users.all()
|
||||
):
|
||||
if not u.notifications.filter(
|
||||
type="FILE_MODERATION", viewed=False
|
||||
).exists():
|
||||
Notification(
|
||||
user=u,
|
||||
url=reverse("core:file_moderation"),
|
||||
type="FILE_MODERATION",
|
||||
).save()
|
||||
|
||||
|
||||
class FileListView(ListView):
|
||||
template_name = 'core/file_list.jinja'
|
||||
template_name = "core/file_list.jinja"
|
||||
context_object_name = "file_list"
|
||||
|
||||
def get_queryset(self):
|
||||
@ -110,81 +148,94 @@ class FileListView(ListView):
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
kwargs = super(FileListView, self).get_context_data(**kwargs)
|
||||
kwargs['popup'] = ""
|
||||
if self.kwargs['popup']:
|
||||
kwargs['popup'] = 'popup'
|
||||
kwargs["popup"] = ""
|
||||
if self.kwargs["popup"]:
|
||||
kwargs["popup"] = "popup"
|
||||
return kwargs
|
||||
|
||||
|
||||
class FileEditView(CanEditMixin, UpdateView):
|
||||
model = SithFile
|
||||
pk_url_kwarg = "file_id"
|
||||
template_name = 'core/file_edit.jinja'
|
||||
template_name = "core/file_edit.jinja"
|
||||
context_object_name = "file"
|
||||
|
||||
def get_form_class(self):
|
||||
fields = ['name', 'is_moderated']
|
||||
fields = ["name", "is_moderated"]
|
||||
if self.object.is_file:
|
||||
fields = ['file'] + fields
|
||||
fields = ["file"] + fields
|
||||
return modelform_factory(SithFile, fields=fields)
|
||||
|
||||
def get_success_url(self):
|
||||
if self.kwargs['popup']:
|
||||
return reverse('core:file_detail', kwargs={'file_id': self.object.id, 'popup': "popup"})
|
||||
return reverse('core:file_detail', kwargs={'file_id': self.object.id, 'popup': ""})
|
||||
if self.kwargs["popup"]:
|
||||
return reverse(
|
||||
"core:file_detail", kwargs={"file_id": self.object.id, "popup": "popup"}
|
||||
)
|
||||
return reverse(
|
||||
"core:file_detail", kwargs={"file_id": self.object.id, "popup": ""}
|
||||
)
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
kwargs = super(FileEditView, self).get_context_data(**kwargs)
|
||||
kwargs['popup'] = ""
|
||||
if self.kwargs['popup']:
|
||||
kwargs['popup'] = 'popup'
|
||||
kwargs["popup"] = ""
|
||||
if self.kwargs["popup"]:
|
||||
kwargs["popup"] = "popup"
|
||||
return kwargs
|
||||
|
||||
|
||||
class FileEditPropForm(forms.ModelForm):
|
||||
class Meta:
|
||||
model = SithFile
|
||||
fields = ['parent', 'owner', 'edit_groups', 'view_groups']
|
||||
parent = make_ajax_field(SithFile, 'parent', 'files', help_text="")
|
||||
edit_groups = make_ajax_field(SithFile, 'edit_groups', 'groups', help_text="", label=_("edit group"))
|
||||
view_groups = make_ajax_field(SithFile, 'view_groups', 'groups', help_text="", label=_("view group"))
|
||||
fields = ["parent", "owner", "edit_groups", "view_groups"]
|
||||
|
||||
parent = make_ajax_field(SithFile, "parent", "files", help_text="")
|
||||
edit_groups = make_ajax_field(
|
||||
SithFile, "edit_groups", "groups", help_text="", label=_("edit group")
|
||||
)
|
||||
view_groups = make_ajax_field(
|
||||
SithFile, "view_groups", "groups", help_text="", label=_("view group")
|
||||
)
|
||||
recursive = forms.BooleanField(label=_("Apply rights recursively"), required=False)
|
||||
|
||||
|
||||
class FileEditPropView(CanEditPropMixin, UpdateView):
|
||||
model = SithFile
|
||||
pk_url_kwarg = "file_id"
|
||||
template_name = 'core/file_edit.jinja'
|
||||
template_name = "core/file_edit.jinja"
|
||||
context_object_name = "file"
|
||||
form_class = FileEditPropForm
|
||||
|
||||
def get_form(self, form_class=None):
|
||||
form = super(FileEditPropView, self).get_form(form_class)
|
||||
form.fields['parent'].queryset = SithFile.objects.filter(is_folder=True)
|
||||
form.fields["parent"].queryset = SithFile.objects.filter(is_folder=True)
|
||||
return form
|
||||
|
||||
def form_valid(self, form):
|
||||
ret = super(FileEditPropView, self).form_valid(form)
|
||||
if form.cleaned_data['recursive']:
|
||||
if form.cleaned_data["recursive"]:
|
||||
self.object.apply_rights_recursively()
|
||||
return ret
|
||||
|
||||
def get_success_url(self):
|
||||
return reverse('core:file_detail', kwargs={'file_id': self.object.id, 'popup': self.kwargs['popup'] or ""})
|
||||
return reverse(
|
||||
"core:file_detail",
|
||||
kwargs={"file_id": self.object.id, "popup": self.kwargs["popup"] or ""},
|
||||
)
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
kwargs = super(FileEditPropView, self).get_context_data(**kwargs)
|
||||
kwargs['popup'] = ""
|
||||
if self.kwargs['popup']:
|
||||
kwargs['popup'] = 'popup'
|
||||
kwargs["popup"] = ""
|
||||
if self.kwargs["popup"]:
|
||||
kwargs["popup"] = "popup"
|
||||
return kwargs
|
||||
|
||||
|
||||
class FileView(CanViewMixin, DetailView, FormMixin):
|
||||
"""This class handle the upload of new files into a folder"""
|
||||
|
||||
model = SithFile
|
||||
pk_url_kwarg = "file_id"
|
||||
template_name = 'core/file_detail.jinja'
|
||||
template_name = "core/file_detail.jinja"
|
||||
context_object_name = "file"
|
||||
form_class = AddFilesForm
|
||||
|
||||
@ -201,79 +252,99 @@ class FileView(CanViewMixin, DetailView, FormMixin):
|
||||
`object` is the SithFile object you want to put in the clipboard, or
|
||||
where you want to paste the clipboard
|
||||
"""
|
||||
if 'delete' in request.POST.keys():
|
||||
for f_id in request.POST.getlist('file_list'):
|
||||
if "delete" in request.POST.keys():
|
||||
for f_id in request.POST.getlist("file_list"):
|
||||
sf = SithFile.objects.filter(id=f_id).first()
|
||||
if sf:
|
||||
sf.delete()
|
||||
if 'clear' in request.POST.keys():
|
||||
request.session['clipboard'] = []
|
||||
if 'cut' in request.POST.keys():
|
||||
for f_id in request.POST.getlist('file_list'):
|
||||
if "clear" in request.POST.keys():
|
||||
request.session["clipboard"] = []
|
||||
if "cut" in request.POST.keys():
|
||||
for f_id in request.POST.getlist("file_list"):
|
||||
f_id = int(f_id)
|
||||
if f_id in [c.id for c in object.children.all()] and f_id not in request.session['clipboard']:
|
||||
request.session['clipboard'].append(f_id)
|
||||
if 'paste' in request.POST.keys():
|
||||
for f_id in request.session['clipboard']:
|
||||
if (
|
||||
f_id in [c.id for c in object.children.all()]
|
||||
and f_id not in request.session["clipboard"]
|
||||
):
|
||||
request.session["clipboard"].append(f_id)
|
||||
if "paste" in request.POST.keys():
|
||||
for f_id in request.session["clipboard"]:
|
||||
sf = SithFile.objects.filter(id=f_id).first()
|
||||
if sf:
|
||||
sf.move_to(object)
|
||||
request.session['clipboard'] = []
|
||||
request.session["clipboard"] = []
|
||||
request.session.modified = True
|
||||
|
||||
def get(self, request, *args, **kwargs):
|
||||
self.form = self.get_form()
|
||||
if 'clipboard' not in request.session.keys():
|
||||
request.session['clipboard'] = []
|
||||
if "clipboard" not in request.session.keys():
|
||||
request.session["clipboard"] = []
|
||||
return super(FileView, self).get(request, *args, **kwargs)
|
||||
|
||||
def post(self, request, *args, **kwargs):
|
||||
self.object = self.get_object()
|
||||
if 'clipboard' not in request.session.keys():
|
||||
request.session['clipboard'] = []
|
||||
if "clipboard" not in request.session.keys():
|
||||
request.session["clipboard"] = []
|
||||
if request.user.can_edit(self.object):
|
||||
# XXX this call can fail!
|
||||
FileView.handle_clipboard(request, self.object)
|
||||
self.form = self.get_form() # The form handle only the file upload
|
||||
files = request.FILES.getlist('file_field')
|
||||
if request.user.is_authenticated() and request.user.can_edit(self.object) and self.form.is_valid():
|
||||
files = request.FILES.getlist("file_field")
|
||||
if (
|
||||
request.user.is_authenticated()
|
||||
and request.user.can_edit(self.object)
|
||||
and self.form.is_valid()
|
||||
):
|
||||
self.form.process(parent=self.object, owner=request.user, files=files)
|
||||
if self.form.is_valid():
|
||||
return super(FileView, self).form_valid(self.form)
|
||||
return self.form_invalid(self.form)
|
||||
|
||||
def get_success_url(self):
|
||||
return reverse('core:file_detail', kwargs={'file_id': self.object.id, 'popup': self.kwargs['popup'] or ""})
|
||||
return reverse(
|
||||
"core:file_detail",
|
||||
kwargs={"file_id": self.object.id, "popup": self.kwargs["popup"] or ""},
|
||||
)
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
kwargs = super(FileView, self).get_context_data(**kwargs)
|
||||
kwargs['popup'] = ""
|
||||
kwargs['form'] = self.form
|
||||
if self.kwargs['popup']:
|
||||
kwargs['popup'] = 'popup'
|
||||
kwargs['clipboard'] = SithFile.objects.filter(id__in=self.request.session['clipboard'])
|
||||
kwargs["popup"] = ""
|
||||
kwargs["form"] = self.form
|
||||
if self.kwargs["popup"]:
|
||||
kwargs["popup"] = "popup"
|
||||
kwargs["clipboard"] = SithFile.objects.filter(
|
||||
id__in=self.request.session["clipboard"]
|
||||
)
|
||||
return kwargs
|
||||
|
||||
|
||||
class FileDeleteView(CanEditPropMixin, DeleteView):
|
||||
model = SithFile
|
||||
pk_url_kwarg = "file_id"
|
||||
template_name = 'core/file_delete_confirm.jinja'
|
||||
template_name = "core/file_delete_confirm.jinja"
|
||||
context_object_name = "file"
|
||||
|
||||
def get_success_url(self):
|
||||
self.object.file.delete() # Doing it here or overloading delete() is the same, so let's do it here
|
||||
if 'next' in self.request.GET.keys():
|
||||
return self.request.GET['next']
|
||||
if "next" in self.request.GET.keys():
|
||||
return self.request.GET["next"]
|
||||
if self.object.parent is None:
|
||||
return reverse('core:file_list', kwargs={'popup': self.kwargs['popup'] or ""})
|
||||
return reverse('core:file_detail', kwargs={'file_id': self.object.parent.id, 'popup': self.kwargs['popup'] or ""})
|
||||
return reverse(
|
||||
"core:file_list", kwargs={"popup": self.kwargs["popup"] or ""}
|
||||
)
|
||||
return reverse(
|
||||
"core:file_detail",
|
||||
kwargs={
|
||||
"file_id": self.object.parent.id,
|
||||
"popup": self.kwargs["popup"] or "",
|
||||
},
|
||||
)
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
kwargs = super(FileDeleteView, self).get_context_data(**kwargs)
|
||||
kwargs['popup'] = ""
|
||||
if self.kwargs['popup']:
|
||||
kwargs['popup'] = 'popup'
|
||||
kwargs["popup"] = ""
|
||||
if self.kwargs["popup"]:
|
||||
kwargs["popup"] = "popup"
|
||||
return kwargs
|
||||
|
||||
|
||||
@ -282,7 +353,7 @@ class FileModerationView(TemplateView):
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
kwargs = super(FileModerationView, self).get_context_data(**kwargs)
|
||||
kwargs['files'] = SithFile.objects.filter(is_moderated=False)[:100]
|
||||
kwargs["files"] = SithFile.objects.filter(is_moderated=False)[:100]
|
||||
return kwargs
|
||||
|
||||
|
||||
@ -295,6 +366,6 @@ class FileModerateView(CanEditPropMixin, SingleObjectMixin):
|
||||
self.object.is_moderated = True
|
||||
self.object.moderator = request.user
|
||||
self.object.save()
|
||||
if 'next' in self.request.GET.keys():
|
||||
return redirect(self.request.GET['next'])
|
||||
return redirect('core:file_moderation')
|
||||
if "next" in self.request.GET.keys():
|
||||
return redirect(self.request.GET["next"])
|
||||
return redirect("core:file_moderation")
|
||||
|
@ -27,7 +27,14 @@ from django import forms
|
||||
from django.conf import settings
|
||||
from django.db import transaction
|
||||
from django.core.exceptions import ValidationError
|
||||
from django.forms import CheckboxSelectMultiple, Select, DateInput, TextInput, DateTimeInput, Textarea
|
||||
from django.forms import (
|
||||
CheckboxSelectMultiple,
|
||||
Select,
|
||||
DateInput,
|
||||
TextInput,
|
||||
DateTimeInput,
|
||||
Textarea,
|
||||
)
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
from django.utils.translation import ugettext
|
||||
from phonenumber_field.widgets import PhoneNumberInternationalFallbackWidget
|
||||
@ -45,114 +52,144 @@ from PIL import Image
|
||||
|
||||
# Widgets
|
||||
|
||||
|
||||
class SelectSingle(Select):
|
||||
def render(self, name, value, attrs=None):
|
||||
if attrs:
|
||||
attrs['class'] = "select_single"
|
||||
attrs["class"] = "select_single"
|
||||
else:
|
||||
attrs = {'class': "select_single"}
|
||||
attrs = {"class": "select_single"}
|
||||
return super(SelectSingle, self).render(name, value, attrs)
|
||||
|
||||
|
||||
class SelectMultiple(Select):
|
||||
def render(self, name, value, attrs=None):
|
||||
if attrs:
|
||||
attrs['class'] = "select_multiple"
|
||||
attrs["class"] = "select_multiple"
|
||||
else:
|
||||
attrs = {'class': "select_multiple"}
|
||||
attrs = {"class": "select_multiple"}
|
||||
return super(SelectMultiple, self).render(name, value, attrs)
|
||||
|
||||
|
||||
class SelectDateTime(DateTimeInput):
|
||||
def render(self, name, value, attrs=None):
|
||||
if attrs:
|
||||
attrs['class'] = "select_datetime"
|
||||
attrs["class"] = "select_datetime"
|
||||
else:
|
||||
attrs = {'class': "select_datetime"}
|
||||
attrs = {"class": "select_datetime"}
|
||||
return super(SelectDateTime, self).render(name, value, attrs)
|
||||
|
||||
|
||||
class SelectDate(DateInput):
|
||||
def render(self, name, value, attrs=None):
|
||||
if attrs:
|
||||
attrs['class'] = "select_date"
|
||||
attrs["class"] = "select_date"
|
||||
else:
|
||||
attrs = {'class': "select_date"}
|
||||
attrs = {"class": "select_date"}
|
||||
return super(SelectDate, self).render(name, value, attrs)
|
||||
|
||||
|
||||
class MarkdownInput(Textarea):
|
||||
def render(self, name, value, attrs=None):
|
||||
output = '<p><a href="%(syntax_url)s">%(help_text)s</a></p>'\
|
||||
'<div class="markdown_editor">%(content)s</div>' % {
|
||||
'syntax_url': Page.get_page_by_full_name(settings.SITH_CORE_PAGE_SYNTAX).get_absolute_url(),
|
||||
'help_text': _("Help on the syntax"),
|
||||
'content': super(MarkdownInput, self).render(name, value, attrs),
|
||||
}
|
||||
output = (
|
||||
'<p><a href="%(syntax_url)s">%(help_text)s</a></p>'
|
||||
'<div class="markdown_editor">%(content)s</div>'
|
||||
% {
|
||||
"syntax_url": Page.get_page_by_full_name(
|
||||
settings.SITH_CORE_PAGE_SYNTAX
|
||||
).get_absolute_url(),
|
||||
"help_text": _("Help on the syntax"),
|
||||
"content": super(MarkdownInput, self).render(name, value, attrs),
|
||||
}
|
||||
)
|
||||
return output
|
||||
|
||||
|
||||
class SelectFile(TextInput):
|
||||
def render(self, name, value, attrs=None):
|
||||
if attrs:
|
||||
attrs['class'] = "select_file"
|
||||
attrs["class"] = "select_file"
|
||||
else:
|
||||
attrs = {'class': "select_file"}
|
||||
output = '%(content)s<div name="%(name)s" class="choose_file_widget" title="%(title)s"></div>' % {
|
||||
'content': super(SelectFile, self).render(name, value, attrs),
|
||||
'title': _("Choose file"),
|
||||
'name': name,
|
||||
}
|
||||
output += '<span name="' + name + '" class="choose_file_button">' + ugettext("Choose file") + '</span>'
|
||||
attrs = {"class": "select_file"}
|
||||
output = (
|
||||
'%(content)s<div name="%(name)s" class="choose_file_widget" title="%(title)s"></div>'
|
||||
% {
|
||||
"content": super(SelectFile, self).render(name, value, attrs),
|
||||
"title": _("Choose file"),
|
||||
"name": name,
|
||||
}
|
||||
)
|
||||
output += (
|
||||
'<span name="'
|
||||
+ name
|
||||
+ '" class="choose_file_button">'
|
||||
+ ugettext("Choose file")
|
||||
+ "</span>"
|
||||
)
|
||||
return output
|
||||
|
||||
|
||||
class SelectUser(TextInput):
|
||||
def render(self, name, value, attrs=None):
|
||||
if attrs:
|
||||
attrs['class'] = "select_user"
|
||||
attrs["class"] = "select_user"
|
||||
else:
|
||||
attrs = {'class': "select_user"}
|
||||
output = '%(content)s<div name="%(name)s" class="choose_user_widget" title="%(title)s"></div>' % {
|
||||
'content': super(SelectUser, self).render(name, value, attrs),
|
||||
'title': _("Choose user"),
|
||||
'name': name,
|
||||
}
|
||||
output += '<span name="' + name + '" class="choose_user_button">' + ugettext("Choose user") + '</span>'
|
||||
attrs = {"class": "select_user"}
|
||||
output = (
|
||||
'%(content)s<div name="%(name)s" class="choose_user_widget" title="%(title)s"></div>'
|
||||
% {
|
||||
"content": super(SelectUser, self).render(name, value, attrs),
|
||||
"title": _("Choose user"),
|
||||
"name": name,
|
||||
}
|
||||
)
|
||||
output += (
|
||||
'<span name="'
|
||||
+ name
|
||||
+ '" class="choose_user_button">'
|
||||
+ ugettext("Choose user")
|
||||
+ "</span>"
|
||||
)
|
||||
return output
|
||||
|
||||
|
||||
# Forms
|
||||
|
||||
|
||||
class LoginForm(AuthenticationForm):
|
||||
def __init__(self, *arg, **kwargs):
|
||||
if 'data' in kwargs.keys():
|
||||
if "data" in kwargs.keys():
|
||||
from counter.models import Customer
|
||||
data = kwargs['data'].copy()
|
||||
|
||||
data = kwargs["data"].copy()
|
||||
account_code = re.compile(r"^[0-9]+[A-Za-z]$")
|
||||
try:
|
||||
if account_code.match(data['username']):
|
||||
user = Customer.objects.filter(account_id__iexact=data['username']).first().user
|
||||
elif '@' in data['username']:
|
||||
user = User.objects.filter(email__iexact=data['username']).first()
|
||||
if account_code.match(data["username"]):
|
||||
user = (
|
||||
Customer.objects.filter(account_id__iexact=data["username"])
|
||||
.first()
|
||||
.user
|
||||
)
|
||||
elif "@" in data["username"]:
|
||||
user = User.objects.filter(email__iexact=data["username"]).first()
|
||||
else:
|
||||
user = User.objects.filter(username=data['username']).first()
|
||||
data['username'] = user.username
|
||||
user = User.objects.filter(username=data["username"]).first()
|
||||
data["username"] = user.username
|
||||
except:
|
||||
pass
|
||||
kwargs['data'] = data
|
||||
kwargs["data"] = data
|
||||
super(LoginForm, self).__init__(*arg, **kwargs)
|
||||
self.fields['username'].label = _("Username, email, or account number")
|
||||
self.fields["username"].label = _("Username, email, or account number")
|
||||
|
||||
|
||||
class RegisteringForm(UserCreationForm):
|
||||
error_css_class = 'error'
|
||||
required_css_class = 'required'
|
||||
error_css_class = "error"
|
||||
required_css_class = "required"
|
||||
captcha = CaptchaField()
|
||||
|
||||
class Meta:
|
||||
model = User
|
||||
fields = ('first_name', 'last_name', 'email')
|
||||
fields = ("first_name", "last_name", "email")
|
||||
|
||||
def save(self, commit=True):
|
||||
user = super(RegisteringForm, self).save(commit=False)
|
||||
@ -169,24 +206,49 @@ class UserProfileForm(forms.ModelForm):
|
||||
This form is actually pretty bad and was made in the rush before the migration. It should be refactored.
|
||||
TODO: refactor this form
|
||||
"""
|
||||
|
||||
class Meta:
|
||||
model = User
|
||||
fields = ['first_name', 'last_name', 'nick_name', 'email', 'date_of_birth', 'profile_pict', 'avatar_pict',
|
||||
'scrub_pict', 'sex', 'second_email', 'address', 'parent_address', 'phone', 'parent_phone',
|
||||
'tshirt_size', 'role', 'department', 'dpt_option', 'semester', 'quote', 'school', 'promo',
|
||||
'forum_signature', 'is_subscriber_viewable']
|
||||
fields = [
|
||||
"first_name",
|
||||
"last_name",
|
||||
"nick_name",
|
||||
"email",
|
||||
"date_of_birth",
|
||||
"profile_pict",
|
||||
"avatar_pict",
|
||||
"scrub_pict",
|
||||
"sex",
|
||||
"second_email",
|
||||
"address",
|
||||
"parent_address",
|
||||
"phone",
|
||||
"parent_phone",
|
||||
"tshirt_size",
|
||||
"role",
|
||||
"department",
|
||||
"dpt_option",
|
||||
"semester",
|
||||
"quote",
|
||||
"school",
|
||||
"promo",
|
||||
"forum_signature",
|
||||
"is_subscriber_viewable",
|
||||
]
|
||||
widgets = {
|
||||
'date_of_birth': SelectDate,
|
||||
'profile_pict': forms.ClearableFileInput,
|
||||
'avatar_pict': forms.ClearableFileInput,
|
||||
'scrub_pict': forms.ClearableFileInput,
|
||||
'phone': PhoneNumberInternationalFallbackWidget,
|
||||
'parent_phone': PhoneNumberInternationalFallbackWidget,
|
||||
"date_of_birth": SelectDate,
|
||||
"profile_pict": forms.ClearableFileInput,
|
||||
"avatar_pict": forms.ClearableFileInput,
|
||||
"scrub_pict": forms.ClearableFileInput,
|
||||
"phone": PhoneNumberInternationalFallbackWidget,
|
||||
"parent_phone": PhoneNumberInternationalFallbackWidget,
|
||||
}
|
||||
labels = {
|
||||
'profile_pict': _("Profile: you need to be visible on the picture, in order to be recognized (e.g. by the barmen)"),
|
||||
'avatar_pict': _("Avatar: used on the forum"),
|
||||
'scrub_pict': _("Scrub: let other know how your scrub looks like!"),
|
||||
"profile_pict": _(
|
||||
"Profile: you need to be visible on the picture, in order to be recognized (e.g. by the barmen)"
|
||||
),
|
||||
"avatar_pict": _("Avatar: used on the forum"),
|
||||
"scrub_pict": _("Scrub: let other know how your scrub looks like!"),
|
||||
}
|
||||
|
||||
def __init__(self, *arg, **kwargs):
|
||||
@ -197,27 +259,36 @@ class UserProfileForm(forms.ModelForm):
|
||||
|
||||
def generate_name(self, field_name, f):
|
||||
field_name = field_name[:-4]
|
||||
return field_name + str(self.instance.id) + "." + f.content_type.split('/')[-1]
|
||||
return field_name + str(self.instance.id) + "." + f.content_type.split("/")[-1]
|
||||
|
||||
def process(self, files):
|
||||
avatar = self.instance.avatar_pict
|
||||
profile = self.instance.profile_pict
|
||||
scrub = self.instance.scrub_pict
|
||||
self.full_clean()
|
||||
self.cleaned_data['avatar_pict'] = avatar
|
||||
self.cleaned_data['profile_pict'] = profile
|
||||
self.cleaned_data['scrub_pict'] = scrub
|
||||
self.cleaned_data["avatar_pict"] = avatar
|
||||
self.cleaned_data["profile_pict"] = profile
|
||||
self.cleaned_data["scrub_pict"] = scrub
|
||||
parent = SithFile.objects.filter(parent=None, name="profiles").first()
|
||||
for field, f in files:
|
||||
with transaction.atomic():
|
||||
try:
|
||||
im = Image.open(BytesIO(f.read()))
|
||||
new_file = SithFile(parent=parent, name=self.generate_name(field, f),
|
||||
file=resize_image(im, 400, f.content_type.split('/')[-1]),
|
||||
owner=self.instance, is_folder=False, mime_type=f.content_type, size=f._size,
|
||||
moderator=self.instance, is_moderated=True)
|
||||
new_file = SithFile(
|
||||
parent=parent,
|
||||
name=self.generate_name(field, f),
|
||||
file=resize_image(im, 400, f.content_type.split("/")[-1]),
|
||||
owner=self.instance,
|
||||
is_folder=False,
|
||||
mime_type=f.content_type,
|
||||
size=f._size,
|
||||
moderator=self.instance,
|
||||
is_moderated=True,
|
||||
)
|
||||
new_file.file.name = new_file.name
|
||||
old = SithFile.objects.filter(parent=parent, name=new_file.name).first()
|
||||
old = SithFile.objects.filter(
|
||||
parent=parent, name=new_file.name
|
||||
).first()
|
||||
if old:
|
||||
old.delete()
|
||||
new_file.clean()
|
||||
@ -226,73 +297,101 @@ class UserProfileForm(forms.ModelForm):
|
||||
self._errors.pop(field, None)
|
||||
except ValidationError as e:
|
||||
self._errors.pop(field, None)
|
||||
self.add_error(field, _("Error uploading file %(file_name)s: %(msg)s") %
|
||||
{'file_name': f, 'msg': str(e.message)})
|
||||
self.add_error(
|
||||
field,
|
||||
_("Error uploading file %(file_name)s: %(msg)s")
|
||||
% {"file_name": f, "msg": str(e.message)},
|
||||
)
|
||||
except IOError:
|
||||
self._errors.pop(field, None)
|
||||
self.add_error(field, _("Error uploading file %(file_name)s: %(msg)s") %
|
||||
{'file_name': f, 'msg': _("Bad image format, only jpeg, png, and gif are accepted")})
|
||||
self.add_error(
|
||||
field,
|
||||
_("Error uploading file %(file_name)s: %(msg)s")
|
||||
% {
|
||||
"file_name": f,
|
||||
"msg": _(
|
||||
"Bad image format, only jpeg, png, and gif are accepted"
|
||||
),
|
||||
},
|
||||
)
|
||||
self._post_clean()
|
||||
|
||||
|
||||
class UserPropForm(forms.ModelForm):
|
||||
error_css_class = 'error'
|
||||
required_css_class = 'required'
|
||||
error_css_class = "error"
|
||||
required_css_class = "required"
|
||||
|
||||
class Meta:
|
||||
model = User
|
||||
fields = ['groups']
|
||||
help_texts = {
|
||||
'groups': "Which groups this user belongs to",
|
||||
}
|
||||
widgets = {
|
||||
'groups': CheckboxSelectMultiple,
|
||||
}
|
||||
fields = ["groups"]
|
||||
help_texts = {"groups": "Which groups this user belongs to"}
|
||||
widgets = {"groups": CheckboxSelectMultiple}
|
||||
|
||||
|
||||
class UserGodfathersForm(forms.Form):
|
||||
type = forms.ChoiceField(choices=[('godfather', _("Godfather")), ('godchild', _("Godchild"))], label=_("Add"))
|
||||
user = AutoCompleteSelectField('users', required=True, label=_("Select user"), help_text=None)
|
||||
type = forms.ChoiceField(
|
||||
choices=[("godfather", _("Godfather")), ("godchild", _("Godchild"))],
|
||||
label=_("Add"),
|
||||
)
|
||||
user = AutoCompleteSelectField(
|
||||
"users", required=True, label=_("Select user"), help_text=None
|
||||
)
|
||||
|
||||
|
||||
class PagePropForm(forms.ModelForm):
|
||||
error_css_class = 'error'
|
||||
required_css_class = 'required'
|
||||
error_css_class = "error"
|
||||
required_css_class = "required"
|
||||
|
||||
class Meta:
|
||||
model = Page
|
||||
fields = ['parent', 'name', 'owner_group', 'edit_groups', 'view_groups', ]
|
||||
edit_groups = make_ajax_field(Page, 'edit_groups', 'groups', help_text="", label=_("edit groups"))
|
||||
view_groups = make_ajax_field(Page, 'view_groups', 'groups', help_text="", label=_("view groups"))
|
||||
fields = ["parent", "name", "owner_group", "edit_groups", "view_groups"]
|
||||
|
||||
edit_groups = make_ajax_field(
|
||||
Page, "edit_groups", "groups", help_text="", label=_("edit groups")
|
||||
)
|
||||
view_groups = make_ajax_field(
|
||||
Page, "view_groups", "groups", help_text="", label=_("view groups")
|
||||
)
|
||||
|
||||
def __init__(self, *arg, **kwargs):
|
||||
super(PagePropForm, self).__init__(*arg, **kwargs)
|
||||
self.fields['edit_groups'].required = False
|
||||
self.fields['view_groups'].required = False
|
||||
self.fields["edit_groups"].required = False
|
||||
self.fields["view_groups"].required = False
|
||||
|
||||
|
||||
class PageForm(forms.ModelForm):
|
||||
class Meta:
|
||||
model = Page
|
||||
fields = ['parent', 'name', 'owner_group', 'edit_groups', 'view_groups']
|
||||
edit_groups = make_ajax_field(Page, 'edit_groups', 'groups', help_text="", label=_("edit groups"))
|
||||
view_groups = make_ajax_field(Page, 'view_groups', 'groups', help_text="", label=_("view groups"))
|
||||
fields = ["parent", "name", "owner_group", "edit_groups", "view_groups"]
|
||||
|
||||
edit_groups = make_ajax_field(
|
||||
Page, "edit_groups", "groups", help_text="", label=_("edit groups")
|
||||
)
|
||||
view_groups = make_ajax_field(
|
||||
Page, "view_groups", "groups", help_text="", label=_("view groups")
|
||||
)
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(PageForm, self).__init__(*args, **kwargs)
|
||||
self.fields['parent'].queryset = self.fields['parent'].queryset.exclude(name=settings.SITH_CLUB_ROOT_PAGE).filter(club=None)
|
||||
self.fields["parent"].queryset = (
|
||||
self.fields["parent"]
|
||||
.queryset.exclude(name=settings.SITH_CLUB_ROOT_PAGE)
|
||||
.filter(club=None)
|
||||
)
|
||||
|
||||
|
||||
class GiftForm(forms.ModelForm):
|
||||
class Meta:
|
||||
model = Gift
|
||||
fields = ['label', 'user']
|
||||
fields = ["label", "user"]
|
||||
|
||||
label = forms.ChoiceField(choices=settings.SITH_GIFT_LIST)
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
user_id = kwargs.pop('user_id', None)
|
||||
user_id = kwargs.pop("user_id", None)
|
||||
super(GiftForm, self).__init__(*args, **kwargs)
|
||||
if user_id:
|
||||
self.fields['user'].queryset = self.fields['user'].queryset.filter(id=user_id)
|
||||
self.fields['user'].widget = forms.HiddenInput()
|
||||
self.fields["user"].queryset = self.fields["user"].queryset.filter(
|
||||
id=user_id
|
||||
)
|
||||
self.fields["user"].widget = forms.HiddenInput()
|
||||
|
@ -34,6 +34,7 @@ class GroupListView(CanEditMixin, ListView):
|
||||
"""
|
||||
Displays the group list
|
||||
"""
|
||||
|
||||
model = RealGroup
|
||||
template_name = "core/group_list.jinja"
|
||||
|
||||
@ -42,17 +43,17 @@ class GroupEditView(CanEditMixin, UpdateView):
|
||||
model = RealGroup
|
||||
pk_url_kwarg = "group_id"
|
||||
template_name = "core/group_edit.jinja"
|
||||
fields = ['name', 'description']
|
||||
fields = ["name", "description"]
|
||||
|
||||
|
||||
class GroupCreateView(CanEditMixin, CreateView):
|
||||
model = RealGroup
|
||||
template_name = "core/group_edit.jinja"
|
||||
fields = ['name', 'description']
|
||||
fields = ["name", "description"]
|
||||
|
||||
|
||||
class GroupDeleteView(CanEditMixin, DeleteView):
|
||||
model = RealGroup
|
||||
pk_url_kwarg = "group_id"
|
||||
template_name = "core/delete_confirm.jinja"
|
||||
success_url = reverse_lazy('core:group_list')
|
||||
success_url = reverse_lazy("core:group_list")
|
||||
|
@ -36,7 +36,6 @@ from core.views import CanViewMixin, CanEditMixin, CanEditPropMixin, CanCreateMi
|
||||
|
||||
|
||||
class CanEditPagePropMixin(CanEditPropMixin):
|
||||
|
||||
def dispatch(self, request, *args, **kwargs):
|
||||
res = super(CanEditPagePropMixin, self).dispatch(request, *args, **kwargs)
|
||||
if self.object.is_club_page:
|
||||
@ -46,93 +45,95 @@ class CanEditPagePropMixin(CanEditPropMixin):
|
||||
|
||||
class PageListView(CanViewMixin, ListView):
|
||||
model = Page
|
||||
template_name = 'core/page_list.jinja'
|
||||
template_name = "core/page_list.jinja"
|
||||
|
||||
|
||||
class PageView(CanViewMixin, DetailView):
|
||||
model = Page
|
||||
template_name = 'core/page_detail.jinja'
|
||||
template_name = "core/page_detail.jinja"
|
||||
|
||||
def dispatch(self, request, *args, **kwargs):
|
||||
res = super(PageView, self).dispatch(request, *args, **kwargs)
|
||||
if self.object and self.object.need_club_redirection:
|
||||
return redirect('club:club_view', club_id=self.object.club.id)
|
||||
return redirect("club:club_view", club_id=self.object.club.id)
|
||||
return res
|
||||
|
||||
def get_object(self):
|
||||
self.page = Page.get_page_by_full_name(self.kwargs['page_name'])
|
||||
self.page = Page.get_page_by_full_name(self.kwargs["page_name"])
|
||||
return self.page
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
context = super(PageView, self).get_context_data(**kwargs)
|
||||
if "page" not in context.keys():
|
||||
context['new_page'] = self.kwargs['page_name']
|
||||
context["new_page"] = self.kwargs["page_name"]
|
||||
return context
|
||||
|
||||
|
||||
class PageHistView(CanViewMixin, DetailView):
|
||||
model = Page
|
||||
template_name = 'core/page_hist.jinja'
|
||||
template_name = "core/page_hist.jinja"
|
||||
|
||||
def dispatch(self, request, *args, **kwargs):
|
||||
res = super(PageHistView, self).dispatch(request, *args, **kwargs)
|
||||
if self.object.need_club_redirection:
|
||||
return redirect('club:club_hist', club_id=self.object.club.id)
|
||||
return redirect("club:club_hist", club_id=self.object.club.id)
|
||||
return res
|
||||
|
||||
def get_object(self):
|
||||
self.page = Page.get_page_by_full_name(self.kwargs['page_name'])
|
||||
self.page = Page.get_page_by_full_name(self.kwargs["page_name"])
|
||||
return self.page
|
||||
|
||||
|
||||
class PageRevView(CanViewMixin, DetailView):
|
||||
model = Page
|
||||
template_name = 'core/page_detail.jinja'
|
||||
template_name = "core/page_detail.jinja"
|
||||
|
||||
def dispatch(self, request, *args, **kwargs):
|
||||
res = super(PageRevView, self).dispatch(request, *args, **kwargs)
|
||||
if self.object.need_club_redirection:
|
||||
return redirect('club:club_view_rev', club_id=self.object.club.id, rev_id=kwargs['rev'])
|
||||
return redirect(
|
||||
"club:club_view_rev", club_id=self.object.club.id, rev_id=kwargs["rev"]
|
||||
)
|
||||
return res
|
||||
|
||||
def get_object(self):
|
||||
self.page = Page.get_page_by_full_name(self.kwargs['page_name'])
|
||||
self.page = Page.get_page_by_full_name(self.kwargs["page_name"])
|
||||
return self.page
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
context = super(PageRevView, self).get_context_data(**kwargs)
|
||||
if self.page is not None:
|
||||
context['page'] = self.page
|
||||
context["page"] = self.page
|
||||
try:
|
||||
rev = self.page.revisions.get(id=self.kwargs['rev'])
|
||||
context['rev'] = rev
|
||||
rev = self.page.revisions.get(id=self.kwargs["rev"])
|
||||
context["rev"] = rev
|
||||
except:
|
||||
# By passing, the template will just display the normal page without taking revision into account
|
||||
pass
|
||||
else:
|
||||
context['new_page'] = self.kwargs['page_name']
|
||||
context["new_page"] = self.kwargs["page_name"]
|
||||
return context
|
||||
|
||||
|
||||
class PageCreateView(CanCreateMixin, CreateView):
|
||||
model = Page
|
||||
form_class = PageForm
|
||||
template_name = 'core/page_prop.jinja'
|
||||
template_name = "core/page_prop.jinja"
|
||||
|
||||
def get_initial(self):
|
||||
init = {}
|
||||
if 'page' in self.request.GET.keys():
|
||||
page_name = self.request.GET['page']
|
||||
parent_name = '/'.join(page_name.split('/')[:-1])
|
||||
if "page" in self.request.GET.keys():
|
||||
page_name = self.request.GET["page"]
|
||||
parent_name = "/".join(page_name.split("/")[:-1])
|
||||
parent = Page.get_page_by_full_name(parent_name)
|
||||
if parent is not None:
|
||||
init['parent'] = parent.id
|
||||
init['name'] = page_name.split('/')[-1]
|
||||
init["parent"] = parent.id
|
||||
init["name"] = page_name.split("/")[-1]
|
||||
return init
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
context = super(PageCreateView, self).get_context_data(**kwargs)
|
||||
context['new_page'] = True
|
||||
context["new_page"] = True
|
||||
return context
|
||||
|
||||
def form_valid(self, form):
|
||||
@ -144,9 +145,9 @@ class PageCreateView(CanCreateMixin, CreateView):
|
||||
class PagePropView(CanEditPagePropMixin, UpdateView):
|
||||
model = Page
|
||||
form_class = PagePropForm
|
||||
template_name = 'core/page_prop.jinja'
|
||||
slug_field = '_full_name'
|
||||
slug_url_kwarg = 'page_name'
|
||||
template_name = "core/page_prop.jinja"
|
||||
slug_field = "_full_name"
|
||||
slug_url_kwarg = "page_name"
|
||||
|
||||
def get_object(self):
|
||||
o = super(PagePropView, self).get_object()
|
||||
@ -169,11 +170,13 @@ class PagePropView(CanEditPagePropMixin, UpdateView):
|
||||
|
||||
class PageEditViewBase(CanEditMixin, UpdateView):
|
||||
model = PageRev
|
||||
form_class = modelform_factory(model=PageRev, fields=['title', 'content', ], widgets={'content': MarkdownInput})
|
||||
template_name = 'core/pagerev_edit.jinja'
|
||||
form_class = modelform_factory(
|
||||
model=PageRev, fields=["title", "content"], widgets={"content": MarkdownInput}
|
||||
)
|
||||
template_name = "core/pagerev_edit.jinja"
|
||||
|
||||
def get_object(self):
|
||||
self.page = Page.get_page_by_full_name(self.kwargs['page_name'])
|
||||
self.page = Page.get_page_by_full_name(self.kwargs["page_name"])
|
||||
return self._get_revision()
|
||||
|
||||
def _get_revision(self):
|
||||
@ -193,17 +196,15 @@ class PageEditViewBase(CanEditMixin, UpdateView):
|
||||
def get_context_data(self, **kwargs):
|
||||
context = super(PageEditViewBase, self).get_context_data(**kwargs)
|
||||
if self.page is not None:
|
||||
context['page'] = self.page
|
||||
context["page"] = self.page
|
||||
else:
|
||||
context['new_page'] = self.kwargs['page_name']
|
||||
context["new_page"] = self.kwargs["page_name"]
|
||||
return context
|
||||
|
||||
def form_valid(self, form):
|
||||
# TODO : factor that, but first make some tests
|
||||
rev = form.instance
|
||||
new_rev = PageRev(title=rev.title,
|
||||
content=rev.content,
|
||||
)
|
||||
new_rev = PageRev(title=rev.title, content=rev.content)
|
||||
new_rev.author = self.request.user
|
||||
new_rev.page = self.page
|
||||
form.instance = new_rev
|
||||
@ -211,18 +212,17 @@ class PageEditViewBase(CanEditMixin, UpdateView):
|
||||
|
||||
|
||||
class PageEditView(PageEditViewBase):
|
||||
|
||||
def dispatch(self, request, *args, **kwargs):
|
||||
res = super(PageEditView, self).dispatch(request, *args, **kwargs)
|
||||
if self.object and self.object.page.need_club_redirection:
|
||||
return redirect('club:club_edit_page', club_id=self.object.page.club.id)
|
||||
return redirect("club:club_edit_page", club_id=self.object.page.club.id)
|
||||
return res
|
||||
|
||||
|
||||
class PageDeleteView(CanEditPagePropMixin, DeleteView):
|
||||
model = Page
|
||||
template_name = 'core/delete_confirm.jinja'
|
||||
pk_url_kwarg = 'page_id'
|
||||
template_name = "core/delete_confirm.jinja"
|
||||
pk_url_kwarg = "page_id"
|
||||
|
||||
def get_success_url(self, **kwargs):
|
||||
return reverse_lazy('core:page_list')
|
||||
return reverse_lazy("core:page_list")
|
||||
|
@ -41,6 +41,7 @@ from club.models import Club
|
||||
def index(request, context=None):
|
||||
if request.user.is_authenticated():
|
||||
from com.views import NewsListView
|
||||
|
||||
return NewsListView.as_view()(request)
|
||||
return render(request, "core/index.jinja")
|
||||
|
||||
@ -50,11 +51,11 @@ class NotificationList(ListView):
|
||||
template_name = "core/notification_list.jinja"
|
||||
|
||||
def get_queryset(self):
|
||||
if 'see_all' in self.request.GET.keys():
|
||||
if "see_all" in self.request.GET.keys():
|
||||
for n in self.request.user.notifications.all():
|
||||
n.viewed = True
|
||||
n.save()
|
||||
return self.request.user.notifications.order_by('-date')[:20]
|
||||
return self.request.user.notifications.order_by("-date")[:20]
|
||||
|
||||
|
||||
def notification(request, notif_id):
|
||||
@ -70,7 +71,12 @@ def notification(request, notif_id):
|
||||
|
||||
|
||||
def search_user(query, as_json=False):
|
||||
res = SearchQuerySet().models(User).filter(text=query).filter_or(text__contains=query)[:20]
|
||||
res = (
|
||||
SearchQuerySet()
|
||||
.models(User)
|
||||
.filter(text=query)
|
||||
.filter_or(text__contains=query)[:20]
|
||||
)
|
||||
return [r.object for r in res]
|
||||
|
||||
|
||||
@ -79,8 +85,10 @@ def search_club(query, as_json=False):
|
||||
if query:
|
||||
clubs = Club.objects.filter(name__icontains=query).all()
|
||||
clubs = clubs[:5]
|
||||
if as_json: # Re-loads json to avoid double encoding by JsonResponse, but still benefit from serializers
|
||||
clubs = json.loads(serializers.serialize('json', clubs, fields=('name')))
|
||||
if (
|
||||
as_json
|
||||
): # Re-loads json to avoid double encoding by JsonResponse, but still benefit from serializers
|
||||
clubs = json.loads(serializers.serialize("json", clubs, fields=("name")))
|
||||
else:
|
||||
clubs = list(clubs)
|
||||
return clubs
|
||||
@ -89,25 +97,23 @@ def search_club(query, as_json=False):
|
||||
@login_required
|
||||
def search_view(request):
|
||||
result = {
|
||||
'users': search_user(request.GET.get('query', '')),
|
||||
'clubs': search_club(request.GET.get('query', '')),
|
||||
"users": search_user(request.GET.get("query", "")),
|
||||
"clubs": search_club(request.GET.get("query", "")),
|
||||
}
|
||||
return render(request, "core/search.jinja", context={'result': result})
|
||||
return render(request, "core/search.jinja", context={"result": result})
|
||||
|
||||
|
||||
@login_required
|
||||
def search_user_json(request):
|
||||
result = {
|
||||
'users': search_user(request.GET.get('query', ''), True),
|
||||
}
|
||||
result = {"users": search_user(request.GET.get("query", ""), True)}
|
||||
return JsonResponse(result)
|
||||
|
||||
|
||||
@login_required
|
||||
def search_json(request):
|
||||
result = {
|
||||
'users': search_user(request.GET.get('query', ''), True),
|
||||
'clubs': search_club(request.GET.get('query', ''), True),
|
||||
"users": search_user(request.GET.get("query", ""), True),
|
||||
"clubs": search_club(request.GET.get("query", ""), True),
|
||||
}
|
||||
return JsonResponse(result)
|
||||
|
||||
@ -116,8 +122,8 @@ class ToMarkdownView(TemplateView):
|
||||
template_name = "core/to_markdown.jinja"
|
||||
|
||||
def post(self, request, *args, **kwargs):
|
||||
self.text = request.POST['text']
|
||||
if request.POST['syntax'] == "doku":
|
||||
self.text = request.POST["text"]
|
||||
if request.POST["syntax"] == "doku":
|
||||
self.text_md = doku_to_markdown(self.text)
|
||||
else:
|
||||
self.text_md = bbcode_to_markdown(self.text)
|
||||
@ -127,9 +133,9 @@ class ToMarkdownView(TemplateView):
|
||||
def get_context_data(self, **kwargs):
|
||||
kwargs = super(ToMarkdownView, self).get_context_data(**kwargs)
|
||||
try:
|
||||
kwargs['text'] = self.text
|
||||
kwargs['text_md'] = self.text_md
|
||||
kwargs["text"] = self.text
|
||||
kwargs["text_md"] = self.text_md
|
||||
except:
|
||||
kwargs['text'] = ""
|
||||
kwargs['text_md'] = ""
|
||||
kwargs["text"] = ""
|
||||
kwargs["text_md"] = ""
|
||||
return kwargs
|
||||
|
@ -31,7 +31,13 @@ from django.core.urlresolvers import reverse
|
||||
from django.core.exceptions import PermissionDenied, ValidationError
|
||||
from django.http import Http404, HttpResponse
|
||||
from django.views.generic.edit import UpdateView
|
||||
from django.views.generic import ListView, DetailView, TemplateView, CreateView, DeleteView
|
||||
from django.views.generic import (
|
||||
ListView,
|
||||
DetailView,
|
||||
TemplateView,
|
||||
CreateView,
|
||||
DeleteView,
|
||||
)
|
||||
from django.forms.models import modelform_factory
|
||||
from django.forms import CheckboxSelectMultiple
|
||||
from django.core.urlresolvers import reverse_lazy
|
||||
@ -42,8 +48,20 @@ from django.views.generic.dates import YearMixin, MonthMixin
|
||||
from datetime import timedelta, date
|
||||
import logging
|
||||
|
||||
from core.views import CanViewMixin, CanEditMixin, CanEditPropMixin, TabedViewMixin, QuickNotifMixin
|
||||
from core.views.forms import RegisteringForm, UserProfileForm, LoginForm, UserGodfathersForm, GiftForm
|
||||
from core.views import (
|
||||
CanViewMixin,
|
||||
CanEditMixin,
|
||||
CanEditPropMixin,
|
||||
TabedViewMixin,
|
||||
QuickNotifMixin,
|
||||
)
|
||||
from core.views.forms import (
|
||||
RegisteringForm,
|
||||
UserProfileForm,
|
||||
LoginForm,
|
||||
UserGodfathersForm,
|
||||
GiftForm,
|
||||
)
|
||||
from core.models import User, SithFile, Preferences, Gift
|
||||
from subscription.models import Subscription
|
||||
from trombi.views import UserTrombiForm
|
||||
@ -55,7 +73,9 @@ def login(request):
|
||||
|
||||
Needs to be improve with correct handling of form exceptions
|
||||
"""
|
||||
return views.login(request, template_name="core/login.jinja", authentication_form=LoginForm)
|
||||
return views.login(
|
||||
request, template_name="core/login.jinja", authentication_form=LoginForm
|
||||
)
|
||||
|
||||
|
||||
def logout(request):
|
||||
@ -69,14 +89,20 @@ def password_change(request):
|
||||
"""
|
||||
Allows a user to change its password
|
||||
"""
|
||||
return views.password_change(request, template_name="core/password_change.jinja", post_change_redirect=reverse("core:password_change_done"))
|
||||
return views.password_change(
|
||||
request,
|
||||
template_name="core/password_change.jinja",
|
||||
post_change_redirect=reverse("core:password_change_done"),
|
||||
)
|
||||
|
||||
|
||||
def password_change_done(request):
|
||||
"""
|
||||
Allows a user to change its password
|
||||
"""
|
||||
return views.password_change_done(request, template_name="core/password_change_done.jinja")
|
||||
return views.password_change_done(
|
||||
request, template_name="core/password_change_done.jinja"
|
||||
)
|
||||
|
||||
|
||||
def password_root_change(request, user_id):
|
||||
@ -95,62 +121,74 @@ def password_root_change(request, user_id):
|
||||
return redirect("core:password_change_done")
|
||||
else:
|
||||
form = views.SetPasswordForm(user=user)
|
||||
return TemplateResponse(request, "core/password_change.jinja", {'form': form, 'target': user})
|
||||
return TemplateResponse(
|
||||
request, "core/password_change.jinja", {"form": form, "target": user}
|
||||
)
|
||||
|
||||
|
||||
def password_reset(request):
|
||||
"""
|
||||
Allows someone to enter an email adresse for resetting password
|
||||
"""
|
||||
return views.password_reset(request,
|
||||
template_name="core/password_reset.jinja",
|
||||
email_template_name="core/password_reset_email.jinja",
|
||||
post_reset_redirect="core:password_reset_done",
|
||||
)
|
||||
return views.password_reset(
|
||||
request,
|
||||
template_name="core/password_reset.jinja",
|
||||
email_template_name="core/password_reset_email.jinja",
|
||||
post_reset_redirect="core:password_reset_done",
|
||||
)
|
||||
|
||||
|
||||
def password_reset_done(request):
|
||||
"""
|
||||
Confirm that the reset email has been sent
|
||||
"""
|
||||
return views.password_reset_done(request, template_name="core/password_reset_done.jinja")
|
||||
return views.password_reset_done(
|
||||
request, template_name="core/password_reset_done.jinja"
|
||||
)
|
||||
|
||||
|
||||
def password_reset_confirm(request, uidb64=None, token=None):
|
||||
"""
|
||||
Provide a reset password formular
|
||||
"""
|
||||
return views.password_reset_confirm(request, uidb64=uidb64, token=token,
|
||||
post_reset_redirect="core:password_reset_complete",
|
||||
template_name="core/password_reset_confirm.jinja",
|
||||
)
|
||||
return views.password_reset_confirm(
|
||||
request,
|
||||
uidb64=uidb64,
|
||||
token=token,
|
||||
post_reset_redirect="core:password_reset_complete",
|
||||
template_name="core/password_reset_confirm.jinja",
|
||||
)
|
||||
|
||||
|
||||
def password_reset_complete(request):
|
||||
"""
|
||||
Confirm the password has sucessfully been reset
|
||||
"""
|
||||
return views.password_reset_complete(request,
|
||||
template_name="core/password_reset_complete.jinja",
|
||||
)
|
||||
return views.password_reset_complete(
|
||||
request, template_name="core/password_reset_complete.jinja"
|
||||
)
|
||||
|
||||
|
||||
def register(request):
|
||||
context = {}
|
||||
if request.method == 'POST':
|
||||
if request.method == "POST":
|
||||
form = RegisteringForm(request.POST)
|
||||
if form.is_valid():
|
||||
logging.debug("Registering " + form.cleaned_data['first_name'] + form.cleaned_data['last_name'])
|
||||
logging.debug(
|
||||
"Registering "
|
||||
+ form.cleaned_data["first_name"]
|
||||
+ form.cleaned_data["last_name"]
|
||||
)
|
||||
u = form.save()
|
||||
context['user_registered'] = u
|
||||
context['tests'] = 'TEST_REGISTER_USER_FORM_OK'
|
||||
context["user_registered"] = u
|
||||
context["tests"] = "TEST_REGISTER_USER_FORM_OK"
|
||||
form = RegisteringForm()
|
||||
else:
|
||||
context['error'] = 'Erreur'
|
||||
context['tests'] = 'TEST_REGISTER_USER_FORM_FAIL'
|
||||
context["error"] = "Erreur"
|
||||
context["tests"] = "TEST_REGISTER_USER_FORM_FAIL"
|
||||
else:
|
||||
form = RegisteringForm()
|
||||
context['form'] = form.as_p()
|
||||
context["form"] = form.as_p()
|
||||
return render(request, "core/register.jinja", context)
|
||||
|
||||
|
||||
@ -160,65 +198,103 @@ class UserTabsMixin(TabedViewMixin):
|
||||
|
||||
def get_list_of_tabs(self):
|
||||
tab_list = []
|
||||
tab_list.append({
|
||||
'url': reverse('core:user_profile', kwargs={'user_id': self.object.id}),
|
||||
'slug': 'infos',
|
||||
'name': _("Infos"),
|
||||
})
|
||||
tab_list.append({
|
||||
'url': reverse('core:user_godfathers', kwargs={'user_id': self.object.id}),
|
||||
'slug': 'godfathers',
|
||||
'name': _("Godfathers"),
|
||||
})
|
||||
tab_list.append({
|
||||
'url': reverse('core:user_pictures', kwargs={'user_id': self.object.id}),
|
||||
'slug': 'pictures',
|
||||
'name': _("Pictures"),
|
||||
})
|
||||
tab_list.append(
|
||||
{
|
||||
"url": reverse("core:user_profile", kwargs={"user_id": self.object.id}),
|
||||
"slug": "infos",
|
||||
"name": _("Infos"),
|
||||
}
|
||||
)
|
||||
tab_list.append(
|
||||
{
|
||||
"url": reverse(
|
||||
"core:user_godfathers", kwargs={"user_id": self.object.id}
|
||||
),
|
||||
"slug": "godfathers",
|
||||
"name": _("Godfathers"),
|
||||
}
|
||||
)
|
||||
tab_list.append(
|
||||
{
|
||||
"url": reverse(
|
||||
"core:user_pictures", kwargs={"user_id": self.object.id}
|
||||
),
|
||||
"slug": "pictures",
|
||||
"name": _("Pictures"),
|
||||
}
|
||||
)
|
||||
if self.request.user == self.object:
|
||||
tab_list.append({
|
||||
'url': reverse('core:user_tools'),
|
||||
'slug': 'tools',
|
||||
'name': _("Tools"),
|
||||
})
|
||||
tab_list.append(
|
||||
{"url": reverse("core:user_tools"), "slug": "tools", "name": _("Tools")}
|
||||
)
|
||||
if self.request.user.can_edit(self.object):
|
||||
tab_list.append({
|
||||
'url': reverse('core:user_edit', kwargs={'user_id': self.object.id}),
|
||||
'slug': 'edit',
|
||||
'name': _("Edit"),
|
||||
})
|
||||
tab_list.append({
|
||||
'url': reverse('core:user_prefs', kwargs={'user_id': self.object.id}),
|
||||
'slug': 'prefs',
|
||||
'name': _("Preferences"),
|
||||
})
|
||||
tab_list.append(
|
||||
{
|
||||
"url": reverse(
|
||||
"core:user_edit", kwargs={"user_id": self.object.id}
|
||||
),
|
||||
"slug": "edit",
|
||||
"name": _("Edit"),
|
||||
}
|
||||
)
|
||||
tab_list.append(
|
||||
{
|
||||
"url": reverse(
|
||||
"core:user_prefs", kwargs={"user_id": self.object.id}
|
||||
),
|
||||
"slug": "prefs",
|
||||
"name": _("Preferences"),
|
||||
}
|
||||
)
|
||||
if self.request.user.can_view(self.object):
|
||||
tab_list.append({
|
||||
'url': reverse('core:user_clubs', kwargs={'user_id': self.object.id}),
|
||||
'slug': 'clubs',
|
||||
'name': _("Clubs"),
|
||||
})
|
||||
tab_list.append(
|
||||
{
|
||||
"url": reverse(
|
||||
"core:user_clubs", kwargs={"user_id": self.object.id}
|
||||
),
|
||||
"slug": "clubs",
|
||||
"name": _("Clubs"),
|
||||
}
|
||||
)
|
||||
if self.request.user.is_owner(self.object):
|
||||
tab_list.append({
|
||||
'url': reverse('core:user_groups', kwargs={'user_id': self.object.id}),
|
||||
'slug': 'groups',
|
||||
'name': _("Groups"),
|
||||
})
|
||||
tab_list.append(
|
||||
{
|
||||
"url": reverse(
|
||||
"core:user_groups", kwargs={"user_id": self.object.id}
|
||||
),
|
||||
"slug": "groups",
|
||||
"name": _("Groups"),
|
||||
}
|
||||
)
|
||||
try:
|
||||
if (self.object.customer and (self.object == self.request.user
|
||||
or self.request.user.is_in_group(settings.SITH_GROUP_ACCOUNTING_ADMIN_ID)
|
||||
or self.request.user.is_in_group(settings.SITH_BAR_MANAGER['unix_name'] + settings.SITH_BOARD_SUFFIX)
|
||||
or self.request.user.is_root)):
|
||||
tab_list.append({
|
||||
'url': reverse('core:user_stats', kwargs={'user_id': self.object.id}),
|
||||
'slug': 'stats',
|
||||
'name': _("Stats"),
|
||||
})
|
||||
tab_list.append({
|
||||
'url': reverse('core:user_account', kwargs={'user_id': self.object.id}),
|
||||
'slug': 'account',
|
||||
'name': _("Account") + " (%s €)" % self.object.customer.amount,
|
||||
})
|
||||
if self.object.customer and (
|
||||
self.object == self.request.user
|
||||
or self.request.user.is_in_group(
|
||||
settings.SITH_GROUP_ACCOUNTING_ADMIN_ID
|
||||
)
|
||||
or self.request.user.is_in_group(
|
||||
settings.SITH_BAR_MANAGER["unix_name"] + settings.SITH_BOARD_SUFFIX
|
||||
)
|
||||
or self.request.user.is_root
|
||||
):
|
||||
tab_list.append(
|
||||
{
|
||||
"url": reverse(
|
||||
"core:user_stats", kwargs={"user_id": self.object.id}
|
||||
),
|
||||
"slug": "stats",
|
||||
"name": _("Stats"),
|
||||
}
|
||||
)
|
||||
tab_list.append(
|
||||
{
|
||||
"url": reverse(
|
||||
"core:user_account", kwargs={"user_id": self.object.id}
|
||||
),
|
||||
"slug": "account",
|
||||
"name": _("Account") + " (%s €)" % self.object.customer.amount,
|
||||
}
|
||||
)
|
||||
except:
|
||||
pass
|
||||
return tab_list
|
||||
@ -228,15 +304,18 @@ class UserView(UserTabsMixin, CanViewMixin, DetailView):
|
||||
"""
|
||||
Display a user's profile
|
||||
"""
|
||||
|
||||
model = User
|
||||
pk_url_kwarg = "user_id"
|
||||
context_object_name = "profile"
|
||||
template_name = "core/user_detail.jinja"
|
||||
current_tab = 'infos'
|
||||
current_tab = "infos"
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
kwargs = super(UserView, self).get_context_data(**kwargs)
|
||||
kwargs['gift_form'] = GiftForm(user_id=self.object.id, initial={'user': self.object})
|
||||
kwargs["gift_form"] = GiftForm(
|
||||
user_id=self.object.id, initial={"user": self.object}
|
||||
)
|
||||
return kwargs
|
||||
|
||||
|
||||
@ -244,33 +323,36 @@ class UserPicturesView(UserTabsMixin, CanViewMixin, DetailView):
|
||||
"""
|
||||
Display a user's pictures
|
||||
"""
|
||||
|
||||
model = User
|
||||
pk_url_kwarg = "user_id"
|
||||
context_object_name = "profile"
|
||||
template_name = "core/user_pictures.jinja"
|
||||
current_tab = 'pictures'
|
||||
current_tab = "pictures"
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
kwargs = super(UserPicturesView, self).get_context_data(**kwargs)
|
||||
kwargs['albums'] = []
|
||||
kwargs['pictures'] = {}
|
||||
picture_qs = self.object.pictures.exclude(picture=None).order_by('-picture__parent__date', 'id').select_related('picture__parent')
|
||||
kwargs["albums"] = []
|
||||
kwargs["pictures"] = {}
|
||||
picture_qs = (
|
||||
self.object.pictures.exclude(picture=None)
|
||||
.order_by("-picture__parent__date", "id")
|
||||
.select_related("picture__parent")
|
||||
)
|
||||
last_album = None
|
||||
for pict_relation in picture_qs:
|
||||
album = pict_relation.picture.parent
|
||||
if album.id != last_album:
|
||||
kwargs['albums'].append(album)
|
||||
kwargs['pictures'][album.id] = []
|
||||
kwargs["albums"].append(album)
|
||||
kwargs["pictures"][album.id] = []
|
||||
last_album = album.id
|
||||
kwargs['pictures'][album.id].append(pict_relation.picture)
|
||||
kwargs["pictures"][album.id].append(pict_relation.picture)
|
||||
return kwargs
|
||||
|
||||
|
||||
def DeleteUserGodfathers(request, user_id, godfather_id, is_father):
|
||||
user = User.objects.get(id=user_id)
|
||||
if ((user == request.user) or
|
||||
request.user.is_root or
|
||||
request.user.is_board_member):
|
||||
if (user == request.user) or request.user.is_root or request.user.is_board_member:
|
||||
ud = get_object_or_404(User, id=godfather_id)
|
||||
if is_father == "True":
|
||||
user.godfathers.remove(ud)
|
||||
@ -278,28 +360,29 @@ def DeleteUserGodfathers(request, user_id, godfather_id, is_father):
|
||||
user.godchildren.remove(ud)
|
||||
else:
|
||||
raise PermissionDenied
|
||||
return redirect('core:user_godfathers', user_id=user_id)
|
||||
return redirect("core:user_godfathers", user_id=user_id)
|
||||
|
||||
|
||||
class UserGodfathersView(UserTabsMixin, CanViewMixin, DetailView):
|
||||
"""
|
||||
Display a user's godfathers
|
||||
"""
|
||||
|
||||
model = User
|
||||
pk_url_kwarg = "user_id"
|
||||
context_object_name = "profile"
|
||||
template_name = "core/user_godfathers.jinja"
|
||||
current_tab = 'godfathers'
|
||||
current_tab = "godfathers"
|
||||
|
||||
def post(self, request, *args, **kwargs):
|
||||
self.object = self.get_object()
|
||||
self.form = UserGodfathersForm(request.POST)
|
||||
if self.form.is_valid() and self.form.cleaned_data['user'] != self.object:
|
||||
if self.form.cleaned_data['type'] == 'godfather':
|
||||
self.object.godfathers.add(self.form.cleaned_data['user'])
|
||||
if self.form.is_valid() and self.form.cleaned_data["user"] != self.object:
|
||||
if self.form.cleaned_data["type"] == "godfather":
|
||||
self.object.godfathers.add(self.form.cleaned_data["user"])
|
||||
self.object.save()
|
||||
else:
|
||||
self.object.godchildren.add(self.form.cleaned_data['user'])
|
||||
self.object.godchildren.add(self.form.cleaned_data["user"])
|
||||
self.object.save()
|
||||
self.form = UserGodfathersForm()
|
||||
return super(UserGodfathersView, self).get(request, *args, **kwargs)
|
||||
@ -307,39 +390,44 @@ class UserGodfathersView(UserTabsMixin, CanViewMixin, DetailView):
|
||||
def get_context_data(self, **kwargs):
|
||||
kwargs = super(UserGodfathersView, self).get_context_data(**kwargs)
|
||||
try:
|
||||
kwargs['form'] = self.form
|
||||
kwargs["form"] = self.form
|
||||
except:
|
||||
kwargs['form'] = UserGodfathersForm()
|
||||
kwargs["form"] = UserGodfathersForm()
|
||||
return kwargs
|
||||
|
||||
|
||||
class UserGodfathersTreeView(UserTabsMixin, CanViewMixin, DetailView):
|
||||
"""
|
||||
Display a user's family tree
|
||||
"""
|
||||
|
||||
model = User
|
||||
pk_url_kwarg = "user_id"
|
||||
context_object_name = "profile"
|
||||
template_name = "core/user_godfathers_tree.jinja"
|
||||
current_tab = 'godfathers'
|
||||
current_tab = "godfathers"
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
kwargs = super(UserGodfathersTreeView, self).get_context_data(**kwargs)
|
||||
if "descent" in self.request.GET:
|
||||
kwargs['param'] = "godchildren"
|
||||
kwargs["param"] = "godchildren"
|
||||
else:
|
||||
kwargs['param'] = "godfathers"
|
||||
kwargs['members_set'] = set()
|
||||
kwargs["param"] = "godfathers"
|
||||
kwargs["members_set"] = set()
|
||||
return kwargs
|
||||
|
||||
|
||||
class UserGodfathersTreePictureView(CanViewMixin, DetailView):
|
||||
"""
|
||||
Display a user's tree as a picture
|
||||
"""
|
||||
|
||||
model = User
|
||||
pk_url_kwarg = "user_id"
|
||||
|
||||
def build_complex_graph(self):
|
||||
import pygraphviz as pgv
|
||||
|
||||
self.depth = int(self.request.GET.get("depth", 4))
|
||||
if self.param == "godfathers":
|
||||
self.graph = pgv.AGraph(strict=False, directed=True, rankdir="BT")
|
||||
@ -349,7 +437,8 @@ class UserGodfathersTreePictureView(CanViewMixin, DetailView):
|
||||
self.level = 1
|
||||
# Since the tree isn't very deep, we can build it recursively
|
||||
def crawl_family(user):
|
||||
if self.level > self.depth: return
|
||||
if self.level > self.depth:
|
||||
return
|
||||
self.level += 1
|
||||
for u in user.__getattribute__(self.param).all():
|
||||
self.graph.add_edge(user.get_short_name(), u.get_short_name())
|
||||
@ -357,12 +446,14 @@ class UserGodfathersTreePictureView(CanViewMixin, DetailView):
|
||||
family.add(u)
|
||||
crawl_family(u)
|
||||
self.level -= 1
|
||||
|
||||
self.graph.add_node(self.object.get_short_name())
|
||||
family.add(self.object)
|
||||
crawl_family(self.object)
|
||||
|
||||
def build_family_graph(self):
|
||||
import pygraphviz as pgv
|
||||
|
||||
self.graph = pgv.AGraph(strict=False, directed=True)
|
||||
self.graph.add_node(self.object.get_short_name())
|
||||
for u in self.object.godfathers.all():
|
||||
@ -384,29 +475,31 @@ class UserGodfathersTreePictureView(CanViewMixin, DetailView):
|
||||
else:
|
||||
self.build_complex_graph()
|
||||
# Pimp the graph before display
|
||||
self.graph.node_attr['color'] = "lightblue"
|
||||
self.graph.node_attr['style'] = "filled"
|
||||
self.graph.node_attr["color"] = "lightblue"
|
||||
self.graph.node_attr["style"] = "filled"
|
||||
main_node = self.graph.get_node(self.object.get_short_name())
|
||||
main_node.attr['color'] = "sandybrown"
|
||||
main_node.attr['shape'] = "rect"
|
||||
main_node.attr["color"] = "sandybrown"
|
||||
main_node.attr["shape"] = "rect"
|
||||
if self.param == "godchildren":
|
||||
self.graph.graph_attr['label'] = _("Godchildren")
|
||||
self.graph.graph_attr["label"] = _("Godchildren")
|
||||
elif self.param == "godfathers":
|
||||
self.graph.graph_attr['label'] = _("Godfathers")
|
||||
self.graph.graph_attr["label"] = _("Godfathers")
|
||||
else:
|
||||
self.graph.graph_attr['label'] = _("Family")
|
||||
self.graph.graph_attr["label"] = _("Family")
|
||||
img = self.graph.draw(format="png", prog="dot")
|
||||
return HttpResponse(img, content_type="image/png")
|
||||
|
||||
|
||||
class UserStatsView(UserTabsMixin, CanViewMixin, DetailView):
|
||||
"""
|
||||
Display a user's stats
|
||||
"""
|
||||
|
||||
model = User
|
||||
pk_url_kwarg = "user_id"
|
||||
context_object_name = "profile"
|
||||
template_name = "core/user_stats.jinja"
|
||||
current_tab = 'stats'
|
||||
current_tab = "stats"
|
||||
|
||||
def dispatch(self, request, *arg, **kwargs):
|
||||
profile = self.get_object()
|
||||
@ -414,10 +507,14 @@ class UserStatsView(UserTabsMixin, CanViewMixin, DetailView):
|
||||
if not hasattr(profile, "customer"):
|
||||
raise Http404
|
||||
|
||||
if not (profile == request.user
|
||||
or request.user.is_in_group(settings.SITH_GROUP_ACCOUNTING_ADMIN_ID)
|
||||
or request.user.is_in_group(settings.SITH_BAR_MANAGER['unix_name'] + settings.SITH_BOARD_SUFFIX)
|
||||
or request.user.is_root):
|
||||
if not (
|
||||
profile == request.user
|
||||
or request.user.is_in_group(settings.SITH_GROUP_ACCOUNTING_ADMIN_ID)
|
||||
or request.user.is_in_group(
|
||||
settings.SITH_BAR_MANAGER["unix_name"] + settings.SITH_BOARD_SUFFIX
|
||||
)
|
||||
or request.user.is_root
|
||||
):
|
||||
raise PermissionDenied
|
||||
|
||||
return super(UserStatsView, self).dispatch(request, *arg, **kwargs)
|
||||
@ -426,22 +523,71 @@ class UserStatsView(UserTabsMixin, CanViewMixin, DetailView):
|
||||
kwargs = super(UserStatsView, self).get_context_data(**kwargs)
|
||||
from counter.models import Counter
|
||||
from django.db.models import Sum
|
||||
|
||||
foyer = Counter.objects.filter(name="Foyer").first()
|
||||
mde = Counter.objects.filter(name="MDE").first()
|
||||
gommette = Counter.objects.filter(name="La Gommette").first()
|
||||
semester_start = Subscription.compute_start(d=date.today(), duration=3)
|
||||
kwargs['total_perm_time'] = sum([p.end - p.start for p in self.object.permanencies.exclude(end=None)], timedelta())
|
||||
kwargs['total_foyer_time'] = sum([p.end - p.start for p in self.object.permanencies.filter(counter=foyer).exclude(end=None)], timedelta())
|
||||
kwargs['total_mde_time'] = sum([p.end - p.start for p in self.object.permanencies.filter(counter=mde).exclude(end=None)], timedelta())
|
||||
kwargs['total_gommette_time'] = sum([p.end - p.start for p in self.object.permanencies.filter(counter=gommette).exclude(end=None)], timedelta())
|
||||
kwargs['total_foyer_buyings'] = sum([b.unit_price * b.quantity for b in
|
||||
self.object.customer.buyings.filter(counter=foyer, date__gte=semester_start)])
|
||||
kwargs['total_mde_buyings'] = sum([b.unit_price * b.quantity for b in self.object.customer.buyings.filter(counter=mde,
|
||||
date__gte=semester_start)])
|
||||
kwargs['total_gommette_buyings'] = sum([b.unit_price * b.quantity for b in
|
||||
self.object.customer.buyings.filter(counter=gommette, date__gte=semester_start)])
|
||||
kwargs['top_product'] = self.object.customer.buyings.values('product__name').annotate(
|
||||
product_sum=Sum('quantity')).exclude(product_sum=None).order_by('-product_sum').all()[:10]
|
||||
kwargs["total_perm_time"] = sum(
|
||||
[p.end - p.start for p in self.object.permanencies.exclude(end=None)],
|
||||
timedelta(),
|
||||
)
|
||||
kwargs["total_foyer_time"] = sum(
|
||||
[
|
||||
p.end - p.start
|
||||
for p in self.object.permanencies.filter(counter=foyer).exclude(
|
||||
end=None
|
||||
)
|
||||
],
|
||||
timedelta(),
|
||||
)
|
||||
kwargs["total_mde_time"] = sum(
|
||||
[
|
||||
p.end - p.start
|
||||
for p in self.object.permanencies.filter(counter=mde).exclude(end=None)
|
||||
],
|
||||
timedelta(),
|
||||
)
|
||||
kwargs["total_gommette_time"] = sum(
|
||||
[
|
||||
p.end - p.start
|
||||
for p in self.object.permanencies.filter(counter=gommette).exclude(
|
||||
end=None
|
||||
)
|
||||
],
|
||||
timedelta(),
|
||||
)
|
||||
kwargs["total_foyer_buyings"] = sum(
|
||||
[
|
||||
b.unit_price * b.quantity
|
||||
for b in self.object.customer.buyings.filter(
|
||||
counter=foyer, date__gte=semester_start
|
||||
)
|
||||
]
|
||||
)
|
||||
kwargs["total_mde_buyings"] = sum(
|
||||
[
|
||||
b.unit_price * b.quantity
|
||||
for b in self.object.customer.buyings.filter(
|
||||
counter=mde, date__gte=semester_start
|
||||
)
|
||||
]
|
||||
)
|
||||
kwargs["total_gommette_buyings"] = sum(
|
||||
[
|
||||
b.unit_price * b.quantity
|
||||
for b in self.object.customer.buyings.filter(
|
||||
counter=gommette, date__gte=semester_start
|
||||
)
|
||||
]
|
||||
)
|
||||
kwargs["top_product"] = (
|
||||
self.object.customer.buyings.values("product__name")
|
||||
.annotate(product_sum=Sum("quantity"))
|
||||
.exclude(product_sum=None)
|
||||
.order_by("-product_sum")
|
||||
.all()[:10]
|
||||
)
|
||||
return kwargs
|
||||
|
||||
|
||||
@ -449,6 +595,7 @@ class UserMiniView(CanViewMixin, DetailView):
|
||||
"""
|
||||
Display a user's profile
|
||||
"""
|
||||
|
||||
model = User
|
||||
pk_url_kwarg = "user_id"
|
||||
context_object_name = "profile"
|
||||
@ -459,6 +606,7 @@ class UserListView(ListView, CanEditPropMixin):
|
||||
"""
|
||||
Displays the user list
|
||||
"""
|
||||
|
||||
model = User
|
||||
template_name = "core/user_list.jinja"
|
||||
|
||||
@ -467,6 +615,7 @@ class UserUploadProfilePictView(CanEditMixin, DetailView):
|
||||
"""
|
||||
Handle the upload of the profile picture taken with webcam in navigator
|
||||
"""
|
||||
|
||||
model = User
|
||||
pk_url_kwarg = "user_id"
|
||||
template_name = "core/user_edit.jinja"
|
||||
@ -475,16 +624,23 @@ class UserUploadProfilePictView(CanEditMixin, DetailView):
|
||||
from core.utils import resize_image
|
||||
from io import BytesIO
|
||||
from PIL import Image
|
||||
|
||||
self.object = self.get_object()
|
||||
if self.object.profile_pict:
|
||||
raise ValidationError(_("User already has a profile picture"))
|
||||
f = request.FILES['new_profile_pict']
|
||||
f = request.FILES["new_profile_pict"]
|
||||
parent = SithFile.objects.filter(parent=None, name="profiles").first()
|
||||
name = str(self.object.id) + "_profile.jpg" # Webcamejs uploads JPGs
|
||||
im = Image.open(BytesIO(f.read()))
|
||||
new_file = SithFile(parent=parent, name=name,
|
||||
file=resize_image(im, 400, f.content_type.split('/')[-1]),
|
||||
owner=self.object, is_folder=False, mime_type=f.content_type, size=f._size)
|
||||
new_file = SithFile(
|
||||
parent=parent,
|
||||
name=name,
|
||||
file=resize_image(im, 400, f.content_type.split("/")[-1]),
|
||||
owner=self.object,
|
||||
is_folder=False,
|
||||
mime_type=f.content_type,
|
||||
size=f._size,
|
||||
)
|
||||
new_file.file.name = name
|
||||
new_file.save()
|
||||
self.object.profile_pict = new_file
|
||||
@ -496,12 +652,13 @@ class UserUpdateProfileView(UserTabsMixin, CanEditMixin, UpdateView):
|
||||
"""
|
||||
Edit a user's profile
|
||||
"""
|
||||
|
||||
model = User
|
||||
pk_url_kwarg = "user_id"
|
||||
template_name = "core/user_edit.jinja"
|
||||
form_class = UserProfileForm
|
||||
current_tab = "edit"
|
||||
edit_once = ['profile_pict', 'date_of_birth', 'first_name', 'last_name']
|
||||
edit_once = ["profile_pict", "date_of_birth", "first_name", "last_name"]
|
||||
board_only = []
|
||||
|
||||
def remove_restricted_fields(self, request):
|
||||
@ -509,7 +666,9 @@ class UserUpdateProfileView(UserTabsMixin, CanEditMixin, UpdateView):
|
||||
Removes edit_once and board_only fields
|
||||
"""
|
||||
for i in self.edit_once:
|
||||
if getattr(self.form.instance, i) and not (request.user.is_board_member or request.user.is_root):
|
||||
if getattr(self.form.instance, i) and not (
|
||||
request.user.is_board_member or request.user.is_root
|
||||
):
|
||||
self.form.fields.pop(i, None)
|
||||
for i in self.board_only:
|
||||
if not (request.user.is_board_member or request.user.is_root):
|
||||
@ -527,14 +686,18 @@ class UserUpdateProfileView(UserTabsMixin, CanEditMixin, UpdateView):
|
||||
self.remove_restricted_fields(request)
|
||||
files = request.FILES.items()
|
||||
self.form.process(files)
|
||||
if request.user.is_authenticated() and request.user.can_edit(self.object) and self.form.is_valid():
|
||||
if (
|
||||
request.user.is_authenticated()
|
||||
and request.user.can_edit(self.object)
|
||||
and self.form.is_valid()
|
||||
):
|
||||
return super(UserUpdateProfileView, self).form_valid(self.form)
|
||||
return self.form_invalid(self.form)
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
kwargs = super(UserUpdateProfileView, self).get_context_data(**kwargs)
|
||||
kwargs['profile'] = self.form.instance
|
||||
kwargs['form'] = self.form
|
||||
kwargs["profile"] = self.form.instance
|
||||
kwargs["form"] = self.form
|
||||
return kwargs
|
||||
|
||||
|
||||
@ -542,6 +705,7 @@ class UserClubView(UserTabsMixin, CanViewMixin, DetailView):
|
||||
"""
|
||||
Display the user's club(s)
|
||||
"""
|
||||
|
||||
model = User
|
||||
context_object_name = "profile"
|
||||
pk_url_kwarg = "user_id"
|
||||
@ -553,28 +717,30 @@ class UserPreferencesView(UserTabsMixin, CanEditMixin, UpdateView):
|
||||
"""
|
||||
Edit a user's preferences
|
||||
"""
|
||||
|
||||
model = User
|
||||
pk_url_kwarg = "user_id"
|
||||
template_name = "core/user_preferences.jinja"
|
||||
form_class = modelform_factory(Preferences, fields=['receive_weekmail',
|
||||
'notify_on_click', 'notify_on_refill'])
|
||||
form_class = modelform_factory(
|
||||
Preferences, fields=["receive_weekmail", "notify_on_click", "notify_on_refill"]
|
||||
)
|
||||
context_object_name = "profile"
|
||||
current_tab = "prefs"
|
||||
|
||||
def get_object(self, queryset=None):
|
||||
user = get_object_or_404(User, pk=self.kwargs['user_id'])
|
||||
user = get_object_or_404(User, pk=self.kwargs["user_id"])
|
||||
return user
|
||||
|
||||
def get_form_kwargs(self):
|
||||
kwargs = super(UserPreferencesView, self).get_form_kwargs()
|
||||
pref = self.object.preferences
|
||||
kwargs.update({'instance': pref})
|
||||
kwargs.update({"instance": pref})
|
||||
return kwargs
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
kwargs = super(UserPreferencesView, self).get_context_data(**kwargs)
|
||||
if not hasattr(self.object, 'trombi_user'):
|
||||
kwargs['trombi_form'] = UserTrombiForm()
|
||||
if not hasattr(self.object, "trombi_user"):
|
||||
kwargs["trombi_form"] = UserTrombiForm()
|
||||
return kwargs
|
||||
|
||||
|
||||
@ -582,11 +748,13 @@ class UserUpdateGroupView(UserTabsMixin, CanEditPropMixin, UpdateView):
|
||||
"""
|
||||
Edit a user's groups
|
||||
"""
|
||||
|
||||
model = User
|
||||
pk_url_kwarg = "user_id"
|
||||
template_name = "core/user_group.jinja"
|
||||
form_class = modelform_factory(User, fields=['groups'],
|
||||
widgets={'groups': CheckboxSelectMultiple})
|
||||
form_class = modelform_factory(
|
||||
User, fields=["groups"], widgets={"groups": CheckboxSelectMultiple}
|
||||
)
|
||||
context_object_name = "profile"
|
||||
current_tab = "groups"
|
||||
|
||||
@ -595,16 +763,18 @@ class UserToolsView(QuickNotifMixin, UserTabsMixin, TemplateView):
|
||||
"""
|
||||
Displays the logged user's tools
|
||||
"""
|
||||
|
||||
template_name = "core/user_tools.jinja"
|
||||
current_tab = "tools"
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
self.object = self.request.user
|
||||
from launderette.models import Launderette
|
||||
|
||||
kwargs = super(UserToolsView, self).get_context_data(**kwargs)
|
||||
kwargs['launderettes'] = Launderette.objects.all()
|
||||
kwargs['profile'] = self.request.user
|
||||
kwargs['object'] = self.request.user
|
||||
kwargs["launderettes"] = Launderette.objects.all()
|
||||
kwargs["profile"] = self.request.user
|
||||
kwargs["object"] = self.request.user
|
||||
return kwargs
|
||||
|
||||
|
||||
@ -612,16 +782,21 @@ class UserAccountBase(UserTabsMixin, DetailView):
|
||||
"""
|
||||
Base class for UserAccount
|
||||
"""
|
||||
|
||||
model = User
|
||||
pk_url_kwarg = "user_id"
|
||||
current_tab = "account"
|
||||
|
||||
def dispatch(self, request, *arg, **kwargs): # Manually validates the rights
|
||||
res = super(UserAccountBase, self).dispatch(request, *arg, **kwargs)
|
||||
if (self.object == request.user
|
||||
or request.user.is_in_group(settings.SITH_GROUP_ACCOUNTING_ADMIN_ID)
|
||||
or request.user.is_in_group(settings.SITH_BAR_MANAGER['unix_name'] + settings.SITH_BOARD_SUFFIX)
|
||||
or request.user.is_root):
|
||||
if (
|
||||
self.object == request.user
|
||||
or request.user.is_in_group(settings.SITH_GROUP_ACCOUNTING_ADMIN_ID)
|
||||
or request.user.is_in_group(
|
||||
settings.SITH_BAR_MANAGER["unix_name"] + settings.SITH_BOARD_SUFFIX
|
||||
)
|
||||
or request.user.is_root
|
||||
):
|
||||
return res
|
||||
raise PermissionDenied
|
||||
|
||||
@ -630,24 +805,20 @@ class UserAccountView(UserAccountBase):
|
||||
"""
|
||||
Display a user's account
|
||||
"""
|
||||
|
||||
template_name = "core/user_account.jinja"
|
||||
|
||||
def expense_by_month(self, obj, calc):
|
||||
stats = []
|
||||
|
||||
for year in obj.datetimes('date', 'year', order='DESC'):
|
||||
for year in obj.datetimes("date", "year", order="DESC"):
|
||||
stats.append([])
|
||||
i = 0
|
||||
for month in obj.filter(date__year=year.year).datetimes(
|
||||
'date', 'month', order='DESC'):
|
||||
q = obj.filter(
|
||||
date__year=month.year,
|
||||
date__month=month.month
|
||||
)
|
||||
stats[i].append({
|
||||
'sum': sum([calc(p) for p in q]),
|
||||
'date': month
|
||||
})
|
||||
"date", "month", order="DESC"
|
||||
):
|
||||
q = obj.filter(date__year=month.year, date__month=month.month)
|
||||
stats[i].append({"sum": sum([calc(p) for p in q]), "date": month})
|
||||
i += 1
|
||||
return stats
|
||||
|
||||
@ -659,22 +830,21 @@ class UserAccountView(UserAccountBase):
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
kwargs = super(UserAccountView, self).get_context_data(**kwargs)
|
||||
kwargs['profile'] = self.object
|
||||
kwargs["profile"] = self.object
|
||||
try:
|
||||
kwargs['customer'] = self.object.customer
|
||||
kwargs['buyings_month'] = self.expense_by_month(
|
||||
self.object.customer.buyings,
|
||||
(lambda q: q.unit_price * q.quantity)
|
||||
kwargs["customer"] = self.object.customer
|
||||
kwargs["buyings_month"] = self.expense_by_month(
|
||||
self.object.customer.buyings, (lambda q: q.unit_price * q.quantity)
|
||||
)
|
||||
kwargs['invoices_month'] = self.expense_by_month(
|
||||
self.object.customer.user.invoices,
|
||||
self.invoices_calc
|
||||
kwargs["invoices_month"] = self.expense_by_month(
|
||||
self.object.customer.user.invoices, self.invoices_calc
|
||||
)
|
||||
kwargs['refilling_month'] = self.expense_by_month(
|
||||
self.object.customer.refillings,
|
||||
(lambda q: q.amount)
|
||||
kwargs["refilling_month"] = self.expense_by_month(
|
||||
self.object.customer.refillings, (lambda q: q.amount)
|
||||
)
|
||||
kwargs['etickets'] = self.object.customer.buyings.exclude(product__eticket=None).all()
|
||||
kwargs["etickets"] = self.object.customer.buyings.exclude(
|
||||
product__eticket=None
|
||||
).all()
|
||||
except Exception as e:
|
||||
print(repr(e))
|
||||
return kwargs
|
||||
@ -684,51 +854,52 @@ class UserAccountDetailView(UserAccountBase, YearMixin, MonthMixin):
|
||||
"""
|
||||
Display a user's account for month
|
||||
"""
|
||||
|
||||
template_name = "core/user_account_detail.jinja"
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
kwargs = super(UserAccountDetailView, self).get_context_data(**kwargs)
|
||||
kwargs['profile'] = self.object
|
||||
kwargs['year'] = self.get_year()
|
||||
kwargs['month'] = self.get_month()
|
||||
kwargs["profile"] = self.object
|
||||
kwargs["year"] = self.get_year()
|
||||
kwargs["month"] = self.get_month()
|
||||
try:
|
||||
kwargs['customer'] = self.object.customer
|
||||
kwargs["customer"] = self.object.customer
|
||||
except:
|
||||
pass
|
||||
kwargs['tab'] = "account"
|
||||
kwargs["tab"] = "account"
|
||||
return kwargs
|
||||
|
||||
|
||||
class GiftCreateView(CreateView):
|
||||
form_class = GiftForm
|
||||
template_name = 'core/create.jinja'
|
||||
template_name = "core/create.jinja"
|
||||
|
||||
def dispatch(self, request, *args, **kwargs):
|
||||
if not (request.user.is_board_member or request.user.is_root):
|
||||
raise PermissionDenied
|
||||
self.user = get_object_or_404(User, pk=kwargs['user_id'])
|
||||
self.user = get_object_or_404(User, pk=kwargs["user_id"])
|
||||
return super(GiftCreateView, self).dispatch(request, *args, **kwargs)
|
||||
|
||||
def get_initial(self):
|
||||
return {'user': self.user}
|
||||
return {"user": self.user}
|
||||
|
||||
def get_form_kwargs(self):
|
||||
kwargs = super(GiftCreateView, self).get_form_kwargs()
|
||||
kwargs['user_id'] = self.user.id
|
||||
kwargs["user_id"] = self.user.id
|
||||
return kwargs
|
||||
|
||||
def get_success_url(self):
|
||||
return reverse_lazy('core:user_profile', kwargs={'user_id': self.user.id})
|
||||
return reverse_lazy("core:user_profile", kwargs={"user_id": self.user.id})
|
||||
|
||||
|
||||
class GiftDeleteView(CanEditPropMixin, DeleteView):
|
||||
model = Gift
|
||||
pk_url_kwarg = "gift_id"
|
||||
template_name = 'core/delete_confirm.jinja'
|
||||
template_name = "core/delete_confirm.jinja"
|
||||
|
||||
def dispatch(self, request, *args, **kwargs):
|
||||
self.user = get_object_or_404(User, pk=kwargs['user_id'])
|
||||
self.user = get_object_or_404(User, pk=kwargs["user_id"])
|
||||
return super(GiftDeleteView, self).dispatch(request, *args, **kwargs)
|
||||
|
||||
def get_success_url(self):
|
||||
return reverse_lazy('core:user_profile', kwargs={'user_id': self.user.id})
|
||||
return reverse_lazy("core:user_profile", kwargs={"user_id": self.user.id})
|
||||
|
Reference in New Issue
Block a user