Initial profile management page

This commit is contained in:
Oliver Marks 2017-01-06 20:35:56 +00:00
parent 2cef5bf87a
commit 9abd81245e
17 changed files with 218 additions and 13 deletions

41
.drone.yml Normal file
View File

@ -0,0 +1,41 @@
pipeline:
backend:
commands:
- python manage.py test
#volumes:
# postgres_data_dev: {}
# postgres_backup_dev: {}
services:
postgres:
build: ./compose/postgres
# volumes:
# - postgres_data_dev:/var/lib/postgresql/data
# - postgres_backup_dev:/backups
environment:
- POSTGRES_USER=mhackspace
# django:
# build:
# context: .
# dockerfile: ./compose/django/Dockerfile-dev
# command: /start-dev.sh
# depends_on:
# - postgres
# environment:
# - POSTGRES_USER=mhackspace
# - USE_DOCKER=yes
# volumes:
# - .:/app
# ports:
# - "8180:8000"
# links:
# - postgres
# - mailhog
mailhog:
image: mailhog/mailhog
ports:
- "8125:8025"

1
.gitignore vendored Normal file
View File

@ -0,0 +1 @@
media/*

View File

@ -40,3 +40,11 @@ docker-compose -f dev.yml run django python manage.py migrate
#+BEGIN_SRC sh
docker-compose -f dev.yml run django python manage.py createsuperuser
#+END_SRC
** Migrations / Managing default data
If you want to export some data you entered into the admin area you can use =dumpdata= and =loaddata= to export and import.
#+BEGIN_SRC sh
docker-compose -fdev.yml run django python manage.py dumpdata feeds > mhackspace/feeds/fixtures/default.json
#+END_SRC

View File

@ -45,10 +45,10 @@ THIRD_PARTY_APPS = (
# Apps specific for this project go here.
LOCAL_APPS = (
# custom users app
# Your stuff: custom apps go here
'mhackspace.users.apps.UsersConfig',
'mhackspace.feeds',
'mhackspace.contact',
# Your stuff: custom apps go here
)
# See: https://docs.djangoproject.com/en/dev/ref/settings/#installed-apps

View File

@ -17,6 +17,7 @@ urlpatterns = [
url(r'^contact/$', contact, name='contact'),
# need to be logged in for these urls
# Django Admin, use {% url 'admin:index' %}
url(settings.ADMIN_URL, admin.site.urls),

View File

@ -34,5 +34,5 @@ services:
mailhog:
image: mailhog/mailhog
ports:
- "8025:8125"
- "8125:8025"

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

View File

@ -28,6 +28,9 @@
<body>
<div class="m-b-1">
<a id="mini_logo" href="/login">
<img src="/static/images/hackspace.png" class="mini-logo">
</a>
<nav class="navbar navbar-dark navbar-static-top bg-inverse">
<div class="container">
<a class="navbar-brand" href="/">Maidstone Hackspace</a>

View File

@ -6,6 +6,32 @@
{% block content %}
<div class="container">
<h2>Profile</h2>
<div class="row">
<div class="col-md-6">
<img src="{{ MEDIA_URL }}{{ user.image }}" alt="Profile image"/>
<p>{{ user.username }}</p>
<p>{{ user.name }}</p>
<p>{{ user.email }}</p>
<p>Last login {{ user.last_login}}</p>
<p>Member since</p>
<p>Description: {{ blurb.description }}</p>
<p>Skills: {{ blurb.description }}</p>
</div>
<div class="col-md-6">
<div id="membercard" class="registered">
<div class="date">Joined </div>
<div class="container">
<div class="middle">
<p>MHS{{ user.id|stringformat:"05d" }}</p><p>Change me</p>
<a href="/profile/membership/cancel">Cancel Membership</a>
</div>
</div>
</div>
</div>
</div>
<div class="row">
<div class="col-sm-12">

View File

@ -5,9 +5,10 @@
{% block content %}
<h1>{{ user.username }}</h1>
<form class="form-horizontal" method="post" action="{% url 'users:update' %}">
<form class="form-horizontal" method="post" action="{% url 'users:update' %}" enctype="multipart/form-data">
{% csrf_token %}
{{ form|crispy }}
{{ form_blurb|crispy }}
<div class="control-group">
<div class="controls">
<button type="submit" class="btn">Update</button>

View File

@ -36,7 +36,7 @@ class MyUserAdmin(AuthUserAdmin):
form = MyUserChangeForm
add_form = MyUserCreationForm
fieldsets = (
('User Profile', {'fields': ('name',)}),
('User Profile', {'fields': ('name', 'image')}),
) + AuthUserAdmin.fieldsets
list_display = ('username', 'name', 'is_superuser')
search_fields = ['name']

10
mhackspace/users/forms.py Normal file
View File

@ -0,0 +1,10 @@
# -*- coding: utf-8 -*-
from django.db import models
from django.forms import ModelForm
from .models import UserBlurb
class UserBlurbForm(ModelForm):
class Meta:
model = UserBlurb
exclude = ['user']

View File

@ -0,0 +1,36 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.10.4 on 2017-01-06 08:53
from __future__ import unicode_literals
from django.conf import settings
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('users', '0001_initial'),
]
operations = [
migrations.CreateModel(
name='Membership',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('payment', models.DecimalField(decimal_places=2, max_digits=6)),
('date', models.DateTimeField()),
('reference', models.CharField(max_length=255)),
('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)),
],
),
migrations.CreateModel(
name='UserBlurb',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('skills', models.CharField(max_length=255)),
('description', models.TextField()),
('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)),
],
),
]

View File

@ -0,0 +1,20 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.10.4 on 2017-01-06 19:03
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('users', '0002_membership_userblurb'),
]
operations = [
migrations.AddField(
model_name='user',
name='image',
field=models.ImageField(blank=True, null=True, upload_to='/upload/avatars'),
),
]

View File

@ -0,0 +1,24 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.10.4 on 2017-01-06 20:30
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('users', '0003_user_image'),
]
operations = [
migrations.RenameModel(
old_name='Membership',
new_name='UserMembership',
),
migrations.AlterField(
model_name='user',
name='image',
field=models.ImageField(blank=True, null=True, upload_to='avatars/'),
),
]

View File

@ -1,6 +1,7 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals, absolute_import
from django.conf import settings
from django.contrib.auth.models import AbstractUser
from django.core.urlresolvers import reverse
from django.db import models
@ -10,13 +11,24 @@ from django.utils.translation import ugettext_lazy as _
@python_2_unicode_compatible
class User(AbstractUser):
# First Name and Last Name do not cover name patterns
# around the globe.
name = models.CharField(_('Name of User'), blank=True, max_length=255)
image = models.ImageField(upload_to='avatars/', blank=True, null=True)
def __str__(self):
return self.username
def get_absolute_url(self):
return reverse('users:detail', kwargs={'username': self.username})
class UserBlurb(models.Model):
user = models.ForeignKey(settings.AUTH_USER_MODEL)
skills = models.CharField(max_length=255)
description = models.TextField()
class UserMembership(models.Model):
user = models.ForeignKey(settings.AUTH_USER_MODEL)
payment = models.DecimalField(max_digits=6, decimal_places=2)
date = models.DateTimeField()
reference = models.CharField(max_length=255)

View File

@ -7,7 +7,10 @@ from django.views.generic import DetailView, ListView, RedirectView, UpdateView
from django.contrib.auth.mixins import LoginRequiredMixin
from .models import User
from .models import UserBlurb
from .models import UserMembership
from .forms import UserBlurbForm
class UserDetailView(LoginRequiredMixin, DetailView):
model = User
@ -15,6 +18,12 @@ class UserDetailView(LoginRequiredMixin, DetailView):
slug_field = 'username'
slug_url_kwarg = 'username'
def get_context_data(self, **kwargs):
# xxx will be available in the template as the related objects
context = super(UserDetailView, self).get_context_data(**kwargs)
context['blurb'] = UserBlurb.objects.filter(user=self.get_object()).first()
context['membership'] = UserMembership.objects.filter(user=self.get_object()).first()
return context
class UserRedirectView(LoginRequiredMixin, RedirectView):
permanent = False
@ -25,21 +34,34 @@ class UserRedirectView(LoginRequiredMixin, RedirectView):
class UserUpdateView(LoginRequiredMixin, UpdateView):
fields = ['name', ]
# we already imported User in the view code above, remember?
fields = ['name', 'image', ]
model = User
# send the user back to their own page after a successful update
def get_success_url(self):
return reverse('users:detail',
kwargs={'username': self.request.user.username})
return reverse(
'users:detail',
kwargs={'username': self.request.user.username})
def get_context_data(self, **kwargs):
context = super(UserUpdateView, self).get_context_data(**kwargs)
profile = UserBlurb.objects.filter(user=self.get_object()).first()
context['form_blurb'] = UserBlurbForm(instance=profile)
return context
def get_object(self):
# Only get the User record for the user making the request
return User.objects.get(username=self.request.user.username)
def form_valid(self, form):
profile = UserBlurb.objects.filter(user=self.get_object()).first()
form_blurb = UserBlurbForm(self.request.POST, instance=profile)
if form_blurb.is_valid():
blurb_model = form_blurb.save(commit=False)
blurb_model.user = self.request.user
blurb_model.save()
return super(UserUpdateView, self).form_valid(form)
class UserListView(LoginRequiredMixin, ListView):
model = User