Initial commit

This commit is contained in:
Oliver Falk
2018-05-07 15:00:03 +02:00
commit 9ff9159f8b
1086 changed files with 1858 additions and 0 deletions

3
.gitignore vendored Normal file
View File

@@ -0,0 +1,3 @@
__pycache__
/db.sqlite3
/static/

47
config.py Normal file
View File

@@ -0,0 +1,47 @@
import os
from sys import platform, argv
from ivatar.settings import BASE_DIR
if os.path.isfile(os.path.join(BASE_DIR, 'config_local.py')):
from config_local import * # noqa # flake8: noqa # NOQA # pragma: no cover
ADMIN_USERS = []
ALLOWED_HOSTS = [
'localhost',
]
from ivatar.settings import INSTALLED_APPS # noqa
INSTALLED_APPS.extend([
'django_extensions',
'django_openid_auth',
'bootstrap4',
'ivatar',
'ivatar.ivataraccount',
])
from ivatar.settings import MIDDLEWARE # noqa
MIDDLEWARE.extend([
'django.middleware.locale.LocaleMiddleware',
])
AUTHENTICATION_BACKENDS = (
# Enable this to allow LDAP authentication. See INSTALL for more information.
# 'django_auth_ldap.backend.LDAPBackend',
'django_openid_auth.auth.OpenIDBackend',
'django.contrib.auth.backends.ModelBackend',
)
from ivatar.settings import TEMPLATES
TEMPLATES[0]['DIRS'].extend([
os.path.join(BASE_DIR, 'templates'),
])
TEMPLATES[0]['OPTIONS']['context_processors'].append(
'ivatar.context_processors.basepage',
)
OPENID_CREATE_USERS = True
OPENID_UPDATE_DETAILS_FROM_SREG = True
IVATAR_VERSION = '0.1'
LOGIN_REDIRECT_URL = '/account/profile/'

2
config_local.py Normal file
View File

@@ -0,0 +1,2 @@
SESSION_COOKIE_SECURE = False
DEBUG = True

1
ivatar/__init__.py Normal file
View File

@@ -0,0 +1 @@
app_label = __name__

View File

@@ -0,0 +1,15 @@
'''
Default: useful variables for the base page templates.
'''
from ivatar.settings import IVATAR_VERSION
from ipware import get_client_ip
def basepage(request):
context = {}
if 'openid_identifier' in request.GET:
context['openid_identifier'] = request.GET['openid_identifier']
client_ip, is_routable = get_client_ip(request)
context['client_ip'] = client_ip
context['ivatar_version'] = IVATAR_VERSION
return context

View File

@@ -0,0 +1 @@
app_label = __name__

View File

@@ -0,0 +1,3 @@
from django.contrib import admin
# Register your models here.

View File

@@ -0,0 +1,5 @@
from django.apps import AppConfig
class IvataraccountConfig(AppConfig):
name = 'ivataraccount'

View File

@@ -0,0 +1,39 @@
from ssl import SSLError
from urllib.request import urlopen, HTTPError, URLError
import hashlib
URL_TIMEOUT = 5 # in seconds
def get_photo(email):
hash_object = hashlib.new('md5')
hash_object.update(email.lower())
thumbnail_url = 'https://secure.gravatar.com/avatar/' + hash_object.hexdigest(
) + '?s=80&d=404'
image_url = 'https://secure.gravatar.com/avatar/' + hash_object.hexdigest(
) + '?s=512&d=404'
# Will redirect to the public profile URL if it exists
service_url = 'http://www.gravatar.com/' + hash_object.hexdigest()
try:
urlopen(image_url, timeout=URL_TIMEOUT)
except HTTPError as e:
if e.code != 404 and e.code != 503:
print('Gravatar fetch failed with an unexpected %s HTTP error' %
e.code)
return False
except URLError as e:
print('Gravatar fetch failed with URL error: %s' % e.reason)
return False
except SSLError as e:
print('Gravatar fetch failed with SSL error: %s' % e.reason)
return False
return {
'thumbnail_url': thumbnail_url,
'image_url': image_url,
'width': 80,
'height': 80,
'service_url': service_url,
'service_name': 'Gravatar'
}

View File

@@ -0,0 +1,108 @@
# Generated by Django 2.0.5 on 2018-05-07 07:13
from django.conf import settings
from django.db import migrations, models
import django.db.models.deletion
import ivatar.ivataraccount.models
class Migration(migrations.Migration):
initial = True
dependencies = [
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
]
operations = [
migrations.CreateModel(
name='ConfirmedEmail',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('ip_address', models.GenericIPAddressField(unpack_ipv4=True)),
('add_date', models.DateTimeField(default=ivatar.ivataraccount.models.utcnow)),
('email', models.EmailField(max_length=254, unique=True)),
],
options={
'verbose_name': 'confirmed email',
'verbose_name_plural': 'confirmed emails',
},
),
migrations.CreateModel(
name='ConfirmedOpenId',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('ip_address', models.GenericIPAddressField(unpack_ipv4=True)),
('add_date', models.DateTimeField(default=ivatar.ivataraccount.models.utcnow)),
('openid', models.URLField(max_length=255, unique=True)),
],
options={
'verbose_name': 'confirmed OpenID',
'verbose_name_plural': 'confirmed OpenIDs',
},
),
migrations.CreateModel(
name='Photo',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('add_date', models.DateTimeField(default=ivatar.ivataraccount.models.utcnow)),
('ip_address', models.GenericIPAddressField(unpack_ipv4=True)),
('data', models.BinaryField()),
('format', models.CharField(max_length=3)),
('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)),
],
options={
'verbose_name': 'photo',
'verbose_name_plural': 'photos',
},
),
migrations.CreateModel(
name='UnconfirmedEmail',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('ip_address', models.GenericIPAddressField(unpack_ipv4=True)),
('add_date', models.DateTimeField(default=ivatar.ivataraccount.models.utcnow)),
('email', models.EmailField(max_length=254)),
('verification_key', models.CharField(max_length=64)),
('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)),
],
options={
'verbose_name': 'unconfirmed_email',
'verbose_name_plural': 'unconfirmed_emails',
},
),
migrations.CreateModel(
name='UnconfirmedOpenId',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('ip_address', models.GenericIPAddressField(unpack_ipv4=True)),
('add_date', models.DateTimeField(default=ivatar.ivataraccount.models.utcnow)),
('openid', models.URLField(max_length=255)),
('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)),
],
options={
'verbose_name': 'unconfirmed OpenID',
'verbose_name_plural': 'unconfirmed_OpenIDs',
},
),
migrations.AddField(
model_name='confirmedopenid',
name='photo',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='openids', to='ivataraccount.Photo'),
),
migrations.AddField(
model_name='confirmedopenid',
name='user',
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL),
),
migrations.AddField(
model_name='confirmedemail',
name='photo',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='emails', to='ivataraccount.Photo'),
),
migrations.AddField(
model_name='confirmedemail',
name='user',
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL),
),
]

