Merge pull request #709 from Gluejar/open-edition-edit

Open edition editing
pull/43/head
eshellman 2017-10-26 13:34:10 -04:00 committed by GitHub
commit a1ab17f150
11 changed files with 83 additions and 41 deletions

View File

@ -37,7 +37,7 @@ from regluit.utils.localdatetime import now
from . import cc
from . import models
from .parameters import WORK_IDENTIFIERS
from .validation import identifier_cleaner
from .validation import identifier_cleaner, unreverse_name
from .loaders.scrape import get_scraper, scrape_sitemap
logger = logging.getLogger(__name__)
@ -517,6 +517,9 @@ def merge_works(w1, w2, user=None):
w2source = wishlist.work_source(w2)
wishlist.remove_work(w2)
wishlist.add_work(w1, w2source)
for userprofile in w2.contributors.all():
userprofile.works.remove(w2)
userprofile.works.add(w1)
for identifier in w2.identifiers.all():
identifier.work = w1
identifier.save()
@ -735,16 +738,6 @@ IDTABLE = [('librarything', 'ltwk'), ('goodreads', 'gdrd'), ('openlibrary', 'olw
('edition_id', 'edid'), ('googlebooks', 'goog'), ('doi', 'doi'),
]
def unreverse(name):
if not ',' in name:
return name
(last, rest) = name.split(',', 1)
if not ',' in rest:
return '%s %s' % (rest.strip(), last.strip())
(first, rest) = rest.split(',', 1)
return '%s %s, %s' % (first.strip(), last.strip(), rest.strip())
def load_from_yaml(yaml_url, test_mode=False):
"""
This really should be called 'load_from_github_yaml'
@ -877,7 +870,7 @@ class BasePandataLoader(object):
rel_code = inverse_marc_rels.get(key, 'aut')
creators = creators if isinstance(creators, list) else [creators]
for creator in creators:
edition.add_author(unreverse(creator.get('agent_name', '')), relation=rel_code)
edition.add_author(unreverse_name(creator.get('agent_name', '')), relation=rel_code)
for yaml_subject in metadata.subjects: #always add yaml subjects (don't clear)
if isinstance(yaml_subject, tuple):
(authority, heading) = yaml_subject

View File

@ -0,0 +1,19 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('core', '0009_auto_20170808_0846'),
]
operations = [
migrations.AddField(
model_name='userprofile',
name='works',
field=models.ManyToManyField(related_name='contributors', to='core.Work', blank=True),
),
]

View File

@ -1211,6 +1211,9 @@ class UserProfile(models.Model):
librarything_id = models.CharField(max_length=31, blank=True)
badges = models.ManyToManyField('Badge', related_name='holders', blank=True)
kindle_email = models.EmailField(max_length=254, blank=True)
# keep track of work the user adds
works = models.ManyToManyField('Work', related_name='contributors', blank=True)
goodreads_user_id = models.CharField(max_length=32, null=True, blank=True)
goodreads_user_name = models.CharField(max_length=200, null=True, blank=True)

View File

@ -129,6 +129,17 @@ def valid_subject( subject_name ):
return False
return True
reverse_name_comma = re.compile(r',(?! *Jr[\., ])')
def unreverse_name(name):
if not reverse_name_comma.search(name):
return name
(last, rest) = name.split(',', 1)
if not ',' in rest:
return '%s %s' % (rest.strip(), last.strip())
(first, rest) = rest.split(',', 1)
return '%s %s, %s' % (first.strip(), last.strip(), rest.strip())
def authlist_cleaner(authlist):
''' given a author string or list of author strings, checks that the author string
is not a list of author names and that no author is repeated'''
@ -144,16 +155,18 @@ def authlist_cleaner(authlist):
# Match comma but not ", Jr"
comma_list_delim = re.compile(r',(?! *Jr[\., ])')
spaces = re.compile(r'\s+')
_and_ = re.compile(r',? and ')
_and_ = re.compile(r',? (and|\&) ')
semicolon_list_delim = re.compile(r'[\;|\&]')
def auth_cleaner(auth):
''' given a author string checks that the author string
is not a list of author names'''
cleaned = []
auth = _and_.sub(',', auth)
if ';' in auth:
authlist = auth.split(';')
authlist = semicolon_list_delim.split(auth)
authlist = [unreverse_name(name) for name in authlist]
else:
auth = _and_.sub(',', auth)
authlist = comma_list_delim.split(auth)
for auth in authlist:
cleaned.append(spaces.sub(' ', auth.strip()))

View File

@ -51,7 +51,7 @@ class IdentifierForm(forms.ModelForm):
required=False,
)
make_new = forms.BooleanField(
label='There\'s no existing Identifier, so please use an Unglue.it ID',
label='There\'s no existing Identifier. ',
required=False,
)
identifier = None
@ -61,7 +61,7 @@ class IdentifierForm(forms.ModelForm):
id_value = self.cleaned_data.get('id_value', '').strip()
make_new = self.cleaned_data.get('make_new', False)
if not make_new:
self.cleaned_data['value'] = identifier_cleaner(id_type)(id_value)
self.cleaned_data['id_value'] = identifier_cleaner(id_type)(id_value)
return self.cleaned_data
class Meta:

View File

@ -238,7 +238,12 @@ ul.fancytree-container {
{% else %}
{% if edition.work %}
<h2><a href="{% url 'work' edition.work.id %}">{{ edition.work.title }}</a> was added to Unglue.it on {{ edition.work.created }}</h2>
{% include 'edition_display.html' %}
<div class="launch_top pale">
Are you the author or other rightsholder for this work?
To edit the metadata or add editions, become an Unglue.it <a href="{% url 'rightsholders' %}">rights holder</a>.
</div>
{% else %}
Sorry, there's no work specified.
{% endif %}

View File

@ -39,11 +39,7 @@
web: <a href="{{ edition.http_id }}">{{ edition.http_id }}</a><br />
{% endif %}
{% if not managing %}
{% if user.is_staff %}
<a href="{% url 'new_edition' work_id edition.id %}">Edit this edition</a><br />
{% elif user in work.last_campaign.managers.all %}
<a href="{% url 'new_edition' work_id edition.id %}">Edit this edition</a><br />
{% elif user.rights_holder.count and not work.last_campaign %}
{% if user_can_edit_work %}
<a href="{% url 'new_edition' work_id edition.id %}">Edit this edition</a><br />
{% endif %}
{% if user.is_authenticated %}

View File

@ -18,6 +18,9 @@
<p>To add a work and edition to Unglue.it, we need to start with an identifier. We'll see if we can find some metadata based on the identifier you give us. If you give us an ISBN, we'll often be able to find some. If there's no ISBN, give us a URL (a web address) and we'll check the page for bibliographic info. </p>
{% if not request.user.rights_holder.all.count %}
<p>If someone else has already added the work to unglue.it, you may not be able to edit its metadata.</p>
{% endif %}
<form id="editform" enctype="multipart/form-data" method="POST" action="#">
{% csrf_token %}
{{ form.as_p }}

View File

@ -476,7 +476,7 @@
<ul id="kw_list"></ul>
{% endif %}
{% if user.is_staff or user in work.last_campaign.managers.all %}
{% if user_can_edit_work %}
<form method="POST" id="kw_add_form">{% csrf_token %}
{{ kwform.add_kw }}<input type="hidden" name="kw_add" value="true"> <input type="submit" name="kw_add_fake" value="add keyword" id="kw_add_form_submit" />
</form>
@ -486,7 +486,7 @@
{% if alert %}
<div class="yikes"><br />{{ alert }}</div>
{% endif %}
{% if user.is_staff or user in work.last_campaign.managers.all %}
{% if user_can_edit_work %}
<div><a href="{% url 'new_edition' work_id edition.id %}">Create a new edition for this work</a><br /><br /></div>
{% endif %}

View File

@ -397,6 +397,7 @@ def work(request, work_id, action='display'):
return render(request, 'work.html', {
'work': work,
'user_can_edit_work': user_can_edit_work(request.user, work),
'premiums': premiums,
'ungluers': userlists.supporting_users(work, 5),
'claimform': claimform,
@ -642,6 +643,8 @@ def googlebooks(request, googlebooks_id):
if edition.new:
# add related editions asynchronously
tasks.populate_edition.delay(edition.isbn_13)
if request.user.is_authenticated():
request.user.profile.works.add(edition.work)
except bookloader.LookupFailure:
logger.warning("failed to load googlebooks_id %s" % googlebooks_id)
return HttpResponseNotFound("failed looking up googlebooks id %s" % googlebooks_id)

View File

@ -29,15 +29,19 @@ def user_can_edit_work(user, work):
'''
Check if a user is allowed to edit the work
'''
if user.is_staff :
if user.is_anonymous():
return False
elif user.is_staff :
return True
elif work and work.last_campaign():
return user in work.last_campaign().managers.all()
elif user.rights_holder.count() and (work == None or not work.last_campaign()):
# allow rights holders to edit unless there is a campaign
return True
elif work and work.claim.all():
return True if work.claim.filter(user=user) else False
else:
return False
return user.profile in work.contributors.all()
def safe_get_work(work_id):
"""
@ -68,6 +72,11 @@ def get_edition(edition_id):
except models.Edition.DoesNotExist:
raise Http404 (duplicate-code)
def user_edition(edition, user):
if user and user.is_authenticated() and edition:
user.profile.works.add(edition.work)
return edition
def get_edition_for_id(id_type, id_value, user=None):
''' the identifier is assumed to not be in database '''
identifiers = {id_type: id_value}
@ -87,17 +96,18 @@ def get_edition_for_id(id_type, id_value, user=None):
if identifiers.has_key('goog'):
edition = add_by_googlebooks_id(identifiers['goog'])
if edition:
return edition
return user_edition(edition, user)
if identifiers.has_key('isbn'):
edition = add_by_isbn(identifiers['isbn'])
if edition:
return edition
return user_edition(edition, user)
if identifiers.has_key('oclc'):
edition = add_by_oclc(identifiers['oclc'])
if edition:
return edition
return user_edition(edition, user)
if identifiers.has_key('glue'):
try:
@ -108,7 +118,7 @@ def get_edition_for_id(id_type, id_value, user=None):
if identifiers.has_key('http'):
edition = add_by_webpage(identifiers['http'], user=user)
return edition
return user_edition(edition, user)
# return a dummy edition and identifier
@ -126,7 +136,7 @@ def get_edition_for_id(id_type, id_value, user=None):
models.Identifier.objects.create(type=key, value=id_value, work=work, edition=None)
else:
models.Identifier.objects.create(type=key, value=id_value, work=work, edition=edition)
return edition
return user_edition(edition, user)
@login_required
def new_edition(request, by=None):
@ -138,7 +148,7 @@ def new_edition(request, by=None):
form = IdentifierForm(data=request.POST)
if form.is_valid():
if form.cleaned_data.get('make_new', False):
edition = get_edition_for_id('glue', 'new')
edition = get_edition_for_id('glue', 'new', user=request.user)
else:
id_type = form.cleaned_data['id_type']
id_value = form.cleaned_data['id_value']
@ -238,17 +248,14 @@ def edit_edition(request, work_id, edition_id, by=None):
ebookchange = True
if ebookchange:
form = EditionForm(instance=edition, data=request.POST, files=request.FILES)
if request.POST.has_key('add_author_submit') and admin:
if request.POST.get('add_author', None) and admin:
new_author_name = request.POST['add_author'].strip()
new_author_relation = request.POST['add_author_relation']
try:
author = models.Author.objects.get(name=new_author_name)
except models.Author.DoesNotExist:
author = models.Author.objects.create(name=new_author_name)
edition.new_authors.append((new_author_name, new_author_relation))
form = EditionForm(instance=edition, data=request.POST, files=request.FILES)
elif not form and admin:
form = EditionForm(instance=edition, data=request.POST, files=request.FILES)
if (new_author_name, new_author_relation) not in edition.new_authors:
edition.new_authors.append((new_author_name, new_author_relation))
form = EditionForm(instance=edition, data=request.POST, files=request.FILES)
if not request.POST.has_key('add_author_submit') and admin:
if form.is_valid():
form.save()
if not work: