Initial commit
3
.gitignore
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
__pycache__
|
||||
/db.sqlite3
|
||||
/static/
|
||||
47
config.py
Normal 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
@@ -0,0 +1,2 @@
|
||||
SESSION_COOKIE_SECURE = False
|
||||
DEBUG = True
|
||||
1
ivatar/__init__.py
Normal file
@@ -0,0 +1 @@
|
||||
app_label = __name__
|
||||
15
ivatar/context_processors.py
Normal 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
|
||||
1
ivatar/ivataraccount/__init__.py
Normal file
@@ -0,0 +1 @@
|
||||
app_label = __name__
|
||||
3
ivatar/ivataraccount/admin.py
Normal file
@@ -0,0 +1,3 @@
|
||||
from django.contrib import admin
|
||||
|
||||
# Register your models here.
|
||||
5
ivatar/ivataraccount/apps.py
Normal file
@@ -0,0 +1,5 @@
|
||||
from django.apps import AppConfig
|
||||
|
||||
|
||||
class IvataraccountConfig(AppConfig):
|
||||
name = 'ivataraccount'
|
||||
39
ivatar/ivataraccount/gravatar.py
Normal 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'
|
||||
}
|
||||
108
ivatar/ivataraccount/migrations/0001_initial.py
Normal 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),
|
||||
),
|
||||
]
|
||||
@@ -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)),
|
||||
],
|
||||
),
|
||||
]
|
||||
0
ivatar/ivataraccount/migrations/__init__.py
Normal file
212
ivatar/ivataraccount/models.py
Normal 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]
|
||||
38
ivatar/ivataraccount/templates/login.html
Normal 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' %}">
|
||||
<a href="/">{% trans 'Cancel' %}</a></p>
|
||||
|
||||
</form>
|
||||
|
||||
{% endblock content %}
|
||||
47
ivatar/ivataraccount/templates/new.html
Normal 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' %}">
|
||||
<a href="/">{% trans 'Cancel' %}</a></p>
|
||||
|
||||
</form>
|
||||
|
||||
{% endblock content %}
|
||||
51
ivatar/ivataraccount/templates/password_change.html
Normal 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' %}" />
|
||||
<a href="{% url 'profile' %}">{% trans 'Cancel' %}</a></p>
|
||||
|
||||
</form>
|
||||
|
||||
{% endblock content %}
|
||||
89
ivatar/ivataraccount/templates/profile.html
Normal 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 %}
|
||||
29
ivatar/ivataraccount/test_views.py
Normal 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)
|
||||
3
ivatar/ivataraccount/tests.py
Normal file
@@ -0,0 +1,3 @@
|
||||
from django.test import TestCase
|
||||
|
||||
# Create your tests here.
|
||||
19
ivatar/ivataraccount/urls.py
Normal 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'),
|
||||
]
|
||||
47
ivatar/ivataraccount/views.py
Normal 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
@@ -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
|
||||
4
ivatar/static/.well-known/browser-hints
Normal file
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"small-hdrs": true,
|
||||
"no-referer": true
|
||||
}
|
||||
187
ivatar/static/css/ivatar.css
Normal 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;
|
||||
}
|
||||
2
ivatar/static/css/jcrop.css
Normal 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
|
After Width: | Height: | Size: 329 B |
BIN
ivatar/static/img/agpl_button.png
Normal file
|
After Width: | Height: | Size: 503 B |
192
ivatar/static/img/agpl_button.svg
Normal 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 |
BIN
ivatar/static/img/broken.gif
Normal file
|
After Width: | Height: | Size: 735 B |
BIN
ivatar/static/img/broken.jpg
Normal file
|
After Width: | Height: | Size: 3.7 KiB |
BIN
ivatar/static/img/broken.png
Normal file
|
After Width: | Height: | Size: 1.6 KiB |
79
ivatar/static/img/broken.svg
Normal 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 |
BIN
ivatar/static/img/deadbeef.png
Normal file
|
After Width: | Height: | Size: 838 B |
BIN
ivatar/static/img/delete_button.png
Normal file
|
After Width: | Height: | Size: 331 B |
BIN
ivatar/static/img/favicon.ico
Normal file
|
After Width: | Height: | Size: 318 B |
BIN
ivatar/static/img/https_lock.png
Normal file
|
After Width: | Height: | Size: 910 B |
95
ivatar/static/img/libravatar_logo.svg
Normal file
|
After Width: | Height: | Size: 8.8 KiB |
BIN
ivatar/static/img/logo.png
Normal file
|
After Width: | Height: | Size: 557 B |
BIN
ivatar/static/img/missing.png
Normal file
|
After Width: | Height: | Size: 1.0 KiB |
83
ivatar/static/img/missing.svg
Normal 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
|
After Width: | Height: | Size: 4.2 KiB |
94
ivatar/static/img/mm.svg
Normal 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
|
After Width: | Height: | Size: 85 B |
BIN
ivatar/static/img/mm/10.png
Normal file
|
After Width: | Height: | Size: 169 B |
BIN
ivatar/static/img/mm/100.png
Normal file
|
After Width: | Height: | Size: 466 B |
BIN
ivatar/static/img/mm/101.png
Normal file
|
After Width: | Height: | Size: 519 B |
BIN
ivatar/static/img/mm/102.png
Normal file
|
After Width: | Height: | Size: 412 B |
BIN
ivatar/static/img/mm/103.png
Normal file
|
After Width: | Height: | Size: 545 B |
BIN
ivatar/static/img/mm/104.png
Normal file
|
After Width: | Height: | Size: 484 B |
BIN
ivatar/static/img/mm/105.png
Normal file
|
After Width: | Height: | Size: 478 B |
BIN
ivatar/static/img/mm/106.png
Normal file
|
After Width: | Height: | Size: 445 B |
BIN
ivatar/static/img/mm/107.png
Normal file
|
After Width: | Height: | Size: 514 B |
BIN
ivatar/static/img/mm/108.png
Normal file
|
After Width: | Height: | Size: 598 B |
BIN
ivatar/static/img/mm/109.png
Normal file
|
After Width: | Height: | Size: 447 B |
BIN
ivatar/static/img/mm/11.png
Normal file
|
After Width: | Height: | Size: 177 B |
BIN
ivatar/static/img/mm/110.png
Normal file
|
After Width: | Height: | Size: 493 B |
BIN
ivatar/static/img/mm/111.png
Normal file
|
After Width: | Height: | Size: 485 B |
BIN
ivatar/static/img/mm/112.png
Normal file
|
After Width: | Height: | Size: 501 B |
BIN
ivatar/static/img/mm/113.png
Normal file
|
After Width: | Height: | Size: 550 B |
BIN
ivatar/static/img/mm/114.png
Normal file
|
After Width: | Height: | Size: 496 B |
BIN
ivatar/static/img/mm/115.png
Normal file
|
After Width: | Height: | Size: 430 B |
BIN
ivatar/static/img/mm/116.png
Normal file
|
After Width: | Height: | Size: 500 B |
BIN
ivatar/static/img/mm/117.png
Normal file
|
After Width: | Height: | Size: 522 B |
BIN
ivatar/static/img/mm/118.png
Normal file
|
After Width: | Height: | Size: 549 B |
BIN
ivatar/static/img/mm/119.png
Normal file
|
After Width: | Height: | Size: 487 B |
BIN
ivatar/static/img/mm/12.png
Normal file
|
After Width: | Height: | Size: 175 B |
BIN
ivatar/static/img/mm/120.png
Normal file
|
After Width: | Height: | Size: 534 B |
BIN
ivatar/static/img/mm/121.png
Normal file
|
After Width: | Height: | Size: 522 B |
BIN
ivatar/static/img/mm/122.png
Normal file
|
After Width: | Height: | Size: 555 B |
BIN
ivatar/static/img/mm/123.png
Normal file
|
After Width: | Height: | Size: 556 B |
BIN
ivatar/static/img/mm/124.png
Normal file
|
After Width: | Height: | Size: 561 B |
BIN
ivatar/static/img/mm/125.png
Normal file
|
After Width: | Height: | Size: 487 B |
BIN
ivatar/static/img/mm/126.png
Normal file
|
After Width: | Height: | Size: 551 B |
BIN
ivatar/static/img/mm/127.png
Normal file
|
After Width: | Height: | Size: 519 B |
BIN
ivatar/static/img/mm/128.png
Normal file
|
After Width: | Height: | Size: 541 B |
BIN
ivatar/static/img/mm/129.png
Normal file
|
After Width: | Height: | Size: 668 B |
BIN
ivatar/static/img/mm/13.png
Normal file
|
After Width: | Height: | Size: 184 B |
BIN
ivatar/static/img/mm/130.png
Normal file
|
After Width: | Height: | Size: 543 B |
BIN
ivatar/static/img/mm/131.png
Normal file
|
After Width: | Height: | Size: 616 B |
BIN
ivatar/static/img/mm/132.png
Normal file
|
After Width: | Height: | Size: 582 B |
BIN
ivatar/static/img/mm/133.png
Normal file
|
After Width: | Height: | Size: 612 B |
BIN
ivatar/static/img/mm/134.png
Normal file
|
After Width: | Height: | Size: 591 B |
BIN
ivatar/static/img/mm/135.png
Normal file
|
After Width: | Height: | Size: 632 B |
BIN
ivatar/static/img/mm/136.png
Normal file
|
After Width: | Height: | Size: 612 B |
BIN
ivatar/static/img/mm/137.png
Normal file
|
After Width: | Height: | Size: 540 B |
BIN
ivatar/static/img/mm/138.png
Normal file
|
After Width: | Height: | Size: 655 B |
BIN
ivatar/static/img/mm/139.png
Normal file
|
After Width: | Height: | Size: 569 B |
BIN
ivatar/static/img/mm/14.png
Normal file
|
After Width: | Height: | Size: 192 B |
BIN
ivatar/static/img/mm/140.png
Normal file
|
After Width: | Height: | Size: 657 B |
BIN
ivatar/static/img/mm/141.png
Normal file
|
After Width: | Height: | Size: 631 B |
BIN
ivatar/static/img/mm/142.png
Normal file
|
After Width: | Height: | Size: 716 B |
BIN
ivatar/static/img/mm/143.png
Normal file
|
After Width: | Height: | Size: 609 B |
BIN
ivatar/static/img/mm/144.png
Normal file
|
After Width: | Height: | Size: 648 B |
BIN
ivatar/static/img/mm/145.png
Normal file
|
After Width: | Height: | Size: 617 B |
BIN
ivatar/static/img/mm/146.png
Normal file
|
After Width: | Height: | Size: 608 B |
BIN
ivatar/static/img/mm/147.png
Normal file
|
After Width: | Height: | Size: 672 B |
BIN
ivatar/static/img/mm/148.png
Normal file
|
After Width: | Height: | Size: 680 B |
BIN
ivatar/static/img/mm/149.png
Normal file
|
After Width: | Height: | Size: 709 B |
BIN
ivatar/static/img/mm/15.png
Normal file
|
After Width: | Height: | Size: 188 B |
BIN
ivatar/static/img/mm/150.png
Normal file
|
After Width: | Height: | Size: 644 B |