View File

@@ -0,0 +1,34 @@
# Generated by Django 2.0.5 on 2018-05-07 07:23
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('ivataraccount', '0001_initial'),
]
operations = [
migrations.CreateModel(
name='OpenIDAssociation',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('server_url', models.TextField(max_length=2047)),
('handle', models.CharField(max_length=255)),
('secret', models.TextField(max_length=255)),
('issued', models.IntegerField()),
('lifetime', models.IntegerField()),
('assoc_type', models.TextField(max_length=64)),
],
),
migrations.CreateModel(
name='OpenIDNonce',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('server_url', models.CharField(max_length=255)),
('timestamp', models.IntegerField()),
('salt', models.CharField(max_length=128)),
],
),
]

View File

@@ -0,0 +1,212 @@
from django.db import models
from django.contrib.auth.models import User
from django.utils.translation import ugettext_lazy as _
from . gravatar import get_photo as get_gravatar_photo
from openid.store.interface import OpenIDStore
from openid.store import nonce as oidnonce
from openid.association import Association as OIDAssociation
import datetime
def utcnow():
return datetime.datetime.utcnow
MAX_LENGTH_EMAIL = 254 # http://stackoverflow.com/questions/386294
MAX_LENGTH_URL = 255 # MySQL can't handle more than that (LP: 1018682)
class BaseAccountModel(models.Model):
user = models.ForeignKey(
User,
on_delete=models.deletion.CASCADE,
)
ip_address = models.GenericIPAddressField(unpack_ipv4=True)
add_date = models.DateTimeField(default=utcnow)
class Meta:
abstract = True
class Photo(BaseAccountModel):
ip_address = models.GenericIPAddressField(unpack_ipv4=True)
data = models.BinaryField()
format = models.CharField(max_length=3)
class Meta:
verbose_name = _('photo')
verbose_name_plural = _('photos')
class ConfirmedEmailManager(models.Manager):
def create_confirmed_email(self, user, email_address, is_logged_in):
confirmed = ConfirmedEmail()
confirmed.user = user
confirmed.ip_address = '0.0.0.0'
confirmed.email = email_address
confirmed.save()
external_photos = []
if is_logged_in:
gravatar = get_gravatar_photo(confirmed.email)
if gravatar:
external_photos.append(gravatar)
return external_photos
class ConfirmedEmail(BaseAccountModel):
email = models.EmailField(unique=True, max_length=MAX_LENGTH_EMAIL)
photo = models.ForeignKey(
Photo,
related_name='emails',
blank=True,
null=True,
on_delete=models.deletion.CASCADE,
)
objects = ConfirmedEmailManager()
class Meta:
verbose_name = _('confirmed email')
verbose_name_plural = _('confirmed emails')
class UnconfirmedEmail(BaseAccountModel):
email = models.EmailField(max_length=MAX_LENGTH_EMAIL)
verification_key = models.CharField(max_length=64)
class Meta:
verbose_name = _('unconfirmed_email')
verbose_name_plural = _('unconfirmed_emails')
def save(self, *args, **kwargs):
hash_object = hashlib.new('sha256')
hash_object.update(urandom(1024) + self.user.username)
self.verification_key = hash_object.hexdigest()
super(UnconfirmedEmail, self).save(*args, **kwargs)
class UnconfirmedOpenId(BaseAccountModel):
openid = models.URLField(unique=False, max_length=MAX_LENGTH_URL)
class Meta:
verbose_name = _('unconfirmed OpenID')
verbose_name_plural = ('unconfirmed_OpenIDs')
class ConfirmedOpenId(BaseAccountModel):
openid = models.URLField(unique=True, max_length=MAX_LENGTH_URL)
photo = models.ForeignKey(
Photo,
related_name='openids',
blank=True,
null=True,
on_delete = models.deletion.CASCADE,
)
class Meta:
verbose_name = _('confirmed OpenID')
verbose_name_plural = _('confirmed OpenIDs')
# Classes related to the OpenID Store (from https://github.com/edx/django-openid-auth/)
class OpenIDNonce(models.Model):
server_url = models.CharField(max_length=255)
timestamp = models.IntegerField()
salt = models.CharField(max_length=128)
class OpenIDAssociation(models.Model):
server_url = models.TextField(max_length=2047)
handle = models.CharField(max_length=255)
secret = models.TextField(max_length=255) # stored base64 encoded
issued = models.IntegerField()
lifetime = models.IntegerField()
assoc_type = models.TextField(max_length=64)
class DjangoOpenIDStore(OpenIDStore):
'''
The Python openid library needs an OpenIDStore subclass to persist data
related to OpenID authentications. This one uses our Django models.
'''
def storeAssociation(self, server_url, association):
# pylint: disable=unexpected-keyword-arg
assoc = OpenIDAssociation(
server_url=server_url,
handle=association.handle,
secret=base64.encodestring(association.secret),
issued=association.issued,
lifetime=association.issued,
assoc_type=association.assoc_type)
assoc.save()
def getAssociation(self, server_url, handle=None):
assocs = []
if handle is not None:
assocs = OpenIDAssociation.objects.filter(
server_url=server_url, handle=handle)
else:
assocs = OpenIDAssociation.objects.filter(server_url=server_url)
if not assocs:
return None
associations = []
for assoc in assocs:
if type(assoc.secret) is str:
assoc.secret = assoc.secret.split("b'")[1].split("'")[0]
assoc.secret = bytes(assoc.secret, 'utf-8')
association = OIDAssociation(assoc.handle,
base64.decodestring(assoc.secret),
assoc.issued, assoc.lifetime,
assoc.assoc_type)
expires = 0
try:
expires = association.getExpiresIn()
except:
expires = association.expiresIn
if expires == 0:
self.removeAssociation(server_url, assoc.handle)
else:
associations.append((association.issued, association))
if not associations:
return None
return associations[-1][1]
def removeAssociation(self, server_url, handle):
assocs = list(
OpenIDAssociation.objects.filter(
server_url=server_url, handle=handle))
assocs_exist = len(assocs) > 0
for assoc in assocs:
assoc.delete()
return assocs_exist
def useNonce(self, server_url, timestamp, salt):
# Has nonce expired?
if abs(timestamp - time.time()) > oidnonce.SKEW:
return False
try:
nonce = OpenIDNonce.objects.get(
server_url__exact=server_url,
timestamp__exact=timestamp,
salt__exact=salt)
except OpenIDNonce.DoesNotExist:
nonce = OpenIDNonce.objects.create(
server_url=server_url, timestamp=timestamp, salt=salt)
return True
nonce.delete()
return False
def cleanupNonces(self):
timestamp = int(time.time()) - oidnonce.SKEW
OpenIDNonce.objects.filter(timestamp__lt=timestamp).delete()
def cleanupAssociations(self):
OpenIDAssociation.objects.extra(
where=['issued + lifetimeint < (%s)' % time.time()]).delete()
# pylint: disable=invalid-name
def getAuthKey(self):
# Use first AUTH_KEY_LEN characters of md5 hash of SECRET_KEY
hash_object = hashlib.new('md5')
hash_object.update(settings.SECRET_KEY)
return hash_object.hexdigest()[:self.AUTH_KEY_LEN]

