Add accounts app and ability to give badges to users
This commit is contained in:
parent
3826e49168
commit
d47ec4635e
13 changed files with 189 additions and 4 deletions
0
accounts/__init__.py
Normal file
0
accounts/__init__.py
Normal file
18
accounts/admin.py
Normal file
18
accounts/admin.py
Normal file
|
@ -0,0 +1,18 @@
|
|||
from django.contrib import admin
|
||||
|
||||
from .models import Account, Badge, BadgeGrant
|
||||
|
||||
# Register your models here.
|
||||
class AccountAdmin(admin.ModelAdmin):
|
||||
list_display = ('user', 'acctname')
|
||||
admin.site.register(Account, AccountAdmin)
|
||||
|
||||
class BadgeAdmin(admin.ModelAdmin):
|
||||
list_display = ('name', 'img_url')
|
||||
admin.site.register(Badge, BadgeAdmin)
|
||||
|
||||
class GrantAdmin(admin.ModelAdmin):
|
||||
list_display = ('badge', 'account', 'expires', 'granted_by')
|
||||
admin.site.register(BadgeGrant, GrantAdmin)
|
||||
|
||||
|
5
accounts/apps.py
Normal file
5
accounts/apps.py
Normal file
|
@ -0,0 +1,5 @@
|
|||
from django.apps import AppConfig
|
||||
|
||||
|
||||
class AccountsConfig(AppConfig):
|
||||
name = 'accounts'
|
55
accounts/migrations/0001_initial.py
Normal file
55
accounts/migrations/0001_initial.py
Normal file
|
@ -0,0 +1,55 @@
|
|||
# Generated by Django 2.0 on 2018-02-02 22:05
|
||||
|
||||
from django.conf import settings
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
initial = True
|
||||
|
||||
dependencies = [
|
||||
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='Account',
|
||||
fields=[
|
||||
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('acctname', models.CharField(blank=True, max_length=150, verbose_name='Account Name')),
|
||||
],
|
||||
options={
|
||||
'ordering': ('user__username',),
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='Badge',
|
||||
fields=[
|
||||
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('name', models.CharField(max_length=64, verbose_name='Badge Name')),
|
||||
('img_url', models.URLField(verbose_name='Badge Image')),
|
||||
],
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='BadgeGrant',
|
||||
fields=[
|
||||
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('expires', models.DateTimeField()),
|
||||
('account', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='accounts.Account')),
|
||||
('badge', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='accounts.Badge')),
|
||||
('granted_by', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, to=settings.AUTH_USER_MODEL)),
|
||||
],
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='account',
|
||||
name='badges',
|
||||
field=models.ManyToManyField(through='accounts.BadgeGrant', to='accounts.Badge'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='account',
|
||||
name='user',
|
||||
field=models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL),
|
||||
),
|
||||
]
|
0
accounts/migrations/__init__.py
Normal file
0
accounts/migrations/__init__.py
Normal file
70
accounts/models.py
Normal file
70
accounts/models.py
Normal file
|
@ -0,0 +1,70 @@
|
|||
from django.db import models
|
||||
from django.contrib.sites.models import Site
|
||||
from django.contrib.auth.models import User, Group, AnonymousUser
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
import pytz
|
||||
import datetime
|
||||
import hashlib
|
||||
|
||||
class Account(models.Model):
|
||||
" Store account information about a user "
|
||||
|
||||
user = models.OneToOneField(User, on_delete=models.CASCADE)
|
||||
acctname = models.CharField(_("Account Name"), max_length=150, blank=True)
|
||||
|
||||
badges = models.ManyToManyField('Badge', through='BadgeGrant')
|
||||
|
||||
class Meta:
|
||||
ordering = ('user__username',)
|
||||
|
||||
def __str__(self):
|
||||
try:
|
||||
if self.acctname:
|
||||
return self.acctname
|
||||
return "%s" % self.user.username
|
||||
except:
|
||||
return "Unknown Account"
|
||||
|
||||
|
||||
def _getUserAccount(self):
|
||||
if not self.is_authenticated:
|
||||
return Account()
|
||||
|
||||
profile, created = Account.objects.get_or_create(user=self)
|
||||
|
||||
if created:
|
||||
if self.first_name:
|
||||
if self.last_name:
|
||||
profile.acctname = '%s %s' % (self.first_name, self.last_name)
|
||||
else:
|
||||
profile.acctname = self.first_name
|
||||
|
||||
profile.save()
|
||||
|
||||
return profile
|
||||
|
||||
def _getAnonAccount(self):
|
||||
return Account(acctname=_('Anonymous User'))
|
||||
|
||||
User.account = property(_getUserAccount)
|
||||
AnonymousUser.account = property(_getAnonAccount)
|
||||
|
||||
class Badge(models.Model):
|
||||
name = models.CharField(_('Badge Name'), max_length=64, blank=False, null=False)
|
||||
img_url = models.URLField(_('Badge Image'), blank=False, null=False)
|
||||
|
||||
def __str__(self):
|
||||
return self.name
|
||||
|
||||
class BadgeGrant(models.Model):
|
||||
badge = models.ForeignKey(Badge, on_delete=models.CASCADE)
|
||||
account = models.ForeignKey(Account, on_delete=models.CASCADE)
|
||||
|
||||
expires = models.DateTimeField()
|
||||
granted_by = models.ForeignKey(User, on_delete=models.SET_NULL, null=True)
|
||||
|
||||
def __str__(self):
|
||||
return '%s for %s' % (self.badge.name, self.account.acctname)
|
||||
|
||||
|
3
accounts/tests.py
Normal file
3
accounts/tests.py
Normal file
|
@ -0,0 +1,3 @@
|
|||
from django.test import TestCase
|
||||
|
||||
# Create your tests here.
|
3
accounts/views.py
Normal file
3
accounts/views.py
Normal file
|
@ -0,0 +1,3 @@
|
|||
from django.shortcuts import render
|
||||
|
||||
# Create your views here.
|
|
@ -46,6 +46,7 @@ INSTALLED_APPS = [
|
|||
|
||||
'get_together',
|
||||
'events',
|
||||
'accounts',
|
||||
]
|
||||
|
||||
LOGIN_URL = 'login'
|
||||
|
|
BIN
get_together/static/img/badges/gold_tier.png
Normal file
BIN
get_together/static/img/badges/gold_tier.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 2 KiB |
BIN
get_together/static/img/badges/silver_tier.png
Normal file
BIN
get_together/static/img/badges/silver_tier.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1 KiB |
|
@ -1,6 +1,20 @@
|
|||
{% extends "get_together/base.html" %}
|
||||
{% load markup %}
|
||||
|
||||
{% block styles %}
|
||||
<style>
|
||||
.gt-profile {
|
||||
position: relative;
|
||||
}
|
||||
.gt-profile .gt-profile-badges {
|
||||
position: absolute;
|
||||
top: 16px;
|
||||
left: 6px;
|
||||
|
||||
}
|
||||
</style>
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="fluid-container">
|
||||
<div class="row">
|
||||
|
@ -38,8 +52,9 @@
|
|||
</div>
|
||||
{% for attendee in attendee_list %}
|
||||
<div class="row mb-3">
|
||||
<div class="col media">
|
||||
<img class="mr-1" src="{{attendee.user.avatar}}" width="32px" height="32px">
|
||||
<div class="col media gt-profile">
|
||||
<img class="mr-1 gt-profile-avatar" src="{{attendee.user.avatar}}" width="32px" height="32px">
|
||||
<span class="gt-profile-badges">{% for badge in attendee.user.user.account.badges.all %}<img class="mr-0 gt-profile-badge" src="{{badge.img_url}}" title="{{badge.name}}" width="16px" height="16px">{% endfor %}</span>
|
||||
<div class="media-body">
|
||||
<h6 class="mt-2 mb-0">{{attendee.user}} <span class="badge badge-success align-top">{{ attendee.status_name }}</span></h6>
|
||||
{% if attendee.role > 0 %}<small class="text-muted">{{ attendee.role_name }}</small>{% endif %}
|
||||
|
|
|
@ -1,6 +1,20 @@
|
|||
{% extends "get_together/base.html" %}
|
||||
{% load markup %}
|
||||
|
||||
{% block styles %}
|
||||
<style>
|
||||
.gt-profile {
|
||||
position: relative;
|
||||
}
|
||||
.gt-profile .gt-profile-badges {
|
||||
position: absolute;
|
||||
top: 16px;
|
||||
left: 6px;
|
||||
|
||||
}
|
||||
</style>
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="fluid-container">
|
||||
<div class="row">
|
||||
|
@ -43,8 +57,9 @@
|
|||
<h4>Members</h4><hr/>
|
||||
{% for member in member_list %}
|
||||
<div class="row mb-3">
|
||||
<div class="col media">
|
||||
<img class="mr-1" src="{{member.user.avatar}}" width="32px" height="32px">
|
||||
<div class="col media gt-profile">
|
||||
<img class="mr-1 gt-profile-avatar" src="{{member.user.avatar}}" width="32px" height="32px">
|
||||
<span class="gt-profile-badges">{% for badge in member.user.user.account.badges.all %}<img class="mr-0 gt-profile-badge" src="{{badge.img_url}}" title="{{badge.name}}" width="16px" height="16px">{% endfor %}</span>
|
||||
<div class="media-body">
|
||||
<h6 class="mt-0 mb-0">{{member.user}}</h6>
|
||||
{% if member.role > 0 %}<small class="text-muted">{{ member.role_name }}</small>{% endif %}
|
||||
|
|
Loading…
Reference in a new issue