create and edit Library objects, which now have names and owners
parent
19179f695d
commit
ccb1f0dd86
|
@ -155,6 +155,9 @@ Not needed on newly designed home page?
|
||||||
<li><a href="{{ rhtoolsurl }}">Rights Holder Tools</a></li>
|
<li><a href="{{ rhtoolsurl }}">Rights Holder Tools</a></li>
|
||||||
<li><a href="{{ privacyurl }}">Privacy</a></li>
|
<li><a href="{{ privacyurl }}">Privacy</a></li>
|
||||||
<li><a href="{{ termsurl }}">Terms of Use</a></li>
|
<li><a href="{{ termsurl }}">Terms of Use</a></li>
|
||||||
|
{% for library in user.libraries.all %}
|
||||||
|
<li><a href="{% url library_admin library.id %}">{{ library }} Administration</a></li>
|
||||||
|
{% endfor %}
|
||||||
{% if user.is_staff %}
|
{% if user.is_staff %}
|
||||||
<li><a href="{{ adminurl }}">Unglue.it Administration</a></li>
|
<li><a href="{{ adminurl }}">Unglue.it Administration</a></li>
|
||||||
<li><a href="{{ editionurl }}">Create New Editions</a></li>
|
<li><a href="{{ editionurl }}">Create New Editions</a></li>
|
||||||
|
|
|
@ -11,7 +11,7 @@
|
||||||
{% if not request.user.is_anonymous %}
|
{% if not request.user.is_anonymous %}
|
||||||
<li class="first"><a href="/"><span>My Books</span></a></li>
|
<li class="first"><a href="/"><span>My Books</span></a></li>
|
||||||
{% for library in request.user.profile.libraries %}
|
{% for library in request.user.profile.libraries %}
|
||||||
<li><a href="{% url library library %}"><span>{{ library }}</span></a></li>
|
<li><a href="{% url library library.user %}"><span>{{ library }}</span></a></li>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
<li>
|
<li>
|
||||||
{% else %}
|
{% else %}
|
||||||
|
@ -55,7 +55,7 @@
|
||||||
</a></li>
|
</a></li>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
{% if library %}
|
{% if library %}
|
||||||
<li class="first"><a href="{% url library_users library %}"><span>More from {{ library }}</span></a></li>
|
<li class="first"><a href="{% url library_users library.id %}"><span>More from {{ library }}</span></a></li>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</ul>
|
</ul>
|
||||||
</li>
|
</li>
|
||||||
|
|
|
@ -25,16 +25,21 @@
|
||||||
<p>We love libraries because we're from the library world. And because we live in a real world that still needs libraries. We've built Unglue.it in part because we've seen that the ebook system we have now really doesn't work for libraries, and we believe in making things better.</p>
|
<p>We love libraries because we're from the library world. And because we live in a real world that still needs libraries. We've built Unglue.it in part because we've seen that the ebook system we have now really doesn't work for libraries, and we believe in making things better.</p>
|
||||||
|
|
||||||
<p>We started out with "Pledge" campaigns to help books become Creative Commons licensed ebooks.
|
<p>We started out with "Pledge" campaigns to help books become Creative Commons licensed ebooks.
|
||||||
We’ve added "Buy-to-Unglue" campaigns to so that libraries can lend ebooks on the road to being unglued. </p>
|
We’ve added "Buy-to-Unglue" campaigns to so that libraries can lend ebooks on the road to being unglued. We've built a <i>free distribution platform</i> to help libraries distribute these books. </p>
|
||||||
|
|
||||||
<p><strong>We need your help, though.</strong> We can't unglue ebooks all by ourselves; we need lots of people to pitch in. If you'd like to share free, unlimited, no-DRM, privacy-respecting ebooks with your patrons, here are some ways you can help:</p>
|
<p><strong>We need your help, though.</strong> We can't unglue ebooks all by ourselves; we need lots of people to pitch in. If you'd like to share free, unlimited, no-DRM, privacy-respecting ebooks with your patrons, here are some ways you can help:</p>
|
||||||
|
|
||||||
<dl>
|
<dl>
|
||||||
<dt><a href="{% url registration_register %}?next={% request.get_full_path|urlencode }}">Sign up.</a></dt>
|
<dt><a href="{% url registration_register %}?next={% request.get_full_path|urlencode }}">Sign up.</a> It's Free!</dt>
|
||||||
<dd>Starting an account, for yourself or your library, is free, and lets you add books to your wishlist, comment on them, and support campaigns. <a href="{{ request.get_full_path|urlencode}}">Sign up here.</a> It's the first step towards becoming an Unglue.it participating library. </dd>
|
<dd>Starting an account, for yourself or your library, is free. Use it to help us distribute unglued and ungluing ebooks. </dd>
|
||||||
<dt>Become an Unglue.it participating library</dt>
|
<dt>Become an Unglue.it participating library</dt>
|
||||||
<dd>Review our <a href="https://www.docracy.com/0_uyw26qv9c/unglue-it-library-license-agreement">LIBRARY LICENCE AGREEMENT</a>. Once an agreement has been signed, you and your patrons can buy Library Licenses for any ebook with a Buy-to-Unglue campaign. You can lend these ebooks to your patrons immediately using our free distribution platform.
|
<dd><ol><li><a href="{% url library_create %}">Make your library page</a> on Unglue.it. It takes just a few minutes. It's the first step towards becoming an Unglue.it participating library.</li>
|
||||||
The library license gives download access to one library member at a time for 14 days each, in multiple formats, from the our platform or yours, if you have one.
|
<li>Review our <a href="https://www.docracy.com/0_uyw26qv9c/unglue-it-library-license-agreement">LIBRARY LICENCE AGREEMENT</a>. </li>
|
||||||
|
<li>Once an agreement has been signed, we'll "approve" your library; you and your patrons can then buy Library Licenses for any ebook with a Buy-to-Unglue campaign. You can lend these ebooks to your patrons immediately using our free distribution platform.
|
||||||
|
The library license gives download access to one library member at a time for 14 days each, in multiple formats, from our platform or yours, if you have one. </li>
|
||||||
|
<li>Log in as the library, and add unglued and ungluing books to your library list. Buy licenses to our buy-to-unglue titles. </li>
|
||||||
|
<li>Let your users know about Unglue.it!</li>
|
||||||
|
</ol>
|
||||||
</dd>
|
</dd>
|
||||||
<dt>Stay in touch.</dt>
|
<dt>Stay in touch.</dt>
|
||||||
<dd>You can follow us on Twitter (<a href="http://twitter.com/unglueit">@unglueit</a>), <a href="http://facebook/com/unglueit">Facebook</a>, and our <a href="http://blog.unglue.it">blog</a>, and <a href="http://eepurl.com/fKLfI">subscribe to our newsletter</a> (1-2 emails per month).</dd>
|
<dd>You can follow us on Twitter (<a href="http://twitter.com/unglueit">@unglueit</a>), <a href="http://facebook/com/unglueit">Facebook</a>, and our <a href="http://blog.unglue.it">blog</a>, and <a href="http://eepurl.com/fKLfI">subscribe to our newsletter</a> (1-2 emails per month).</dd>
|
||||||
|
|
|
@ -0,0 +1,39 @@
|
||||||
|
{% extends "basedocumentation.html" %}
|
||||||
|
{% block title %} Library Admin {% endblock %}
|
||||||
|
{% block extra_extra_head %}
|
||||||
|
<link rel="stylesheet" href="https://ajax.googleapis.com/ajax/libs/jqueryui/1.8.13/themes/ui-lightness/jquery-ui.css" type="text/css" media="screen">
|
||||||
|
{{ form.media.css }}
|
||||||
|
<script type="text/javascript" src="{{ jquery_ui_home }}" ></script>
|
||||||
|
|
||||||
|
{{ form.media.js }}
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block doccontent %}
|
||||||
|
{% if library.pk %}
|
||||||
|
<h2>Edit Library</h2>
|
||||||
|
<ul><li> Go to <a href="{% url library library.user %}">{{ library }} Page</a></li>
|
||||||
|
<li><a href="{% url library_login library.id %}">Log in</a> as the library user </li>
|
||||||
|
{% else %}
|
||||||
|
<h2>Create New Library</h2>
|
||||||
|
{% endif %}
|
||||||
|
<p>{{ status }}</p>
|
||||||
|
<form method="POST" action="#" class="std_form">
|
||||||
|
{% csrf_token %}
|
||||||
|
{{ form.work }}
|
||||||
|
{{ form.non_field_errors }}
|
||||||
|
<div>
|
||||||
|
<p><b>Library Name</b>: {{ form.name.errors }}{{ form.name }}</p>
|
||||||
|
{% if form.instance.user %}
|
||||||
|
<p><b>Library Username</b>: {{ form.instance.user }}</p>
|
||||||
|
<p><b>Library Email</b>: {{ form.instance.user.email }}</p>
|
||||||
|
{% else %}
|
||||||
|
<p><b>Library Username</b>: {{ form.username.errors }}{{ form.username }} This will be the Unglue.it username for the library.</p>
|
||||||
|
<p><b>Library Email</b>: {{ form.email.errors }}{{ form.email }} The notification address for the library.</p>
|
||||||
|
|
||||||
|
{% endif %}
|
||||||
|
<p><b>Library Authentication Method</b>: {{ form.backend.errors }}{{ form.backend }}</p>
|
||||||
|
</div>
|
||||||
|
<input type="submit" name="create_new_library" value="{% if library.pk %}Save Edits{% else %}Create A Library{% endif %}" id="submit">
|
||||||
|
</form>
|
||||||
|
|
||||||
|
{% endblock %}
|
|
@ -1,7 +1,7 @@
|
||||||
{% extends "base.html" %}
|
{% extends "base.html" %}
|
||||||
{% load endless %}
|
{% load endless %}
|
||||||
{% load truncatechars %}
|
{% load truncatechars %}
|
||||||
{% block title %} — {{ library.user.username }}{% endblock %}
|
{% block title %} — {{ library }}{% endblock %}
|
||||||
{% block extra_css %}
|
{% block extra_css %}
|
||||||
<link type="text/css" rel="stylesheet" href="/static/css/supporter_layout.css" />
|
<link type="text/css" rel="stylesheet" href="/static/css/supporter_layout.css" />
|
||||||
<link type="text/css" rel="stylesheet" href="/static/css/searchandbrowse2.css" />
|
<link type="text/css" rel="stylesheet" href="/static/css/searchandbrowse2.css" />
|
||||||
|
@ -37,7 +37,7 @@ function highlightTarget(targetdiv) {
|
||||||
{% block topsection %}
|
{% block topsection %}
|
||||||
<div id="locationhash">{% ifequal activetab '#3' %}#1{% else %}{{ activetab }}{% endifequal %}</div>
|
<div id="locationhash">{% ifequal activetab '#3' %}#1{% else %}{{ activetab }}{% endifequal %}</div>
|
||||||
{% ifequal supporter request.user %}
|
{% ifequal supporter request.user %}
|
||||||
<div class="launch_top pale">You are logged in as the administrator of {{ library.user.username }}
|
<div class="launch_top pale">You are logged in as the administrator of {{ library }}
|
||||||
</div>
|
</div>
|
||||||
{% endifequal %}
|
{% endifequal %}
|
||||||
|
|
||||||
|
@ -52,7 +52,7 @@ function highlightTarget(targetdiv) {
|
||||||
<div class="block-inner">
|
<div class="block-inner">
|
||||||
<img class="user-avatar" src="{{ library.user.profile.avatar_url }}" height="50" width="50" alt="Avatar for {{ supporter }}" title="Avatar" />
|
<img class="user-avatar" src="{{ library.user.profile.avatar_url }}" height="50" width="50" alt="Avatar for {{ supporter }}" title="Avatar" />
|
||||||
<span class="user-name">
|
<span class="user-name">
|
||||||
<a href="#"><span itemprop="name">{{ library.user.username }}</span></a>
|
<a href="#"><span itemprop="name">{{ library }}</span></a>
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<span class="user-badges">
|
<span class="user-badges">
|
||||||
|
@ -157,7 +157,7 @@ function highlightTarget(targetdiv) {
|
||||||
</div>
|
</div>
|
||||||
{% else %}
|
{% else %}
|
||||||
<div class="empty-wishlist">
|
<div class="empty-wishlist">
|
||||||
It looks like {{ library.user.username }} is just getting started, and isn't offering any books just yet.<br /><br />
|
It looks like {{ library }} is just getting started, and isn't offering any books just yet.<br /><br />
|
||||||
{% endifequal %}
|
{% endifequal %}
|
||||||
{% else %}
|
{% else %}
|
||||||
|
|
||||||
|
|
|
@ -47,12 +47,12 @@
|
||||||
{% for library in libraries %}
|
{% for library in libraries %}
|
||||||
<div class="items {% cycle 'row1' 'row2' %}{% if library.group in request.user.groups.all %} joined{% endif %}">
|
<div class="items {% cycle 'row1' 'row2' %}{% if library.group in request.user.groups.all %} joined{% endif %}">
|
||||||
<div class="avatar">
|
<div class="avatar">
|
||||||
<a href="{% url library library %}">
|
<a href="{% url library library.user %}">
|
||||||
<img class="user-avatar" src="{{ library.user.profile.avatar_url }}" height="50" width="50" alt="Avatar for {{ library }}" title="{{ library }}" />
|
<img class="user-avatar" src="{{ library.user.profile.avatar_url }}" height="50" width="50" alt="Avatar for {{ library }}" title="{{ library }}" />
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
<div class="nonavatar">
|
<div class="nonavatar">
|
||||||
<div class="libname"><a href="{% url library library %}">{{ library }}</a> {{ library.user.tagline }}</div>
|
<div class="libname"><a href="{% url library library.user %}">{{ library }}</a> {{ library.user.tagline }}</div>
|
||||||
<div class="libstat">{% if library.group in request.user.groups.all %}<em>joined</em>{% else %} {% endif %}</div>
|
<div class="libstat">{% if library.group in request.user.groups.all %}<em>joined</em>{% else %} {% endif %}</div>
|
||||||
<div class="libstat">{{ library.library_users.count }} Unglue.it users</div>
|
<div class="libstat">{{ library.library_users.count }} Unglue.it users</div>
|
||||||
<div class="libstat">{{ library.user.acqs.count }} Unglue.it holdings</div>
|
<div class="libstat">{{ library.user.acqs.count }} Unglue.it holdings</div>
|
||||||
|
|
|
@ -19,7 +19,7 @@
|
||||||
<div id="user-block1">
|
<div id="user-block1">
|
||||||
<div id="block-intro-text"><span class="special-user-name">{{ library }} </span> </div>
|
<div id="block-intro-text"><span class="special-user-name">{{ library }} </span> </div>
|
||||||
</div>
|
</div>
|
||||||
<div class="user-block24"><span class="user-short-info">These ungluers are are using <a href="{% url library library %}">{{ library }}</a>. </span>
|
<div class="user-block24"><span class="user-short-info">These ungluers are are using <a href="{% url library library.user %}">{{ library }}</a>. </span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -67,7 +67,7 @@
|
||||||
No users yet.
|
No users yet.
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
{% else %}
|
{% else %}
|
||||||
You need to be a member of {{ library }} to see all its members. They can borrow and donate books. Perhaps you'd like to <a href="{% url join_library library %}">join them</a>?
|
You need to be a member of {{ library }} to see all its members. They can borrow and donate books. Perhaps you'd like to <a href="{% url join_library library.id %}">join them</a>?
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
Your request to join {{ library }} has been accepted. Welcome!
|
Your request to join {{ library }} has been accepted. Welcome!
|
||||||
|
|
||||||
{{ library }} is participating in Unglue.it. That means you can borrow Unglue.it ebooks owned by {{ library }} (when available). A list of the ebooks available to {{ library }} members is available here:
|
{{ library }} is participating in Unglue.it. That means you can borrow Unglue.it ebooks owned by {{ library }} (when available). A list of the ebooks available to {{ library }} members is available here:
|
||||||
https://{{ current_site.domain }}{% url library library %}
|
https://{{ current_site.domain }}{% url library library.user %}
|
||||||
|
|
||||||
When you buy an ebook through Unglue.it, you'll be offered the option to by a library license in stead of an individual license. That means that {{ library }} will own the ebook, but you'll be the first in line to borrow it. After two weeks, the book will be available to other members of {{ library }}.
|
When you buy an ebook through Unglue.it, you'll be offered the option to by a library license in stead of an individual license. That means that {{ library }} will own the ebook, but you'll be the first in line to borrow it. After two weeks, the book will be available to other members of {{ library }}.
|
||||||
|
|
||||||
|
@ -14,7 +14,7 @@ eBooks available for purchase through Unglue.it will eventually be free to the w
|
||||||
{{ user.username }}'s request to join {{ library }} has been accepted.
|
{{ user.username }}'s request to join {{ library }} has been accepted.
|
||||||
|
|
||||||
Manage your users at
|
Manage your users at
|
||||||
https://{{ current_site.domain }}{% url library_users library %}
|
https://{{ current_site.domain }}{% url library_users library.id %}
|
||||||
|
|
||||||
the Unglue.it team
|
the Unglue.it team
|
||||||
{% endifequal %}
|
{% endifequal %}
|
|
@ -1,6 +1,6 @@
|
||||||
{% extends "notification/notice_template.html" %}
|
{% extends "notification/notice_template.html" %}
|
||||||
{% block comments_book %}
|
{% block comments_book %}
|
||||||
<a href="{% url library library %}"><img src="{{ library.user.profile.avatar_url }}" alt="avatar for {{ library }}" /></a>
|
<a href="{% url library library.user %}"><img src="{{ library.user.profile.avatar_url }}" alt="avatar for {{ library }}" /></a>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block comments_graphical %}
|
{% block comments_graphical %}
|
||||||
|
@ -13,7 +13,7 @@
|
||||||
|
|
||||||
{% block comments_textual %}
|
{% block comments_textual %}
|
||||||
{% ifequal user recipient %}
|
{% ifequal user recipient %}
|
||||||
<p>{{ library }} is participating in Unglue.it. That means you can borrow Unglue.it ebooks owned by {{ library }} (when available). Here's <a href="{% url library library %}">a list of the ebooks available</a> to {{ library }} members. <p>
|
<p>{{ library }} is participating in Unglue.it. That means you can borrow Unglue.it ebooks owned by {{ library }} (when available). Here's <a href="{% url library library.user %}">a list of the ebooks available</a> to {{ library }} members. <p>
|
||||||
|
|
||||||
<p>When you buy an ebook through unglue.it, you'll be offered the option to by a library license in stead of an individual license. That means that {{ library }} will own the ebook, but you'll be the first in line to borrow it. After two weeks, the book will be available to other members of {{ library }}. </p>
|
<p>When you buy an ebook through unglue.it, you'll be offered the option to by a library license in stead of an individual license. That means that {{ library }} will own the ebook, but you'll be the first in line to borrow it. After two weeks, the book will be available to other members of {{ library }}. </p>
|
||||||
|
|
||||||
|
@ -22,6 +22,6 @@
|
||||||
<p>{{ library }} and the Unglue.it team
|
<p>{{ library }} and the Unglue.it team
|
||||||
</p>
|
</p>
|
||||||
{% else %}
|
{% else %}
|
||||||
<p>You can manage your users <a href="{% url library_users library %}">on this page</a>.</p>
|
<p>You can manage your users <a href="{% url library_users library.id %}">on this page</a>.</p>
|
||||||
{% endifequal %}
|
{% endifequal %}
|
||||||
{% endblock %}
|
{% endblock %}
|
|
@ -73,7 +73,7 @@ function highlightTarget(targetdiv) {
|
||||||
{% block topsection %}
|
{% block topsection %}
|
||||||
<div id="locationhash">{{ activetab }}</div>
|
<div id="locationhash">{{ activetab }}</div>
|
||||||
{% if supporter.library %}
|
{% if supporter.library %}
|
||||||
<div class="launch_top pale">{{ supporter.library }} is a Library participating in Unglue.it. <a href="{% url join_library supporter.username %}">Click here</a> to use {{ supporter.library }}'s books.
|
<div class="launch_top pale">{{ supporter.library }} is a Library participating in Unglue.it. <a href="{% url join_library supporter.library.id %}">Click here</a> to use {{ supporter.library }}'s books.
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,9 @@
|
||||||
|
from django import forms
|
||||||
from django.contrib.auth.forms import AuthenticationForm
|
from django.contrib.auth.forms import AuthenticationForm
|
||||||
|
from django.contrib.auth.models import User
|
||||||
|
from django.utils.translation import ugettext_lazy as _
|
||||||
|
|
||||||
|
from .models import Library
|
||||||
|
|
||||||
class AuthForm(AuthenticationForm):
|
class AuthForm(AuthenticationForm):
|
||||||
def __init__(self, request=None, *args, **kwargs):
|
def __init__(self, request=None, *args, **kwargs):
|
||||||
|
@ -8,3 +13,38 @@ class AuthForm(AuthenticationForm):
|
||||||
else:
|
else:
|
||||||
super(AuthForm, self).__init__(*args, **kwargs)
|
super(AuthForm, self).__init__(*args, **kwargs)
|
||||||
|
|
||||||
|
class NewLibraryForm(forms.ModelForm):
|
||||||
|
username = forms.RegexField(
|
||||||
|
label=_("Library Username"),
|
||||||
|
max_length=30,
|
||||||
|
regex=r'^[\w.@+-]+$',
|
||||||
|
help_text = _("30 characters or fewer."),
|
||||||
|
error_messages = {
|
||||||
|
'invalid': _("This value may contain only letters, numbers and @/./+/-/_ characters.")
|
||||||
|
},
|
||||||
|
initial = '',
|
||||||
|
)
|
||||||
|
email = forms.EmailField(
|
||||||
|
label=_("notification email address for library"),
|
||||||
|
max_length=100,
|
||||||
|
error_messages={'required': 'Please enter an email address for the library.'},
|
||||||
|
)
|
||||||
|
def clean_username(self):
|
||||||
|
username= self.cleaned_data['username']
|
||||||
|
try:
|
||||||
|
user = User.objects.get(username=username)
|
||||||
|
raise forms.ValidationError(_("That username is already in use, please choose another."))
|
||||||
|
except User.DoesNotExist:
|
||||||
|
self.instance.user = User(username=username)
|
||||||
|
return username
|
||||||
|
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
model = Library
|
||||||
|
fields = 'name', 'backend', 'email', 'username'
|
||||||
|
widgets = {'name':forms.TextInput(attrs={'size':'40'})}
|
||||||
|
|
||||||
|
class LibraryForm(forms.ModelForm):
|
||||||
|
class Meta:
|
||||||
|
model = Library
|
||||||
|
fields = 'name', 'backend',
|
||||||
|
|
|
@ -0,0 +1,115 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
import datetime
|
||||||
|
from south.db import db
|
||||||
|
from south.v2 import SchemaMigration
|
||||||
|
from django.db import models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(SchemaMigration):
|
||||||
|
|
||||||
|
def forwards(self, orm):
|
||||||
|
# Adding field 'Library.name'
|
||||||
|
db.add_column('libraryauth_library', 'name',
|
||||||
|
self.gf('django.db.models.fields.CharField')(default='', max_length=80),
|
||||||
|
keep_default=False)
|
||||||
|
|
||||||
|
# Adding field 'Library.approved'
|
||||||
|
db.add_column('libraryauth_library', 'approved',
|
||||||
|
self.gf('django.db.models.fields.BooleanField')(default=False),
|
||||||
|
keep_default=False)
|
||||||
|
|
||||||
|
# Adding field 'Library.owner'
|
||||||
|
db.add_column('libraryauth_library', 'owner',
|
||||||
|
self.gf('django.db.models.fields.related.ForeignKey')(default=10, related_name='libraries', to=orm['auth.User']),
|
||||||
|
keep_default=False)
|
||||||
|
|
||||||
|
|
||||||
|
def backwards(self, orm):
|
||||||
|
# Deleting field 'Library.name'
|
||||||
|
db.delete_column('libraryauth_library', 'name')
|
||||||
|
|
||||||
|
# Deleting field 'Library.approved'
|
||||||
|
db.delete_column('libraryauth_library', 'approved')
|
||||||
|
|
||||||
|
# Deleting field 'Library.owner'
|
||||||
|
db.delete_column('libraryauth_library', 'owner_id')
|
||||||
|
|
||||||
|
|
||||||
|
models = {
|
||||||
|
'auth.group': {
|
||||||
|
'Meta': {'object_name': 'Group'},
|
||||||
|
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||||
|
'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}),
|
||||||
|
'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'})
|
||||||
|
},
|
||||||
|
'auth.permission': {
|
||||||
|
'Meta': {'ordering': "('content_type__app_label', 'content_type__model', 'codename')", 'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'},
|
||||||
|
'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
|
||||||
|
'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
|
||||||
|
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||||
|
'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})
|
||||||
|
},
|
||||||
|
'auth.user': {
|
||||||
|
'Meta': {'object_name': 'User'},
|
||||||
|
'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
|
||||||
|
'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}),
|
||||||
|
'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
|
||||||
|
'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}),
|
||||||
|
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||||
|
'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
|
||||||
|
'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
|
||||||
|
'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
|
||||||
|
'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
|
||||||
|
'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
|
||||||
|
'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}),
|
||||||
|
'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}),
|
||||||
|
'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'})
|
||||||
|
},
|
||||||
|
'contenttypes.contenttype': {
|
||||||
|
'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"},
|
||||||
|
'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
|
||||||
|
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||||
|
'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
|
||||||
|
'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})
|
||||||
|
},
|
||||||
|
'libraryauth.block': {
|
||||||
|
'Meta': {'ordering': "['lower']", 'object_name': 'Block'},
|
||||||
|
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||||
|
'library': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'blocks'", 'to': "orm['libraryauth.Library']"}),
|
||||||
|
'lower': ('regluit.libraryauth.models.IPAddressModelField', [], {'unique': 'True', 'db_index': 'True'}),
|
||||||
|
'upper': ('regluit.libraryauth.models.IPAddressModelField', [], {'db_index': 'True', 'null': 'True', 'blank': 'True'})
|
||||||
|
},
|
||||||
|
'libraryauth.cardpattern': {
|
||||||
|
'Meta': {'object_name': 'CardPattern'},
|
||||||
|
'checksum': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
|
||||||
|
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||||
|
'library': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'card_patterns'", 'to': "orm['libraryauth.Library']"}),
|
||||||
|
'pattern': ('django.db.models.fields.CharField', [], {'max_length': '20'})
|
||||||
|
},
|
||||||
|
'libraryauth.emailpattern': {
|
||||||
|
'Meta': {'object_name': 'EmailPattern'},
|
||||||
|
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||||
|
'library': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'email_patterns'", 'to': "orm['libraryauth.Library']"}),
|
||||||
|
'pattern': ('django.db.models.fields.CharField', [], {'max_length': '20'})
|
||||||
|
},
|
||||||
|
'libraryauth.library': {
|
||||||
|
'Meta': {'object_name': 'Library'},
|
||||||
|
'approved': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
|
||||||
|
'backend': ('django.db.models.fields.CharField', [], {'default': "'ip'", 'max_length': '10'}),
|
||||||
|
'group': ('django.db.models.fields.related.OneToOneField', [], {'related_name': "'library'", 'unique': 'True', 'null': 'True', 'to': "orm['auth.Group']"}),
|
||||||
|
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||||
|
'name': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '80'}),
|
||||||
|
'owner': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'libraries'", 'to': "orm['auth.User']"}),
|
||||||
|
'user': ('django.db.models.fields.related.OneToOneField', [], {'related_name': "'library'", 'unique': 'True', 'to': "orm['auth.User']"})
|
||||||
|
},
|
||||||
|
'libraryauth.libraryuser': {
|
||||||
|
'Meta': {'object_name': 'LibraryUser'},
|
||||||
|
'credential': ('django.db.models.fields.CharField', [], {'max_length': '30', 'null': 'True'}),
|
||||||
|
'date_modified': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'}),
|
||||||
|
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||||
|
'library': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'library_users'", 'to': "orm['libraryauth.Library']"}),
|
||||||
|
'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'user_libraries'", 'to': "orm['auth.User']"})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
complete_apps = ['libraryauth']
|
|
@ -9,6 +9,7 @@ from django.db.models import Q
|
||||||
from django.db.models.signals import post_save
|
from django.db.models.signals import post_save
|
||||||
from django.forms import IPAddressField as BaseIPAddressField
|
from django.forms import IPAddressField as BaseIPAddressField
|
||||||
from django.utils.translation import ugettext_lazy as _
|
from django.utils.translation import ugettext_lazy as _
|
||||||
|
from django.core.urlresolvers import reverse
|
||||||
|
|
||||||
class Library(models.Model):
|
class Library(models.Model):
|
||||||
'''
|
'''
|
||||||
|
@ -21,10 +22,13 @@ class Library(models.Model):
|
||||||
('cardnum', 'Library Card Number check'),
|
('cardnum', 'Library Card Number check'),
|
||||||
('email', 'e-mail pattern check'),
|
('email', 'e-mail pattern check'),
|
||||||
),default='ip')
|
),default='ip')
|
||||||
|
name = models.CharField(max_length=80, default='')
|
||||||
|
approved = models.BooleanField(default=False)
|
||||||
|
owner = models.ForeignKey(User, related_name="libraries")
|
||||||
credential = None
|
credential = None
|
||||||
|
|
||||||
def __unicode__(self):
|
def __unicode__(self):
|
||||||
return self.user.username
|
return unicode(self.name)
|
||||||
|
|
||||||
def add_user(self, user):
|
def add_user(self, user):
|
||||||
user.groups.add(self.group)
|
user.groups.add(self.group)
|
||||||
|
@ -39,6 +43,9 @@ class Library(models.Model):
|
||||||
def join_template(self):
|
def join_template(self):
|
||||||
return 'libraryauth/' + self.backend + '_join.html'
|
return 'libraryauth/' + self.backend + '_join.html'
|
||||||
|
|
||||||
|
def get_absolute_url(self):
|
||||||
|
return reverse('library', args=[self.user.username])
|
||||||
|
|
||||||
def add_group(sender, created, instance, **kwargs):
|
def add_group(sender, created, instance, **kwargs):
|
||||||
if created:
|
if created:
|
||||||
num=''
|
num=''
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
<div class="p_form">To use {{ library }}...{{authenticator.form.non_field_errors}}<br />
|
<div class="p_form">To use {{ library }}...{{authenticator.form.non_field_errors}}<br />
|
||||||
<form action="{% url join_library library %}#" method="POST" class="std_form " id="join_form">
|
<form action="{% url join_library library.id %}#" method="POST" class="std_form " id="join_form">
|
||||||
{% csrf_token %}
|
{% csrf_token %}
|
||||||
{{ authenticator.form.credential.label_tag }}: {{ authenticator.form.credential }}
|
{{ authenticator.form.credential.label_tag }}: {{ authenticator.form.credential }}
|
||||||
{% if authenticator.form.credential.errors %}
|
{% if authenticator.form.credential.errors %}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
<br />
|
<br />
|
||||||
{% if authenticator.allowed %}
|
{% if authenticator.allowed %}
|
||||||
<a href="{% url join_library authenticator.library %}?next={% url join_library authenticator.library %}" class="fakeinput">Make this my Library</a>
|
<a href="{% url join_library authenticator.library.id %}?next={% url join_library authenticator.library.id %}" class="fakeinput">Make this my Library</a>
|
||||||
{% else %}
|
{% else %}
|
||||||
Based on your account's email address, you can't join {{ authenticator.library }}. You can <a href="{% url email_change %}"> change your email address</a> if you need to.
|
Based on your account's email address, you can't join {{ authenticator.library }}. You can <a href="{% url email_change %}"> change your email address</a> if you need to.
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
<br />
|
<br />
|
||||||
{% if authenticator.allowed %}
|
{% if authenticator.allowed %}
|
||||||
<a href="{% url join_library authenticator.library %}?next={% url join_library authenticator.library %}" class="fakeinput">Make this my Library</a>
|
<a href="{% url join_library authenticator.library.id %}?next={% url join_library authenticator.library.id %}" class="fakeinput">Make this my Library</a>
|
||||||
{% else %}
|
{% else %}
|
||||||
You can't join {{ authenticator.library }} at your current location.
|
You can't join {{ authenticator.library }} at your current location.
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
|
@ -1,16 +1,20 @@
|
||||||
from django.conf.urls.defaults import *
|
from django.conf.urls.defaults import *
|
||||||
from django.core.urlresolvers import reverse
|
from django.core.urlresolvers import reverse
|
||||||
from django.views.generic.simple import direct_to_template
|
from django.views.generic.simple import direct_to_template
|
||||||
|
from django.contrib.auth.decorators import login_required
|
||||||
from . import views, models
|
from . import views, models
|
||||||
|
|
||||||
urlpatterns = patterns(
|
urlpatterns = patterns(
|
||||||
"",
|
"",
|
||||||
url(r"^libraryauth/(?P<library>[^/]+)/join/$", views.join_library, name="join_library"),
|
url(r"^libraryauth/(?P<library_id>\d+)/join/$", views.join_library, name="join_library"),
|
||||||
url(r"^libraryauth/(?P<library>[^/]+)/deny/$", direct_to_template, {'template':'libraryauth/denied.html'}, name="bad_library"),
|
url(r"^libraryauth/(?P<library_id>\d+)/deny/$", direct_to_template, {'template':'libraryauth/denied.html'}, name="bad_library"),
|
||||||
url(r"^libraryauth/(?P<library>[^/]+)/users/$", views.library, {'template':'libraryauth/users.html'}, name="library_users"),
|
url(r"^libraryauth/(?P<library_id>\d+)/users/$", views.library, {'template':'libraryauth/users.html'}, name="library_users"),
|
||||||
|
url(r"^libraryauth/(?P<library_id>\d+)/admin/$", login_required(views.UpdateLibraryView.as_view()), name="library_admin"),
|
||||||
|
url(r"^libraryauth/(?P<library_id>\d+)/login/$", views.login_as_library, name="library_login"),
|
||||||
|
url(r"^libraryauth/create/$", login_required(views.CreateLibraryView.as_view()), name="library_create"),
|
||||||
url(r"^libraryauth/list/$", direct_to_template, {
|
url(r"^libraryauth/list/$", direct_to_template, {
|
||||||
'template':'libraryauth/list.html',
|
'template':'libraryauth/list.html',
|
||||||
'extra_context':{'libraries':models.Library.objects.order_by('user__username')}
|
'extra_context':{'libraries':models.Library.objects.order_by('name')}
|
||||||
}, name="library_list"),
|
}, name="library_list"),
|
||||||
url(r'^accounts/superlogin/$', views.superlogin, name='superlogin'),
|
url(r'^accounts/superlogin/$', views.superlogin, name='superlogin'),
|
||||||
)
|
)
|
||||||
|
|
|
@ -1,20 +1,31 @@
|
||||||
import logging
|
import logging
|
||||||
|
from django.conf import settings
|
||||||
from django.core.urlresolvers import reverse
|
from django.core.urlresolvers import reverse
|
||||||
from django.shortcuts import get_object_or_404, render
|
from django.shortcuts import get_object_or_404, render
|
||||||
from django.contrib.auth.views import login
|
from django.contrib.auth.views import login
|
||||||
|
from django.contrib.auth import login as login_to_user
|
||||||
|
from django.contrib.auth import load_backend
|
||||||
|
from django.contrib.auth.decorators import login_required
|
||||||
from django.http import HttpResponseRedirect
|
from django.http import HttpResponseRedirect
|
||||||
|
from django.views.generic.edit import FormView, CreateView, UpdateView
|
||||||
from . import backends
|
from . import backends
|
||||||
|
|
||||||
from .models import Library
|
from .models import Library
|
||||||
from .forms import AuthForm
|
from .forms import AuthForm, LibraryForm, NewLibraryForm
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
def library(request, library,
|
def get_library_or_404(library=None, library_id=None):
|
||||||
|
if library_id:
|
||||||
|
return get_object_or_404(Library, id=library_id)
|
||||||
|
else:
|
||||||
|
return get_object_or_404(Library, user__username=library)
|
||||||
|
|
||||||
|
def library(request, library=None, library_id=None,
|
||||||
extra_context={},
|
extra_context={},
|
||||||
template='libraryauth/library.html',
|
template='libraryauth/library.html',
|
||||||
**kwargs):
|
**kwargs):
|
||||||
library=get_object_or_404(Library, user__username=library)
|
library=get_library_or_404(library=library, library_id=library_id)
|
||||||
context={ 'library':library,
|
context={ 'library':library,
|
||||||
'is_admin': request.user.is_staff or request.user==library.user,
|
'is_admin': request.user.is_staff or request.user==library.user,
|
||||||
'is_member': request.user.is_staff or library.has_user(request.user),
|
'is_member': request.user.is_staff or library.has_user(request.user),
|
||||||
|
@ -22,11 +33,11 @@ def library(request, library,
|
||||||
context.update(extra_context)
|
context.update(extra_context)
|
||||||
return render(request, template, context)
|
return render(request, template, context)
|
||||||
|
|
||||||
def join_library(request, library):
|
def join_library(request, library_id):
|
||||||
library=get_object_or_404(Library, user__username=library)
|
library=get_library_or_404(library_id=library_id)
|
||||||
return Authenticator(request,library).process(
|
return Authenticator(request,library).process(
|
||||||
reverse('library',args=[str(library)]),
|
reverse('library',args=[library.user]),
|
||||||
reverse('bad_library',args=[str(library)]),
|
reverse('bad_library',args=[library.id]),
|
||||||
)
|
)
|
||||||
|
|
||||||
def superlogin(request, extra_context=None, **kwargs):
|
def superlogin(request, extra_context=None, **kwargs):
|
||||||
|
@ -78,3 +89,64 @@ class Authenticator:
|
||||||
def allowed(self):
|
def allowed(self):
|
||||||
backend_test= getattr(backends, self.library.backend + '_authenticate')
|
backend_test= getattr(backends, self.library.backend + '_authenticate')
|
||||||
return backend_test(self.request, self.library)
|
return backend_test(self.request, self.library)
|
||||||
|
|
||||||
|
class CreateLibraryView(CreateView):
|
||||||
|
model = Library
|
||||||
|
template_name="libraryauth/edit.html"
|
||||||
|
form_class = NewLibraryForm
|
||||||
|
|
||||||
|
def get_initial(self):
|
||||||
|
return {'email': self.request.user.email}
|
||||||
|
|
||||||
|
def form_valid(self, form):
|
||||||
|
form.instance.owner = self.request.user
|
||||||
|
user = form.instance.user
|
||||||
|
user.email = form.cleaned_data['email']
|
||||||
|
user.save()
|
||||||
|
form.instance.user = user
|
||||||
|
form.instance.save()
|
||||||
|
context_data = self.get_context_data(form=form)
|
||||||
|
context_data['status'] = 'Library Updated'
|
||||||
|
return HttpResponseRedirect(reverse('library_admin',args=[form.instance.id]))
|
||||||
|
|
||||||
|
|
||||||
|
class UpdateLibraryView(UpdateView):
|
||||||
|
model = Library
|
||||||
|
pk_url_kwarg = 'library_id'
|
||||||
|
template_name="libraryauth/edit.html"
|
||||||
|
form_class = LibraryForm
|
||||||
|
|
||||||
|
def form_valid(self, form):
|
||||||
|
if self.request.user in [form.instance.owner, form.instance.user]:
|
||||||
|
form.instance.save()
|
||||||
|
context_data = self.get_context_data(form=form)
|
||||||
|
context_data['status'] = 'Library Updated.'
|
||||||
|
else:
|
||||||
|
context_data['status'] = 'You\'re not permitted to edit this library.'
|
||||||
|
return self.render_to_response(context_data)
|
||||||
|
|
||||||
|
@login_required
|
||||||
|
def login_as_library(request, library_id):
|
||||||
|
library=get_library_or_404(library_id=library_id)
|
||||||
|
if request.user == library.owner:
|
||||||
|
login_user(request, library.user)
|
||||||
|
|
||||||
|
return HttpResponseRedirect(reverse('library',args=[library.user]))
|
||||||
|
else:
|
||||||
|
return HttpResponseRedirect(reverse('library_admin',args=[library.user]))
|
||||||
|
|
||||||
|
|
||||||
|
def login_user(request, user):
|
||||||
|
"""
|
||||||
|
Log in a user without requiring credentials (using ``login`` from
|
||||||
|
``django.contrib.auth``, first finding a matching backend).
|
||||||
|
magic from https://djangosnippets.org/snippets/1547/
|
||||||
|
|
||||||
|
"""
|
||||||
|
if not hasattr(user, 'backend'):
|
||||||
|
for backend in settings.AUTHENTICATION_BACKENDS:
|
||||||
|
if user == load_backend(backend).get_user(user.pk):
|
||||||
|
user.backend = backend
|
||||||
|
break
|
||||||
|
if hasattr(user, 'backend'):
|
||||||
|
return login_to_user(request, user)
|
Loading…
Reference in New Issue