View File

@@ -0,0 +1,38 @@
{% extends 'base.html' %}
{% load i18n %}
{% block title %}{% trans 'Login to yourivatar account' %}{% endblock title %}
{% block content %}
<h1>{% trans 'Login' %}</h1>
<form action="{% url 'login' %}" method="post" name="login">{% csrf_token %}
<table summary="">
{% if form.username.errors %}
<tr>
<td colspan="2">{{ form.username.errors }}</td>
</tr>
{% endif %}
<tr>
<td>{{ form.username.label_tag }}</td>
<td>{{ form.username }}</td>
</tr>
{% if form.password.errors %}
<tr>
<td colspan="2">{{ form.password.errors }}</td>
</tr>
{% endif %}
<tr>
<td>{{ form.password.label_tag }}</td>
<td>{{ form.password }}</td>
</tr>
</table>
<p><input type="submit" value="{% trans 'Login' %}">
&nbsp;<a href="/">{% trans 'Cancel' %}</a></p>
</form>
{% endblock content %}

View File

@@ -0,0 +1,47 @@
{% extends 'base.html' %}
{% load i18n %}
{% block title %}{% trans 'Create a new ivatar account' %}{% endblock title %}
{% block content %}
<h1>{% trans 'Create a new account' %}</h1>
<form action="{% url 'new_account' %}" method="post" name="newaccount">{% csrf_token %}
<table summary="">
{% if form.username.errors %}
<tr>
<td colspan="2">{{ form.username.errors }}</td>
</tr>
{% endif %}
<tr>
<td>{{ form.username.label_tag }}</td>
<td>{{ form.username }}</td>
</tr>
{% if form.password1.errors %}
<tr>
<td colspan="2">{{ form.password1.errors }}</td>
</tr>
{% endif %}
<tr>
<td>{{ form.password1.label_tag }}</td>
<td>{{ form.password1 }}</td>
</tr>
{% if form.password2.errors %}
<tr>
<td colspan="2">{{ form.password2.errors }}</td>
</tr>
{% endif %}
<tr>
<td>{{ form.password2.label_tag }}</td>
<td>{{ form.password2 }}</td>
</tr>
</table>
<p><input type="submit" value="{% trans 'Create account' %}">
&nbsp;<a href="/">{% trans 'Cancel' %}</a></p>
</form>
{% endblock content %}

View File

@@ -0,0 +1,51 @@
{% extends 'base.html' %}
{% load i18n %}
{% block title %}{% trans 'Change your ivatar password' %}{% endblock title %}
{% block content %}
<h1>{% trans 'Change password' %}</h1>
<form action="" method="post" name="changepassword">{% csrf_token %}
<table summary="">
{% if form.old_password %}
{% if form.old_password.errors %}
<tr>
<td colspan="2">{{ form.old_password.errors }}</td>
</tr>
{% endif %}
<tr>
<td>{{ form.old_password.label_tag }}</td>
<td>{{ form.old_password }}</td>
</tr>
{% endif %}
{% if form.new_password1.errors %}
<tr>
<td colspan="2">{{ form.new_password1.errors }}</td>
</tr>
{% endif %}
<tr>
<td>{{ form.new_password1.label_tag }}</td>
<td>{{ form.new_password1 }}</td>
</tr>
{% if form.new_password2.errors %}
<tr>
<td colspan="2">{{ form.new_password2.errors }}</td>
</tr>
{% endif %}
<tr>
<td>{{ form.new_password2.label_tag }}</td>
<td>{{ form.new_password2 }}</td>
</tr>
</table>
<p><input type="submit" value="{% trans 'Change my password' %}" />
&nbsp;<a href="{% url 'profile' %}">{% trans 'Cancel' %}</a></p>
</form>
{% endblock content %}

