Building out new Account system.

master
Nick Sergeant 2013-02-11 00:40:11 -05:00
parent 83bda92684
commit 141814cbb8
12 changed files with 193 additions and 249 deletions

View File

@ -1,114 +0,0 @@
from django import forms
from accounts.models import UserProfile
import re
class AccountForm(forms.ModelForm):
class Meta:
model = UserProfile
exclude = ('user', 'is_pro', 'stripe_id',)
def clean_blog_title(self):
data = self.cleaned_data['blog_title']
if not re.match('^[ A-Za-z0-9\._-]*$', data):
raise forms.ValidationError('Only spaces, letters, numbers, underscores, dashes, and periods are valid.')
return data
def clean_blog_theme(self):
data = self.cleaned_data['blog_theme']
if not re.match('^[ A-Za-z0-9\._-]*$', data):
raise forms.ValidationError('Only spaces, letters, numbers, underscores, dashes, and periods are valid.')
return data
def clean_blog_domain(self):
data = self.cleaned_data['blog_domain']
if not re.match('^[ A-Za-z0-9\._-]*$', data):
raise forms.ValidationError('Only spaces, letters, numbers, underscores, dashes, and periods are valid.')
return data
def clean_default_editor(self):
data = self.cleaned_data['default_editor']
if not re.match('^[ A-Za-z0-9\._-]*$', data):
raise forms.ValidationError('Only spaces, letters, numbers, underscores, dashes, and periods are valid.')
return data
def clean_editor_theme(self):
data = self.cleaned_data['editor_theme']
if not re.match('^[ A-Za-z0-9\._-]*$', data):
raise forms.ValidationError('Only spaces, letters, numbers, underscores, dashes, and periods are valid.')
return data
def clean_gittip_username(self):
data = self.cleaned_data['gittip_username']
if not re.match('^[ A-Za-z0-9\._-]*$', data):
raise forms.ValidationError('Only spaces, letters, numbers, underscores, dashes, and periods are valid.')
return data
def clean_disqus_shortname(self):
data = self.cleaned_data['disqus_shortname']
if not re.match('^[ A-Za-z0-9\._-]*$', data):
raise forms.ValidationError('Only spaces, letters, numbers, underscores, dashes, and periods are valid.')
return data
def clean_google_analytics_tracking_id(self):
data = self.cleaned_data['google_analytics_tracking_id']
if not re.match('^[ A-Za-z0-9\._-]*$', data):
raise forms.ValidationError('Only spaces, letters, numbers, underscores, dashes, and periods are valid.')
return data
def clean_gauges_site_id(self):
data = self.cleaned_data['gauges_site_id']
if not re.match('^[ A-Za-z0-9\._-]*$', data):
raise forms.ValidationError('Only spaces, letters, numbers, underscores, dashes, and periods are valid.')
return data
def clean_google_ad_client(self):
data = self.cleaned_data['google_ad_client']
if not re.match('^[ A-Za-z0-9\._-]*$', data):
raise forms.ValidationError('Only spaces, letters, numbers, underscores, dashes, and periods are valid.')
return data
def clean_google_ad_slot(self):
data = self.cleaned_data['google_ad_slot']
if not re.match('^[ A-Za-z0-9\._-]*$', data):
raise forms.ValidationError('Only spaces, letters, numbers, underscores, dashes, and periods are valid.')
return data
def clean_google_ad_width(self):
data = self.cleaned_data['google_ad_width']
if not re.match('^[ A-Za-z0-9\._-]*$', data):
raise forms.ValidationError('Only spaces, letters, numbers, underscores, dashes, and periods are valid.')
return data
def clean_google_ad_height(self):
data = self.cleaned_data['google_ad_height']
if not re.match('^[ A-Za-z0-9\._-]*$', data):
raise forms.ValidationError('Only spaces, letters, numbers, underscores, dashes, and periods are valid.')
return data

View File

