All: Apply Black coding rules

This commit is contained in:
2018-10-04 21:29:19 +02:00
parent 0581c667de
commit cb58b00b6e
204 changed files with 13173 additions and 6376 deletions

View File

@ -22,4 +22,4 @@
#
#
default_app_config = 'core.apps.SithConfig'
default_app_config = "core.apps.SithConfig"

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -21,4 +21,3 @@
# Place - Suite 330, Boston, MA 02111-1307, USA.
#
#

View File

@ -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()

View File

@ -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"
)

View File

@ -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

View File

@ -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()

View File

@ -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")

View File

@ -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="")

View File

@ -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 "

View File

@ -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"
),
),
]

View File

@ -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),
)
]

View File

@ -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",
),
)
]

View File

@ -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
),
)
]

View File

@ -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",
),
),
]

View File

@ -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),
)
]

View File

@ -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"),
)
]

View File

@ -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,
),
),
]

View File

@ -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),
)
]

View File

@ -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,
),
),
]

View File

@ -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
),
),
],
),
)
]

View File

@ -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),
),
]

View File

@ -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"),
],
),
)
]

View File

@ -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,
),
)
]

View File

@ -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",
),
)
]

View File

@ -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),
)
]

View File

@ -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",
),
)
]

View File

@ -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"
),
)
]

View File

@ -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",
),
),
]

View File

@ -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"),
],
),
)
]

View File

@ -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",
),
)
]

View File

@ -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
),
),
]

View File

@ -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,
),
)
]

View File

@ -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.",
)
],
),
)
]

View File

@ -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",
),
)
]

View File

@ -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
),
),
],
),
)
]

View File

@ -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"),
],
),
)
]

View File

@ -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",
),
)
]

File diff suppressed because it is too large Load Diff

View File

@ -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)

View File

@ -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 []

View File

@ -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)

View File

@ -21,4 +21,3 @@
# Place - Suite 330, Boston, MA 02111-1307, USA.
#
#

View File

@ -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():

View File

@ -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&lt;guy&gt;Bibou&lt;/guy&gt;' +
"&lt;script&gt;alert(\\'Guy\\');&lt;/script&gt;" 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&lt;guy&gt;Bibou&lt;/guy&gt;"
+ "&lt;script&gt;alert(\\'Guy\\');&lt;/script&gt;"
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))

View File

@ -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",
),
]

View File

@ -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'![\2](\1 "\2")', text) # Images
text = re.sub(r'{{(.*?)(\|(.*?))?}}', r'![\1](\1 "\1")', 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'![\2](\1 "\2")', text) # Images
text = re.sub(r"{{(.*?)(\|(.*?))?}}", r'![\1](\1 "\1")', 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'![\1](\1 "\1")', 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'![\1](\1 "\1")', 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)

View File

@ -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 *

View File

@ -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")

View File

@ -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()

View File

@ -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")

View File

@ -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")

View File

@ -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

View File

@ -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})