View File

@@ -0,0 +1,89 @@
{% extends 'base.html' %}
{% load i18n %}
{% load static %}
{% block title %}{% trans 'Your Profile' %}{% endblock title %}
{% block content %}
<h1>
{% trans 'Your Profile' %} -
{% if user.first_name and user.last_name %}
{{ user.first_name }} {{ user.last_name }}
{% else %}
{{ user.username }}
{% endif %}
</h1>
{% if user.photos.confirmed_emails or user.photos.confirmed_openids %}
<p>{% trans 'You have the following confirmed email addresses and OpenIDs:' %}</p>
<ul class="horizontal-list avatar-list">
{% for email in confirmed_emails %}
<li><form action="{% url 'remove_confirmed_email' email.id %}" method="post">{% csrf_token %}
<a href="{% url 'assign_photo_email' email.id %}">
<img class="thumbnail editable avatar-chooser" src="{{ email.photo_url }}" alt=""></a>
{{ email.email }}
<br><a href="{% url 'assign_photo_email' email.id %}">{% trans 'Change photo' %}</a>
<br><br><input type="image" src="{% static '/img/delete_button.png' %}" value="{% trans 'Remove' %}"></form></li>
{% endfor %}
{% for openid in confirmed_openids %}
<li><form action="{% url 'remove_confirmed_openid' openid.id %}" method="post">{% csrf_token %}
<a href="{% url 'assign_photo_openid' openid.id %}">
<img class="thumbnail editable avatar-chooser" src="{{openid.photo_url}}" alt=""></a>
{{openid.openid}}
<br><a href="{% url 'assign_photo_openid' openid.id %}">{% trans 'Change photo' %}</a>
<br><br><input type="image" src="{% static '/img/delete_button.png' %}" value="{% trans 'Remove' %}"></form></li>
{% endfor %}
</ul>
<div class="clear-both"></div>
{% endif %}
{% if unconfirmed_emails or unconfirmed_openids %}
<p>{% trans 'You have the following unconfirmed email addresses and OpenIDs:' %}</p>
<ul class="vertical-list">
{% for email in unconfirmed_emails %}
<li><form action="{% url 'remove_unconfirmed_email' email.id %}" method="post">{% csrf_token %}{{ email.email }}
<input type="image" src="{% static '/img/delete_button.png' %}" value="{% trans 'Remove' %}"></form>{# TODO: (expires in xx hours) #}</li>
{% endfor %}
{% for openid in unconfirmed_openids %}
<li><form action="{% url 'remove_unconfirmed_openid' openid.id %}" method="post">{% csrf_token %}{{ openid.openid }}
<input type="image" src="{% static '/static/img/delete_button.png' %}" value="{% trans 'Remove' %}"></form>{# TODO: (expires in xx hours) #}</li>
{% endfor %}
</ul>
{% endif %}
<p>
{% if not max_emails %}
<a href="{% url 'add_email' %}">{% trans 'Add a new email address' %}</a>
|
{% endif %}
<a href="{% url 'add_openid' %}">{% trans 'Add a new OpenID' %}</a></p>
</p>
{% if photos %}
<p>{% trans 'Here are the photos you have uploaded/imported:' %}</p>
<ul class="horizontal-list avatar-list centered">
{% for photo in photos %}
<li><img class="thumbnail" src="{{photo}}" title="{% blocktrans with photo.upload_datetime as datetime %}Uploaded on {{ datetime }}{% endblocktrans %}" alt="{% blocktrans with photo.upload_datetime as datetime %}Uploaded on {{ datetime }}{% endblocktrans %}"><br>
<a href="{% url 'delete_photo' photo.id %}">{% trans 'Delete' %}</a></li>
{% endfor %}
</ul>
{% endif %}
{% if not max_photos %}
<p><a href="{% url 'upload_photo' %}">{% trans 'Upload a new photo' %}</a></p>
{% endif %}
<h2>{% trans 'Account settings' %}</h2>
{% if has_password %}
<p><a href="{% url 'password_change' %}">{% trans 'Change your password' %}</a></p>
{% else %}
<p><a href="{% url 'password_set' %}">{% trans 'Set a password' %}</a></p>
{% endif %}
<!-- <p><a href="{% url 'export' %}">{% trans 'Export your data' %}</a></p> -->
<p><a href="{% url 'delete' %}">{% trans 'Permanently delete your account' %}</a></p>
{% endblock content %}

View File

@@ -0,0 +1,29 @@
from django.test import TestCase
from django.test import Client
from django.urls import reverse
import os
import django
os.environ['DJANGO_SETTINGS_MODULE'] = 'ivatar.settings'
django.setup()
from ivatar.utils import random_string
class Tester(TestCase):
client = Client()
username = random_string()
password = random_string()
def test_new_user(self):
"""
Create a new user
"""
response = self.client.get(reverse('new_account'))
self.assertEqual(response.status_code, 200, 'no 200 ok?')
url = reverse('new_account')
response = self.client.post(url, {
'username': self.username,
'password1': self.password,
'password2': self.password,
})
print(response)

View File

@@ -0,0 +1,3 @@
from django.test import TestCase
# Create your tests here.

View File

@@ -0,0 +1,19 @@
from django.urls import path
from django.views.generic import TemplateView
from . views import CreateView, PasswordSetView
from django.contrib.auth.views import login, logout, password_change, password_change_done
from django.urls import reverse_lazy
urlpatterns = [
path('new/', CreateView.as_view(), name='new_account'),
path('login/', login, { 'template_name': 'login.html' }, name='login'),
path('logout/', logout, { 'next_page': reverse_lazy('login') }, name='logout'),
path('export/', TemplateView.as_view(template_name='export.html'), name='export'),
path('delete/', TemplateView.as_view(template_name='delete.html'), name='delete'),
path('profile/', TemplateView.as_view(template_name='profile.html'), name='profile'),
path('add_email/', TemplateView.as_view(template_name='add_email.html'), name='add_email'),
path('add_openid/', TemplateView.as_view(template_name='add_openid.html'), name='add_openid'),
path('upload_photo/', TemplateView.as_view(template_name='upload_photo.html'), name='upload_photo'),
path('password_set/', PasswordSetView.as_view(), name='password_set'),
]

View File

@@ -0,0 +1,47 @@
from django.shortcuts import render
from django.views.decorators.csrf import csrf_protect
from django.db import transaction
from django.contrib.messages.views import SuccessMessageMixin
from django.views.generic.edit import FormView
from django.contrib.auth import authenticate, login
from django.contrib.auth.models import User
from django.contrib.auth.forms import UserCreationForm, SetPasswordForm
from django.utils.translation import ugettext_lazy as _
from django.http import HttpResponseRedirect
from django.urls import reverse_lazy
class CreateView(SuccessMessageMixin, FormView):
template_name = 'new.html'
form_class = UserCreationForm
success_message = _('created successfully')
success_url = reverse_lazy('profile')
def form_valid(self, form):
form.save()
user = authenticate(
username=form.cleaned_data['username'],
password=form.cleaned_data['password1'])
if user is not None:
login(self.request, user)
return HttpResponseRedirect(reverse_lazy('profile'))
else:
return HttpResponseRedirect(reverse_lazy('login'))
return super().form_valid(form)
class PasswordSetView(SuccessMessageMixin, FormView):
template_name = 'password_change.html'
form_class = SetPasswordForm
success_message = _('password changed successfully')
success_url = reverse_lazy('profile')
def get_form_kwargs(self):
kwargs = super(PasswordSetView, self).get_form_kwargs()
kwargs['user'] = self.request.user
return kwargs
def form_valid(self, form):
form.save()
super().form_valid(form)
return HttpResponseRedirect(reverse_lazy('login'))

117
ivatar/settings.py Normal file
View File

@@ -0,0 +1,117 @@
"""
Django settings for ivatar project.
"""
import os
PACKAGE_ROOT = os.path.abspath(os.path.dirname(__file__))
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
# TODO: Changeme
# SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = '=v(+-^t#ahv^a&&e)uf36g8algj$d1@6ou^w(r0@%)#8mlc*zk'
# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = False
ALLOWED_HOSTS = []
# Application definition
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
]
MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
]
ROOT_URLCONF = 'ivatar.urls'
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [],
'APP_DIRS': True,
'OPTIONS': {
'context_processors': [
'django.template.context_processors.debug',
'django.template.context_processors.request',
'django.contrib.auth.context_processors.auth',
'django.contrib.messages.context_processors.messages',
],
},
},
]
WSGI_APPLICATION = 'ivatar.wsgi.application'
# Database
# https://docs.djangoproject.com/en/2.0/ref/settings/#databases
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
}
}
# Password validation
# https://docs.djangoproject.com/en/2.0/ref/settings/#auth-password-validators
AUTH_PASSWORD_VALIDATORS = [
{
'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
},
{
'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
},
{
'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
},
{
'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
},
]
# Internationalization
# https://docs.djangoproject.com/en/2.0/topics/i18n/
LANGUAGE_CODE = 'en-us'
TIME_ZONE = 'UTC'
USE_I18N = True
USE_L10N = True
USE_TZ = True
# Static files configuration (esp. req. during dev.)
PROJECT_ROOT = os.path.abspath(
os.path.join(
os.path.dirname(__file__),
os.pardir
)
)
STATIC_URL = '/static/'
STATIC_ROOT = os.path.join(BASE_DIR, 'static')
from config import * # noqa

View File

@@ -0,0 +1,4 @@
{
"small-hdrs": true,
"no-referer": true
}

View File

@@ -0,0 +1,187 @@
/* Main palette from http://www.colourlovers.com/palette/4569033/Graceful */
body {
background-color: #FFE7B9;
margin: 0;
}
#site-name {
color: #332B3A;
font-size: 1.5em;
font-style: normal;
letter-spacing: 0.35em;
}
#logo {
float: left;
margin: 0 1em 0 0;
}
#logo img {
border: 0;
}
#site-branding {
color: #0B0507;
font-style: italic;
float: left;
}
h1 {
color: #AFA44B;
}
h2 {
color: #F9711F;
font-weight: normal;
}
.error, .errorlist li {
background-color: #FF0000;
border-radius: 8px;
color: #FFFFFF;
font-weight: bold;
padding: 8px;
}
#outer {
background-color: #AFA44B;
padding: 16px;
}
#header, #footer {
color: #8390BA;
}
a {
color: #F9711F;
font-weight: bold;
}
#header {
height: 54px;
padding: 8px 8px 16px 8px;
}
#footer {
font-size: small;
padding: 16px 8px 8px 8px;
}
#account {
text-align: right;
}
#content {
background-color: #FFFFFF;
border-radius: 8px;
padding: 8px 16px 16px 16px;
}
#content a {
color: #AFA44B;
}
.thumbnail {
border: 0;
height: 80px;
width: 80px;
}
.avatar-list {
height: 105px;
margin: 0 0 0 1.5em;
padding: 0;
}
.avatar-list .editable {
margin: 0 8px 0 0;
}
ul li {
list-style-type: none;
}
.horizontal-list li {
display: inline;
float: left;
margin: 0 15px 15px 0;
}
.centered li {
text-align: center;
vertical-align: middle;
}
.imported-list {
height: 125px;
margin: 0 0 0 1.5em;
padding: 0;
}
.conditions {
list-style-type: none;
margin: 0;
padding-start: 0;
}
.hint {
color: #6D6D6D;
font-style: italic;
margin: 0 0 0 20px;
}
.avatar-chooser {
float: left;
}
#action-panel {
border: 5px;
border-radius: 8px;
border-style: dashed;
float: right;
margin: 20px;
padding: 5px 20px 15px 20px;
}
#id_openid, #id_openid_identifier {
background : #FFFFFF url("../img/openid_logo.png") no-repeat scroll 0 50%;
padding : 4px 18px;
width: 400px;
}
#contribute-button {
text-align: center;
}
#contribute-button a {
background-color: #AFA44B;
border: 1px;
border-color: #000;
border-radius: 8px;
border-style: solid;
color: #fff;
font-size: 1.5em;
padding: 3px 5px 5px 5px;
text-decoration: none;
}
#agpl-button {
background: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGsAAAAUCAMAAAC9FTMqAAAAV1BMVEXV1tXMzczGyMa4urivsq+rraurraurrauqrKqnq6edoJyTl5OFiIR7fntwc3BjZWJbXVtISUc/QD8xMjEnJyccHBwSEhIMDAwBAQEAAAAAAAAAAAAAAAAPezW4AAABW0lEQVRIx73VyY7DIBAE0E6kisxibJYGDvX/3zkHE8eamUssJ31BspCfKJYWfq+EwXynAoVGpn/K2mmapgspMRSaBwDA4lVmVTYLAOmyAKeX5eYnZG2oJOlxKXawQhiSt7GXRpaxRL3eWlYAgPdYo0NkdWOZYczNKY8xpcaWUsokW2rvW2sEYBYL64G5N7/v3fiZyG2MIoVFRIRkkXzCqoCNZltKJ3U/KJkks2SNoiySVLWzSNQk5aRF90gWAEwsSqbdSptlnZHCLCU6pyxinQ/1nBW4xhkAzGwRXtu1W7ebbNYyMrxNZzOc+7LHtvbq8TtDZd4s5kN2pyybyojNF6o73Ot2tLre5a79YInc37Uw92oBM+fexxE5nnkNjRoqySWsJOt231lDCMvbliebaiPrjONzVa+/y/Dbpx6PD+Nn3ihgaaRGh89Qw3r2FOPMn9ZycU/5Zq/8Xv0AInWfQFkFqnUAAAAASUVORK5CYII=');
float: left;
height: 20px;
margin: 0 5px 0 0;
width: 107px;
}
.bolder {
font-weight: bolder;
}
.hidden {
display: none;
}
.clear-both {
clear: both;
}