@ -23,15 +23,15 @@
<li>
<a href="/password/change/">Change Password</a>
</li>
<li ng-class="{active: route.current.scope.section == 'Billing'}">
<a href="/account/billing/">Billing</a>
</li>
<li class="nav-header">Pro</li>
<li ng-class="{active: route.current.scope.section == 'Blogging'}">
<a href="/account/blogging/">Blog settings</a>
<a href="/account/blogging/">Blogging</a>
</li>
<li ng-class="{active: route.current.scope.section == 'Editor'}">
<a href="/account/editor/">Editor settings</a>
<a href="/account/editor/">Editor</a>
</li>
<li ng-class="{active: route.current.scope.section == 'Billing'}">
<a href="/account/billing/">Billing</a>
</li>
</ul>
</aside>

View File

@ -1,8 +1,9 @@
from django.views.generic.simple import direct_to_template
from django.conf.urls.defaults import *
from accounts import views
urlpatterns = patterns('',
url(r'^stats/$', views.stats, name='account-stats'),
url(r'^', views.account, name='account-detail'),
url(r'^stats/$', views.stats, name='account-stats'),
url(r'^', direct_to_template, {'template': 'account.html'}, name='account-detail'),
)

View File

@ -1,48 +1,8 @@
from django.contrib.auth.decorators import login_required
from django.http import HttpResponseRedirect
from annoying.decorators import render_to
from accounts.forms import AccountForm
from django.contrib import messages
from snipts.models import Snipt
@login_required
@render_to('account.html')
def account(request):
if request.POST:
form = AccountForm(request.POST, instance=request.user.profile)
if form.is_valid():
form.save()
messages.add_message(request, 25, 'Account settings saved.')
return HttpResponseRedirect('/account/')
else:
profile = request.user.profile
form = AccountForm(initial={
'blog_title': profile.blog_title,
'blog_theme': profile.blog_theme,
'blog_domain': profile.blog_domain,
'default_editor': profile.default_editor,
'editor_theme': profile.editor_theme,
'gittip_username': profile.gittip_username,
'disqus_shortname': profile.disqus_shortname,
'google_analytics_tracking_id': profile.google_analytics_tracking_id,
'gauges_site_id': profile.gauges_site_id,
'google_ad_client': profile.google_ad_client,
'google_ad_slot': profile.google_ad_slot,
'google_ad_width': profile.google_ad_width,
'google_ad_height': profile.google_ad_height,
})
return {
'form': form
}
@login_required
@render_to('stats.html')
def stats(request):

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -1516,7 +1516,7 @@ body.account {
section.profile {
aside {
float: left;
padding-top: 30px;
padding-top: 35px;
width: 190px;
ul {
@ -1538,8 +1538,51 @@ body.account {
border-bottom: 1px solid #DDDDDD;
border-left: 4px solid #43A8C6;
float: right;
min-height: 400px;
min-height: 308px;
padding: 30px 0 0 0;
width: 555px;
@include multi-border-radius(0, 0, 0, 10px);
div.def {
border: 1px solid #DDDDDD;
margin: 15px;
padding: 30px 10px 10px;
position: relative;
@include border-radius;
&:before {
background: #F5F5F5;
border: 1px solid #DDDDDD;
color: #43A8C6;
content: attr(data-title);
left: -1px;
font: bold 12px $Helvetica;
padding: 3px 7px;
position: absolute;
top: -1px;
@include multi-border-radius(4px, 0, 4px, 0);
}
}
p.alert {
margin: 0 15px;
}
form {
span.help-block {
color: #999;
font: normal 12px $Helvetica;
}
div.control-group:last-of-type {
margin-bottom: 0;
input, select {
margin-bottom: 0;
}
span.help-block {
margin-bottom: 0;
margin-top: 10px;
}
}
}
}
}
}

View File

@ -1 +1 @@
Section: [[ section ]]
<p class="alert alert-info">Working on this section. Stay tuned!</p>

View File

@ -1,73 +1,85 @@
<div class="control-group {% if form.errors.blog_title %}error{% endif %}">
<label class="control-label" for="id_blog_title">Blog title:</label>
<div class="controls">
{{ form.blog_title }}
<form action="" method="get" accept-charset="utf-8">
<div class="def" data-title="Site settings">
<div class="control-group">
<label class="control-label" for="id_blog_title">Blog title:</label>
<div class="controls">
<input id="id_blog_title" type="text" name="blog_title" value="[[ user.blog_title ]]" maxlength="250">
</div>
</div>
<div class="control-group ">
<label class="control-label" for="id_blog_theme">Blog theme:</label>
<div class="controls">
<select name="blog_theme" id="id_blog_theme">
<option value="D" ng-selected="user.blog_theme == 'D'">Default</option>
<option value="A" ng-selected="user.blog_theme == 'A'">Pro Adams</option>
</select>
</div>
</div>
<div class="control-group">
<label class="control-label" for="id_blog_domain">Blog domain:</label>
<div class="controls">
<input id="id_blog_domain" type="text" name="blog_domain" maxlength="250" value="[[ user.blog_domain ]]">
<span class="help-block">Like 'snipt.nicksergeant.com' or 'nicksergeant.com' (without quotes). Set your CNAME / A-record to point to 96.126.110.160</span>
</div>
</div>
</div>
</div>
<div class="control-group {% if form.errors.blog_theme %}error{% endif %}">
<label class="control-label" for="id_blog_theme">Blog theme:</label>
<div class="controls">
{{ form.blog_theme }}
<div class="def" data-title="Services">
<div class="control-group">
<label class="control-label" for="id_gittip_username">Gittip username:</label>
<div class="controls">
<input id="id_gittip_username" type="text" name="gittip_username" value="[[ user.gittip_username ]]" maxlength="250">
<span class="help-block">Your <a href="https://www.gittip.com/">Gittip</a> username, if you have one.</span>
</div>
</div>
<div class="control-group">
<label class="control-label" for="id_disqus_shortname">Disqus shortname:</label>
<div class="controls">
<input id="id_disqus_shortname" type="text" name="disqus_shortname" maxlength="250" value="[[ user.disqus_shortname ]]">
<span class="help-block">If you have your own <a href="http://disqus.com/">Disqus</a> account that you'd like to use for your blog comments, enter your shortname here.</span>
</div>
</div>
</div>
</div>
<div class="control-group {% if form.errors.blog_domain %}error{% endif %}">
<label class="control-label" for="id_blog_domain">Blog domain:</label>
<div class="controls">
{{ form.blog_domain }}
<span class="help-block">Like 'snipt.nicksergeant.com' or 'nicksergeant.com' (without quotes). Set your CNAME / A-record to point to 96.126.110.160</span>
<div class="def" data-title="Analytics">
<div class="control-group">
<label class="control-label" for="id_google_analytics_tracking_id">Google Analytics tracking ID:</label>
<div class="controls">
<input id="id_google_analytics_tracking_id" type="text" name="google_analytics_tracking_id" maxlength="250" value="[[ user.google_analytics_tracking_id ]]">
<span class="help-block">If you'd like to track visits to your blog site with <a href="http://analytics.google.com">Google Analytics</a>, enter your tracking ID here.</span>
</div>
</div>
<div class="control-group">
<label class="control-label" for="id_gauges_site_id">Gauges site ID:</label>
<div class="controls">
<input id="id_gauges_site_id" type="text" name="gauges_site_id" value="[[ user.gauges_site_id ]]" maxlength="250">
<span class="help-block">If you'd like to track visits to your blog site with <a href="http://get.gaug.es/">Gauges</a>, enter your site ID here.</span>
</div>
</div>
</div>
</div>
<div class="control-group {% if form.errors.gittip_username %}error{% endif %}">
<label class="control-label" for="id_gittip_username">Gittip username:</label>
<div class="controls">
{{ form.gittip_username }}
<span class="help-block">Your <a href="https://www.gittip.com/">Gittip</a> username, if you have one.</span>
<div class="def" data-title="Google AdSense">
<div class="control-group">
<label class="control-label" for="id_google_ad_client">Google Ads: "google_ad_client"</label>
<div class="controls">
<input id="id_google_ad_client" type="text" name="google_ad_client" maxlength="250" value="[[ user.google_ad_client ]]">
<span class="help-block">If you'd like to run Google Ads in your blog's sidebar, enter your client ID here, as well as the following three fields.</span>
</div>
</div>
<div class="control-group">
<label class="control-label" for="id_google_ad_slot">Google Ads: "google_ad_slot"</label>
<div class="controls">
<input id="id_google_ad_slot" type="text" name="google_ad_slot" maxlength="250" value="[[ user.google_ad_slot ]]">
</div>
</div>
<div class="control-group">
<label class="control-label" for="id_google_ad_width">Google Ads: "google_ad_width"</label>
<div class="controls">
<input id="id_google_ad_width" type="text" name="google_ad_width" maxlength="250" value="[[ user.google_ad_width ]]">
</div>
</div>
<div class="control-group">
<label class="control-label" for="id_google_ad_height">Google Ads: "google_ad_height"</label>
<div class="controls">
<input id="id_google_ad_height" type="text" name="google_ad_height" maxlength="250" value="[[ user.google_ad_height ]]">
</div>
</div>
</div>
</div>
<div class="control-group {% if form.errors.disqus_shortname %}error{% endif %}">
<label class="control-label" for="id_disqus_shortname">Disqus shortname:</label>
<div class="controls">
{{ form.disqus_shortname }}
<span class="help-block">If you have your own <a href="http://disqus.com/">Disqus</a> account that you'd like to use for your blog comments, enter your shortname here.</span>
</div>
</div>
<div class="control-group {% if form.errors.google_analytics_tracking_id %}error{% endif %}">
<label class="control-label" for="id_google_analytics_tracking_id">Google Analytics tracking ID:</label>
<div class="controls">
{{ form.google_analytics_tracking_id }}
<span class="help-block">If you'd like to track visits to your blog site with <a href="http://analytics.google.com">Google Analytics</a>, enter your tracking ID here.</span>
</div>
</div>
<div class="control-group {% if form.errors.gauges_site_id %}error{% endif %}">
<label class="control-label" for="id_gauges_site_id">Gauges site ID:</label>
<div class="controls">
{{ form.gauges_site_id }}
<span class="help-block">If you'd like to track visits to your blog site with <a href="http://get.gaug.es/">Gauges</a>, enter your site ID here.</span>
</div>
</div>
<div class="control-group {% if form.errors.google_ad_client %}error{% endif %}">
<label class="control-label" for="id_google_ad_client">Google Ads: "google_ad_client"</label>
<div class="controls">
{{ form.google_ad_client }}
<span class="help-block">If you'd like to run Google Ads in your blog's sidebar, enter your client ID here, as well as the following three fields.</span>
</div>
</div>
<div class="control-group {% if form.errors.google_ad_slot %}error{% endif %}">
<label class="control-label" for="id_google_ad_slot">Google Ads: "google_ad_slot"</label>
<div class="controls">
{{ form.google_ad_slot }}
</div>
</div>
<div class="control-group {% if form.errors.google_ad_width %}error{% endif %}">
<label class="control-label" for="id_google_ad_width">Google Ads: "google_ad_width"</label>
<div class="controls">
{{ form.google_ad_width }}
</div>
</div>
<div class="control-group {% if form.errors.google_ad_height %}error{% endif %}">
<label class="control-label" for="id_google_ad_height">Google Ads: "google_ad_height"</label>
<div class="controls">
{{ form.google_ad_height }}
</div>
</div>
</form>

View File

@ -1,12 +1,37 @@
<div class="control-group {% if form.errors.default_editor %}error{% endif %}">
<label class="control-label" for="id_default_editor">Default editor:</label>
<div class="controls">
{{ form.default_editor }}
<form action="" method="get" accept-charset="utf-8">
<div class="def" data-title="Editor">
<div class="control-group">
<label class="control-label" for="id_default_editor">Default editor:</label>
<div class="controls">
<select name="default_editor" id="id_default_editor">
<option value="C" ng-selected="user.default_editor == 'C'">CodeMirror</option>
<option value="T" ng-selected="user.default_editor == 'T'">Textarea</option>
</select>
</div>
</div>
<div class="control-group">
<label class="control-label" for="id_editor_theme">Default editor theme:</label>
<div class="controls">
<select name="editor_theme" id="id_editor_theme">
<option value="default" ng-selected="user.editor_theme == 'default'">Default</option>
<option value="ambiance" ng-selected="user.editor_theme == 'ambiance'">Ambiance</option>
<option value="blackboard" ng-selected="user.editor_theme == 'blackboard'">Blackboard</option>
<option value="cobalt" ng-selected="user.editor_theme == 'cobalt'">Cobalt</option>
<option value="eclipse" ng-selected="user.editor_theme == 'eclipse'">Eclipse</option>
<option value="elegant" ng-selected="user.editor_theme == 'elegant'">Elegant</option>
<option value="erlang-dark" ng-selected="user.editor_theme == 'erlang-dark'">Erlang Dark</option>
<option value="lesser-dark" ng-selected="user.editor_theme == 'lesser-dark'">Lesser Dark</option>
<option value="monokai" ng-selected="user.editor_theme == 'monokai'">Monokai</option>
<option value="neat" ng-selected="user.editor_theme == 'neat'">Neat</option>
<option value="night" ng-selected="user.editor_theme == 'night'">Night</option>
<option value="rubyblue" ng-selected="user.editor_theme == 'rubyblue'">Ruby Blue</option>
<option value="solarized dark" ng-selected="user.editor_theme == 'solarized dark'">Solarized Dark</option>
<option value="solarized light" ng-selected="user.editor_theme == 'solarized light'">Solarized Light</option>
<option value="twilight" ng-selected="user.editor_theme == 'twilight'">Twilight</option>
<option value="vibrant-ink" ng-selected="user.editor_theme == 'vibrant-ink'">Vibrant Ink</option>
<option value="xq-dark" ng-selected="user.editor_theme == 'xq-dark'">XQ Dark</option>
</select>
</div>
</div>
</div>
</div>
<div class="control-group {% if form.errors.editor_theme %}error{% endif %}">
<label class="control-label" for="id_editor_theme">Default editor theme:</label>
<div class="controls">
{{ form.editor_theme }}
</div>
</div>
</form>

View File

@ -1,3 +1,12 @@
Username: [[ user.username ]]
<a href="/api/">API</a> key: [[ user.api_key ]]
<a href="/api/">API</a> user ID: [[ user.id ]]
<div class="def" data-title="Username">
[[ user.username ]]
</div>
<div class="def" data-title="User ID">
[[ user.user_id ]]
</div>
<div class="def" data-title="Email">
[[ user.email ]]
</div>
<div class="def" data-title="API Key">
fdsaf809ds7a89gd7sa89g7ds09a7g0d9s8a
</div>

View File

@ -138,9 +138,17 @@ class PrivateUserProfileResource(ModelResource):
def dehydrate(self, bundle):
bundle.data['email'] = bundle.obj.user.email
bundle.data['username'] = bundle.obj.user.username
bundle.data['user_id'] = bundle.obj.user.id
bundle.data['api_key'] = bundle.obj.user.api_key.key
bundle.data['is_pro'] = bundle.obj.user.profile.is_pro
return bundle
def obj_update(self, bundle, request=None, **kwargs):
# TODO: Clean all account fields.
return super(PrivateUserProfileResource, self).obj_update(bundle, request,
user=request.user, **kwargs)
class PrivateUserResource(ModelResource):
profile = fields.ForeignKey(PrivateUserProfileResource, 'profile', full=False)