mirror of
https://git.linux-kernel.at/oliver/ivatar.git
synced 2025-11-15 12:38:03 +00:00
Merge branch 'preferences' into 'master'
Feature: Userpreferences See merge request oliver/ivatar!24
This commit is contained in:
@@ -16,6 +16,7 @@ from ivatar.settings import MIN_LENGTH_EMAIL, MAX_LENGTH_EMAIL
|
||||
from ivatar.settings import MIN_LENGTH_URL, MAX_LENGTH_URL
|
||||
from . models import UnconfirmedEmail, ConfirmedEmail, Photo
|
||||
from . models import UnconfirmedOpenId, ConfirmedOpenId
|
||||
from . models import UserPreference
|
||||
|
||||
MAX_NUM_UNCONFIRMED_EMAILS_DEFAULT = 5
|
||||
|
||||
@@ -180,3 +181,16 @@ class AddOpenIDForm(forms.Form):
|
||||
unconfirmed.save()
|
||||
|
||||
return unconfirmed.pk
|
||||
|
||||
class UpdatePreferenceForm(forms.ModelForm):
|
||||
'''
|
||||
Form for updating user preferences
|
||||
'''
|
||||
|
||||
class Meta:
|
||||
'''
|
||||
Meta class for UpdatePreferenceForm
|
||||
'''
|
||||
model = UserPreference
|
||||
fields = ['theme']
|
||||
|
||||
|
||||
35
ivatar/ivataraccount/migrations/0008_userpreference.py
Normal file
35
ivatar/ivataraccount/migrations/0008_userpreference.py
Normal file
@@ -0,0 +1,35 @@
|
||||
# Generated by Django 2.0.6 on 2018-07-04 12:32
|
||||
|
||||
from django.conf import settings
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
|
||||
|
||||
def add_preference_to_user(apps, schema_editor):
|
||||
'''
|
||||
Make sure all users have preferences set up
|
||||
'''
|
||||
from django.contrib.auth.models import User
|
||||
UserPreference = apps.get_model('ivataraccount', 'UserPreference')
|
||||
for u in User.objects.filter(userpreference=None):
|
||||
p = UserPreference.objects.create(user_id=u.pk)
|
||||
p.save()
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('auth', '0009_alter_user_last_name_max_length'),
|
||||
('ivataraccount', '0007_auto_20180627_0624'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='UserPreference',
|
||||
fields=[
|
||||
('theme', models.CharField(choices=[('default', 'Default theme'), ('clime', 'Climes theme')], default='default', max_length=10)),
|
||||
('user', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, primary_key=True, serialize=False, to=settings.AUTH_USER_MODEL)),
|
||||
],
|
||||
),
|
||||
migrations.RunPython(add_preference_to_user),
|
||||
]
|
||||
18
ivatar/ivataraccount/migrations/0009_auto_20180705_1152.py
Normal file
18
ivatar/ivataraccount/migrations/0009_auto_20180705_1152.py
Normal file
@@ -0,0 +1,18 @@
|
||||
# Generated by Django 2.0.6 on 2018-07-05 11:52
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('ivataraccount', '0008_userpreference'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='userpreference',
|
||||
name='theme',
|
||||
field=models.CharField(choices=[('default', 'Default theme'), ('clime', 'climes theme'), ('falko', 'falkos theme')], default='default', max_length=10),
|
||||
),
|
||||
]
|
||||
18
ivatar/ivataraccount/migrations/0010_auto_20180705_1201.py
Normal file
18
ivatar/ivataraccount/migrations/0010_auto_20180705_1201.py
Normal file
@@ -0,0 +1,18 @@
|
||||
# Generated by Django 2.0.6 on 2018-07-05 12:01
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('ivataraccount', '0009_auto_20180705_1152'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='userpreference',
|
||||
name='theme',
|
||||
field=models.CharField(choices=[('default', 'Default theme'), ('falko', 'falkos theme')], default='default', max_length=10),
|
||||
),
|
||||
]
|
||||
@@ -57,6 +57,32 @@ def pil_format(image_type):
|
||||
return None
|
||||
|
||||
|
||||
class UserPreference(models.Model):
|
||||
'''
|
||||
Holds the user users preferences
|
||||
'''
|
||||
THEMES = (
|
||||
('default', 'Default theme'),
|
||||
# ('clime', 'climes theme'), # Not yet available
|
||||
('falko', 'falkos theme'),
|
||||
)
|
||||
|
||||
theme = models.CharField(
|
||||
max_length=10,
|
||||
choices=THEMES,
|
||||
default='default',
|
||||
)
|
||||
|
||||
user = models.OneToOneField(
|
||||
User,
|
||||
on_delete=models.deletion.CASCADE,
|
||||
primary_key=True,
|
||||
)
|
||||
|
||||
def __str__(self):
|
||||
return '<UserPreference (%i) for %s>' % (self.pk, self.user)
|
||||
|
||||
|
||||
class BaseAccountModel(models.Model):
|
||||
'''
|
||||
Base, abstract model, holding fields we use in all cases
|
||||
|
||||
20
ivatar/ivataraccount/templates/preferences.html
Normal file
20
ivatar/ivataraccount/templates/preferences.html
Normal file
@@ -0,0 +1,20 @@
|
||||
{% extends 'base.html' %}
|
||||
{% load i18n %}
|
||||
{% load bootstrap4 %}
|
||||
{% load static %}
|
||||
|
||||
{% block title %}{% trans 'Your Preferences' %}{% endblock title %}
|
||||
|
||||
{% block content %}
|
||||
|
||||
<div style="width:600px;">
|
||||
<form method="post" name="check">{% csrf_token %}
|
||||
{% bootstrap_form form %}
|
||||
{% buttons %}
|
||||
<button type="submit" class="btn btn-primary">{% trans 'Update' %}</button>
|
||||
<button type="cancel" class="btn btn-danger">{% trans 'Cancel' %}</button>
|
||||
{% endbuttons %}
|
||||
</form>
|
||||
</div>
|
||||
|
||||
{% endblock content %}
|
||||
@@ -13,6 +13,7 @@ from . views import ImportPhotoView, RawImageView, DeletePhotoView
|
||||
from . views import UploadPhotoView, AssignPhotoOpenIDView
|
||||
from . views import AddOpenIDView, RedirectOpenIDView, ConfirmOpenIDView
|
||||
from . views import CropPhotoView
|
||||
from . views import UserPreferenceView
|
||||
|
||||
# Define URL patterns, self documenting
|
||||
# To see the fancy, colorful evaluation of these use:
|
||||
@@ -73,4 +74,5 @@ urlpatterns = [ # pylint: disable=invalid-name
|
||||
DeletePhotoView.as_view(), name='delete_photo'),
|
||||
url(r'raw_image/(?P<pk>\d+)', RawImageView.as_view(), name='raw_image'),
|
||||
url(r'crop_photo/(?P<pk>\d+)', CropPhotoView.as_view(), name='crop_photo'),
|
||||
url(r'pref/$', UserPreferenceView.as_view(), name='user_preference'),
|
||||
]
|
||||
|
||||
@@ -5,7 +5,7 @@ from django.contrib.auth.decorators import login_required
|
||||
from django.utils.decorators import method_decorator
|
||||
from django.contrib.messages.views import SuccessMessageMixin
|
||||
from django.contrib import messages
|
||||
from django.views.generic.edit import FormView
|
||||
from django.views.generic.edit import FormView, UpdateView
|
||||
from django.views.generic.base import View, TemplateView
|
||||
from django.views.generic.detail import DetailView
|
||||
from django.contrib.auth import authenticate, login
|
||||
@@ -19,8 +19,10 @@ from openid import oidutil
|
||||
from openid.consumer import consumer
|
||||
|
||||
from .forms import AddEmailForm, UploadPhotoForm, AddOpenIDForm
|
||||
from .forms import UpdatePreferenceForm
|
||||
from .models import UnconfirmedEmail, ConfirmedEmail, Photo
|
||||
from .models import UnconfirmedOpenId, ConfirmedOpenId, DjangoOpenIDStore
|
||||
from .models import UserPreference
|
||||
|
||||
from ivatar.settings import MAX_NUM_PHOTOS, MAX_PHOTO_SIZE
|
||||
|
||||
@@ -561,3 +563,16 @@ class CropPhotoView(TemplateView):
|
||||
pass # Ignore automatic assignment
|
||||
|
||||
return photo.perform_crop(request, dimensions, email, openid)
|
||||
|
||||
@method_decorator(login_required, name='dispatch')
|
||||
class UserPreferenceView(FormView, UpdateView):
|
||||
'''
|
||||
View class for user preferences view/update
|
||||
'''
|
||||
template_name = 'preferences.html'
|
||||
model = UserPreference
|
||||
form_class = UpdatePreferenceForm
|
||||
success_url = reverse_lazy('user_preference')
|
||||
|
||||
def get_object(self):
|
||||
return self.request.user.userpreference
|
||||
|
||||
41
ivatar/static/css/falko.css
Normal file
41
ivatar/static/css/falko.css
Normal file
@@ -0,0 +1,41 @@
|
||||
/* Main palette from http://www.colourlovers.com/palette/4581580/Dr._Hans_6 */
|
||||
|
||||
body {
|
||||
background-color: #DEE8F1;
|
||||
}
|
||||
|
||||
#site-name {
|
||||
color: #675E57;
|
||||
}
|
||||
|
||||
#site-branding {
|
||||
color: #4F6384;
|
||||
}
|
||||
|
||||
h1 {
|
||||
color: #675E57;
|
||||
}
|
||||
|
||||
h2 {
|
||||
color: #4F6384;
|
||||
}
|
||||
|
||||
#outer {
|
||||
background-color: #9AB5D2;
|
||||
}
|
||||
|
||||
a {
|
||||
color: #675E57;
|
||||
}
|
||||
|
||||
#content {
|
||||
background-color: #FFFFFF;
|
||||
}
|
||||
|
||||
#content a {
|
||||
color: #4F6384;
|
||||
}
|
||||
|
||||
.fas, .fab {
|
||||
color: #675E57;
|
||||
}
|
||||
@@ -40,7 +40,7 @@
|
||||
<a href="{{ mailurl }}">
|
||||
<img src="{{ mailurl }}" style="max-width: {{ size }}px; max-height: {{ size }}px;">
|
||||
</a>
|
||||
<div style="float:inline-end; font-size:{% widthratio size 3 1 %}px;">
|
||||
<div style="padding-left:2px; float:inline-end; font-size:{% widthratio size 3 1 %}px;">
|
||||
<i class="fas fa-unlock" title="None-SSL connection (http)"></i>
|
||||
<br/>
|
||||
<i class="fas fa-at" title="mail: {{ form.mail.value }}"></i>
|
||||
@@ -53,7 +53,7 @@
|
||||
<a href="{{ mailurl_secure }}">
|
||||
<img src="{{ mailurl_secure }}" style="max-width: {{ size }}px; max-height: {{ size }}px;">
|
||||
</a>
|
||||
<div style="float:inline-end; font-size:{% widthratio size 3 1 %}px;">
|
||||
<div style="padding-left:2px; float:inline-end; font-size:{% widthratio size 3 1 %}px;">
|
||||
<i class="fas fa-lock" title="Secure connection (https)"></i>
|
||||
<br/>
|
||||
<i class="fas fa-at" title="mail: {{ form.mail.value }}"></i>
|
||||
@@ -67,7 +67,7 @@
|
||||
<a href="{{ BASE_URL }}{{ mail_hash256 }}?s={{ size }}">
|
||||
<img src="{{ BASE_URL }}{{ mail_hash256 }}?s={{ size }}" style="max-width: {{ size }}px; max-height: {{ size }}px;">
|
||||
</a>
|
||||
<div style="float:inline-end; font-size:{% widthratio size 3 1 %}px;">
|
||||
<div style="padding-left:2px; float:inline-end; font-size:{% widthratio size 3 1 %}px;">
|
||||
<i class="fas fa-unlock" title="None-SSL connection (http)"></i>
|
||||
<br/>
|
||||
<i class="fas fa-at" title="mail: {{ form.mail.value }}"></i>
|
||||
@@ -80,7 +80,7 @@
|
||||
<a href="{{ SECURE_BASE_URL }}{{ mail_hash256 }}?s={{ size }}">
|
||||
<img src="{{ SECURE_BASE_URL }}{{ mail_hash256 }}?s={{ size }}" style="max-width: {{ size }}px; max-height: {{ size }}px;">
|
||||
</a>
|
||||
<div style="float:inline-end; font-size:{% widthratio size 3 1 %}px;">
|
||||
<div style="padding-left:2px; float:inline-end; font-size:{% widthratio size 3 1 %}px;">
|
||||
<i class="fas fa-lock" title="Secure connection (https)"></i>
|
||||
<br/>
|
||||
<i class="fas fa-at" title="mail: {{ form.mail.value }}"></i>
|
||||
@@ -96,7 +96,7 @@
|
||||
<a href="{{ openidurl }}">
|
||||
<img src="{{ openidurl }}" style="max-width: {{ size }}px; max-height: {{ size }}px;">
|
||||
</a>
|
||||
<div style="float:inline-end; font-size:{% widthratio size 3 1 %}px">
|
||||
<div style="padding-left:2px; float:inline-end; font-size:{% widthratio size 3 1 %}px">
|
||||
<i class="fas fa-unlock" title="None-SSL connection (http)"></i>
|
||||
<br/>
|
||||
<i class="fab fa-openid" title="openid: {{ form.openid.value }}"></i>
|
||||
@@ -109,7 +109,7 @@
|
||||
<a href="{{ openidurl_secure }}">
|
||||
<img src="{{ openidurl_secure }}" style="max-width: {{ size }}px; max-height: {{ size }}px;">
|
||||
</a>
|
||||
<div style="float:inline-end; font-size:{% widthratio size 3 1 %}px">
|
||||
<div style="padding-left:2px; float:inline-end; font-size:{% widthratio size 3 1 %}px">
|
||||
<i class="fas fa-lock" title="Secure connection (http)"></i>
|
||||
<br/>
|
||||
<i class="fab fa-openid" title="openid: {{ form.openid.value }}"></i>
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
<div id="account">
|
||||
{% if user.is_authenticated %}
|
||||
<a href="{% url 'profile' %}">{% trans 'Profile' %}</a> |
|
||||
<a href="{% url 'user_preference' %}">{% trans 'Preferences' %}</a> |
|
||||
<a href="{% url 'tools_check' %}">{% trans 'Check' %}</a> |
|
||||
<a href="{{ contact_us }}">{% trans 'Contact Us' %}</a> |
|
||||
<a href="{{ security_url }}">{% trans 'Security' %}</a> |
|
||||
|
||||
@@ -20,6 +20,11 @@
|
||||
<link rel="mask-icon" href="{% static '/img/safari-pinned-tab.svg' %}" color="#fa711f">
|
||||
<link rel="stylesheet" href="{% static '/css/ivatar.css' %}" type="text/css">
|
||||
<link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.1.0/css/all.css" integrity="sha384-lKuwvrZot6UHsBSfcMvOkWwlCMgc0TaWr+30HWe3a4ltaBwTZhyTEggF5tJv8tbt" crossorigin="anonymous">
|
||||
{% if user.is_authenticated %}
|
||||
{% if user.userpreference and user.userpreference.theme != 'default' %}
|
||||
<link rel="stylesheet" href="{% static 'css/' %}{{ user.userpreference.theme }}.css" type="text/css">
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
<link rel="manifest" href="/manifest.json">
|
||||
<meta name="msapplication-TileImage" content="{% static '/img/nobody/144.png' %}">
|
||||
<meta name="msapplication-TileColor" content="#fa711f">
|
||||
|
||||
Reference in New Issue
Block a user