View File

@@ -0,0 +1,2 @@
/* jquery.Jcrop.min.css v0.9.12 (build:20140524) */
.jcrop-holder{direction:ltr;text-align:left;-ms-touch-action:none}.jcrop-hline,.jcrop-vline{background:#fff url(/static/img/Jcrop.gif);font-size:0;position:absolute}.jcrop-vline{height:100%;width:1px!important}.jcrop-vline.right{right:0}.jcrop-hline{height:1px!important;width:100%}.jcrop-hline.bottom{bottom:0}.jcrop-tracker{height:100%;width:100%;-webkit-tap-highlight-color:transparent;-webkit-touch-callout:none;-webkit-user-select:none}.jcrop-handle{background-color:#333;border:1px #eee solid;width:7px;height:7px;font-size:1px}.jcrop-handle.ord-n{left:50%;margin-left:-4px;margin-top:-4px;top:0}.jcrop-handle.ord-s{bottom:0;left:50%;margin-bottom:-4px;margin-left:-4px}.jcrop-handle.ord-e{margin-right:-4px;margin-top:-4px;right:0;top:50%}.jcrop-handle.ord-w{left:0;margin-left:-4px;margin-top:-4px;top:50%}.jcrop-handle.ord-nw{left:0;margin-left:-4px;margin-top:-4px;top:0}.jcrop-handle.ord-ne{margin-right:-4px;margin-top:-4px;right:0;top:0}.jcrop-handle.ord-se{bottom:0;margin-bottom:-4px;margin-right:-4px;right:0}.jcrop-handle.ord-sw{bottom:0;left:0;margin-bottom:-4px;margin-left:-4px}.jcrop-dragbar.ord-n,.jcrop-dragbar.ord-s{height:7px;width:100%}.jcrop-dragbar.ord-e,.jcrop-dragbar.ord-w{height:100%;width:7px}.jcrop-dragbar.ord-n{margin-top:-4px}.jcrop-dragbar.ord-s{bottom:0;margin-bottom:-4px}.jcrop-dragbar.ord-e{margin-right:-4px;right:0}.jcrop-dragbar.ord-w{margin-left:-4px}.jcrop-light .jcrop-hline,.jcrop-light .jcrop-vline{background:#fff;filter:alpha(opacity=70)!important;opacity:.7!important}.jcrop-light .jcrop-handle{-moz-border-radius:3px;-webkit-border-radius:3px;background-color:#000;border-color:#fff;border-radius:3px}.jcrop-dark .jcrop-hline,.jcrop-dark .jcrop-vline{background:#000;filter:alpha(opacity=70)!important;opacity:.7!important}.jcrop-dark .jcrop-handle{-moz-border-radius:3px;-webkit-border-radius:3px;background-color:#fff;border-color:#000;border-radius:3px}.solid-line .jcrop-hline,.solid-line .jcrop-vline{background:#fff}.jcrop-holder img,img.jcrop-preview{max-width:none}

BIN
ivatar/static/img/Jcrop.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 329 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 503 B

View File

@@ -0,0 +1,192 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 15.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="80px"
height="15px" viewBox="0 0 80 15" enable-background="new 0 0 80 15" xml:space="preserve">
<g id="Layer_1">
<image overflow="visible" width="80" height="15" xlink:href="data:image/png;base64,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
OAAAAABJRU5ErkJggg==" transform="matrix(0.9999 0 0 0.9999 0 0)">
</image>
<image display="none" overflow="visible" width="155" height="51" xlink:href="data:image/png;base64,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" transform="matrix(2.9133 0 0 2.9133 -183 -67)">
</image>
</g>
<g id="Art">
<g id="Background">
<g id="Second_Level">
<g id="Outline_x5F_black">
<rect width="80" height="15"/>
</g>
<g id="Outline_x5F_white">
<rect x="1" y="1" fill="#FFFFFF" width="78" height="13"/>
</g>
</g>
<g id="First_Level">
<g id="Layer_7">
<rect x="2" y="2" width="76" height="11"/>
</g>
<g id="Layer_5">
<path fill="#ABB1AA" d="M2,2v11h20c0,0,3-1.938,3-5.5S22,2,22,2H2"/>
</g>
</g>
</g>
<g id="Symbol">
<g>
<path d="M6.235,2.504c0,0-0.401,2.332,0.953,5.644C6.912,8.498,6.4,9.15,6.18,10.405C5.758,9.577,5.056,4.41,6.235,2.504z"/>
<path d="M12.431,5.765c0,0,3.035-2.107,3.612-1.254c0.577,0.853-3.286,3.361-3.612,3.637c0.677-0.276,1.781-0.853,2.559-0.853
c0.777,0,1.054,0.351-0.1,1.153c-1.154,0.804-3.086,2.233-5.343,2.233c-1.028,0-1.63-0.527-1.63-1.28
c0-0.752,0.777-3.612,6.848-6.471c-1.229,0.326-8.303,3.687-8.253,8.403c0,1.003,1.304,1.53,1.982,1.53
c0.677,0,1.781-0.125,3.11-0.753c1.33-0.627,7.174-4.339,6.17-5.995c-0.276-0.451-0.903-0.275-0.903-0.275
s2.834-2.006,1.856-3.336S13.459,3.707,12.431,5.765z"/>
</g>
</g>
</g>
<g id="Type">
<g>
<path fill="#FFFFFF" d="M32,8.091h-2v2h-1V6.083h1v-1h2v1h1v4.008h-1V8.091z M32,7.083V6.091h-2v0.992H32z"/>
<path fill="#FFFFFF" d="M37,7.083h2v2.008h-1v1h-2v-1h-1V6.083h1v-1h3v1.008h-3v2.992h1.752H38V8.091h-1V7.083z"/>
<path fill="#FFFFFF" d="M41,5.083h3v1h1v1.008h-1v1h-2v2h-1V5.083z M44,7.083V6.091h-2v0.992H44z"/>
<path fill="#FFFFFF" d="M47,5.083h1v4h1.752H50v1.008h-3V5.083z"/>
</g>
</g>
<g id="Guides" display="none">
</g>
</svg>

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 735 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

View File

@@ -0,0 +1,79 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="257.50296"
height="257.50296"
id="svg2"
version="1.1"
inkscape:version="0.47 r22583"
sodipodi:docname="broken.svg">
<defs
id="defs4">
<inkscape:perspective
sodipodi:type="inkscape:persp3d"
inkscape:vp_x="0 : 526.18109 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_z="744.09448 : 526.18109 : 1"
inkscape:persp3d-origin="372.04724 : 350.78739 : 1"
id="perspective10" />
</defs>
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="1.0181848"
inkscape:cx="18.460113"
inkscape:cy="120.47806"
inkscape:document-units="px"
inkscape:current-layer="text3590"
showgrid="false"
inkscape:window-width="1280"
inkscape:window-height="1005"
inkscape:window-x="0"
inkscape:window-y="0"
inkscape:window-maximized="0" />
<metadata
id="metadata7">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title />
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:label="Calque 1"
inkscape:groupmode="layer"
id="layer1"
transform="translate(-124.46281,-467.53928)">
<rect
style="fill:none;stroke:#000000;stroke-width:2;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:16, 16;stroke-dashoffset:10"
id="rect2816"
width="255.50296"
height="255.50296"
x="125.46281"
y="468.53928" />
<g
style="font-size:40px;font-style:normal;font-weight:normal;fill:#ff0000;fill-opacity:1;stroke:none;font-family:Bitstream Vera Sans"
id="text3590">
<path
d="m 316.935,527.9314 -49.43848,66.52832 52.00195,70.19043 -26.48925,0 -39.79493,-53.71094 -39.79492,53.71094 -26.48926,0 53.10059,-71.53321 -48.58398,-65.18554 26.48925,0 36.25489,48.70605 36.25488,-48.70605 26.48926,0"
style="font-size:250px;fill:#ff0000"
id="path2816" />
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 838 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 331 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 318 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 910 B

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 8.8 KiB

BIN
ivatar/static/img/logo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 557 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

View File

@@ -0,0 +1,83 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="257.5"
height="257.5"
id="svg2"
version="1.1"
inkscape:version="0.48.1 r9760"
sodipodi:docname="missing.svg">
<defs
id="defs4">
<inkscape:perspective
sodipodi:type="inkscape:persp3d"
inkscape:vp_x="0 : 526.18109 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_z="744.09448 : 526.18109 : 1"
inkscape:persp3d-origin="372.04724 : 350.78739 : 1"
id="perspective10" />
</defs>
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="1.0181848"
inkscape:cx="245.81958"
inkscape:cy="126.91355"
inkscape:document-units="px"
inkscape:current-layer="layer1"
showgrid="false"
inkscape:window-width="1280"
inkscape:window-height="781"
inkscape:window-x="0"
inkscape:window-y="0"
inkscape:window-maximized="0"
fit-margin-top="0"
fit-margin-left="0"
fit-margin-right="0"
fit-margin-bottom="0" />
<metadata
id="metadata7">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title />
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:label="Calque 1"
inkscape:groupmode="layer"
id="layer1"
transform="translate(-124.46875,-467.53125)">
<rect
style="fill:none;stroke:#000000;stroke-width:2;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:16, 16;stroke-dashoffset:10"
id="rect2816"
width="255.50296"
height="255.50296"
x="125.46281"
y="468.53928" />
<g
style="font-size:40px;font-style:normal;font-weight:normal;fill:#000000;fill-opacity:1;stroke:none;font-family:Bitstream Vera Sans"
id="text3590">
<path
d="m 238.1264,645.70483 19.82422,0 0,24.80469 -19.82422,0 0,-24.80469 m 19.23829,-14.35546 -18.65235,0 0,-15.03907 c -4e-5,-6.57546 0.91142,-11.9791 2.73438,-16.21093 1.82287,-4.2317 5.66401,-9.14706 11.52343,-14.7461 l 8.78907,-8.6914 c 3.71087,-3.45043 6.38014,-6.70563 8.00781,-9.76563 1.69264,-3.05979 2.53899,-6.18479 2.53906,-9.375 -7e-5,-5.79415 -2.14851,-10.48165 -6.44531,-14.0625 -4.23183,-3.5806 -9.86334,-5.37096 -16.89453,-5.37109 -5.14328,1.3e-4 -10.64457,1.13945 -16.50391,3.41797 -5.7943,2.27877 -11.84898,5.59908 -18.16406,9.96093 l 0,-18.35937 c 6.11977,-3.7108 12.30466,-6.47772 18.55469,-8.30078 6.31506,-1.82277 12.82547,-2.73423 19.53125,-2.73438 11.9791,1.5e-4 21.58195,3.1577 28.80859,9.47266 7.29158,6.31523 10.93741,14.64856 10.9375,25 -9e-5,4.94802 -1.17197,9.66807 -3.51562,14.16015 -2.34384,4.42718 -6.4454,9.4402 -12.30469,15.03907 l -8.59375,8.39843 c -3.05996,3.05997 -5.24095,5.46882 -6.54297,7.22657 -1.23704,1.69277 -2.11595,3.35293 -2.63672,4.98047 -0.39068,1.36725 -0.68365,3.0274 -0.87891,4.98046 -0.19537,1.95319 -0.29302,4.62245 -0.29296,8.00782 l 0,12.01172"
style="font-size:200px"
id="path2987" />
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 3.6 KiB

BIN
ivatar/static/img/mm.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

94
ivatar/static/img/mm.svg Normal file
View File

@@ -0,0 +1,94 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="585"
height="585"
id="svg2"
version="1.1"
inkscape:version="0.48.1 r9760"
sodipodi:docname="mm.svg">
<defs
id="defs4" />
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="0.7"
inkscape:cx="363.16555"
inkscape:cy="281.80281"
inkscape:document-units="px"
inkscape:current-layer="layer1"
showgrid="false"
fit-margin-top="0"
fit-margin-left="0"
fit-margin-right="0"
fit-margin-bottom="0"
inkscape:window-width="1172"
inkscape:window-height="777"
inkscape:window-x="0"
inkscape:window-y="0"
inkscape:window-maximized="0" />
<metadata
id="metadata7">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:label="Calque 1"
inkscape:groupmode="layer"
id="layer1"
transform="translate(-128.57143,-128.79074)">
<rect
style="fill:#808080;fill-opacity:1;stroke:none"
id="rect3755"
width="585"
height="585"
x="128.57143"
y="128.79074" />
<path
sodipodi:type="arc"
style="fill:#ffffff;fill-opacity:1;stroke:none"
id="path2985"
sodipodi:cx="451.42856"
sodipodi:cy="329.50504"
sodipodi:rx="165.71428"
sodipodi:ry="165.71428"
d="m 617.14284,329.50504 c 0,91.52146 -74.19281,165.71427 -165.71428,165.71427 -91.52147,0 -165.71428,-74.19281 -165.71428,-165.71427 0,-91.52147 74.19281,-165.71428 165.71428,-165.71428 91.52147,0 165.71428,74.19281 165.71428,165.71428 z"
transform="translate(-30.357132,0)" />
<path
sodipodi:type="star"
style="fill:#ffffff;fill-opacity:1;stroke:none"
id="path3759"
sodipodi:sides="3"
sodipodi:cx="417.14285"
sodipodi:cy="343.79074"
sodipodi:r1="330.14529"
sodipodi:r2="165.07265"
sodipodi:arg1="2.6179939"
sodipodi:arg2="3.6651914"
inkscape:flatsided="true"
inkscape:rounded="0"
inkscape:randomized="0"
d="M 131.22864,508.86338 417.14286,13.645447 703.05706,508.86339 z"
inkscape:transform-center-y="-66.822037"
transform="matrix(0.80383817,0,0,0.80960764,85.756082,301.79749)" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.9 KiB

BIN
ivatar/static/img/mm/1.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 85 B

BIN
ivatar/static/img/mm/10.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 169 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 466 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 519 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 412 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 545 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 484 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 478 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 445 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 514 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 598 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 447 B

BIN
ivatar/static/img/mm/11.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 177 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 493 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 485 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 501 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 550 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 496 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 430 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 500 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 522 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 549 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 487 B

BIN
ivatar/static/img/mm/12.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 175 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 534 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 522 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 555 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 556 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 561 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 487 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 551 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 519 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 541 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 668 B

BIN
ivatar/static/img/mm/13.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 184 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 543 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 616 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 582 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 612 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 591 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 632 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 612 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 540 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 655 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 569 B

BIN
ivatar/static/img/mm/14.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 192 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 657 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 631 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 716 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 609 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 648 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 617 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 608 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 672 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 680 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 709 B

BIN
ivatar/static/img/mm/15.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 188 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 644 B

Some files were not shown because too many files have changed in this diff Show More