commit
a1ab17f150
|
@ -37,7 +37,7 @@ from regluit.utils.localdatetime import now
|
||||||
from . import cc
|
from . import cc
|
||||||
from . import models
|
from . import models
|
||||||
from .parameters import WORK_IDENTIFIERS
|
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
|
from .loaders.scrape import get_scraper, scrape_sitemap
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
@ -517,6 +517,9 @@ def merge_works(w1, w2, user=None):
|
||||||
w2source = wishlist.work_source(w2)
|
w2source = wishlist.work_source(w2)
|
||||||
wishlist.remove_work(w2)
|
wishlist.remove_work(w2)
|
||||||
wishlist.add_work(w1, w2source)
|
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():
|
for identifier in w2.identifiers.all():
|
||||||
identifier.work = w1
|
identifier.work = w1
|
||||||
identifier.save()
|
identifier.save()
|
||||||
|
@ -735,16 +738,6 @@ IDTABLE = [('librarything', 'ltwk'), ('goodreads', 'gdrd'), ('openlibrary', 'olw
|
||||||
('edition_id', 'edid'), ('googlebooks', 'goog'), ('doi', 'doi'),
|
('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):
|
def load_from_yaml(yaml_url, test_mode=False):
|
||||||
"""
|
"""
|
||||||
This really should be called 'load_from_github_yaml'
|
This really should be called 'load_from_github_yaml'
|
||||||
|
@ -877,7 +870,7 @@ class BasePandataLoader(object):
|
||||||
rel_code = inverse_marc_rels.get(key, 'aut')
|
rel_code = inverse_marc_rels.get(key, 'aut')
|
||||||
creators = creators if isinstance(creators, list) else [creators]
|
creators = creators if isinstance(creators, list) else [creators]
|
||||||
for creator in 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)
|
for yaml_subject in metadata.subjects: #always add yaml subjects (don't clear)
|
||||||
if isinstance(yaml_subject, tuple):
|
if isinstance(yaml_subject, tuple):
|
||||||
(authority, heading) = yaml_subject
|
(authority, heading) = yaml_subject
|
||||||
|
|
|
@ -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),
|
||||||
|
),
|
||||||
|
]
|
|
@ -1211,6 +1211,9 @@ class UserProfile(models.Model):
|
||||||
librarything_id = models.CharField(max_length=31, blank=True)
|
librarything_id = models.CharField(max_length=31, blank=True)
|
||||||
badges = models.ManyToManyField('Badge', related_name='holders', blank=True)
|
badges = models.ManyToManyField('Badge', related_name='holders', blank=True)
|
||||||
kindle_email = models.EmailField(max_length=254, 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_id = models.CharField(max_length=32, null=True, blank=True)
|
||||||
goodreads_user_name = models.CharField(max_length=200, null=True, blank=True)
|
goodreads_user_name = models.CharField(max_length=200, null=True, blank=True)
|
||||||
|
|
|
@ -129,6 +129,17 @@ def valid_subject( subject_name ):
|
||||||
return False
|
return False
|
||||||
return True
|
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):
|
def authlist_cleaner(authlist):
|
||||||
''' given a author string or list of author strings, checks that the author string
|
''' 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'''
|
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"
|
# Match comma but not ", Jr"
|
||||||
comma_list_delim = re.compile(r',(?! *Jr[\., ])')
|
comma_list_delim = re.compile(r',(?! *Jr[\., ])')
|
||||||
spaces = re.compile(r'\s+')
|
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):
|
def auth_cleaner(auth):
|
||||||
''' given a author string checks that the author string
|
''' given a author string checks that the author string
|
||||||
is not a list of author names'''
|
is not a list of author names'''
|
||||||
cleaned = []
|
cleaned = []
|
||||||
auth = _and_.sub(',', auth)
|
|
||||||
if ';' in auth:
|
if ';' in auth:
|
||||||
authlist = auth.split(';')
|
authlist = semicolon_list_delim.split(auth)
|
||||||
|
authlist = [unreverse_name(name) for name in authlist]
|
||||||
else:
|
else:
|
||||||
|
auth = _and_.sub(',', auth)
|
||||||
authlist = comma_list_delim.split(auth)
|
authlist = comma_list_delim.split(auth)
|
||||||
for auth in authlist:
|
for auth in authlist:
|
||||||
cleaned.append(spaces.sub(' ', auth.strip()))
|
cleaned.append(spaces.sub(' ', auth.strip()))
|
||||||
|
|
|
@ -51,7 +51,7 @@ class IdentifierForm(forms.ModelForm):
|
||||||
required=False,
|
required=False,
|
||||||
)
|
)
|
||||||
make_new = forms.BooleanField(
|
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,
|
required=False,
|
||||||
)
|
)
|
||||||
identifier = None
|
identifier = None
|
||||||
|
@ -61,7 +61,7 @@ class IdentifierForm(forms.ModelForm):
|
||||||
id_value = self.cleaned_data.get('id_value', '').strip()
|
id_value = self.cleaned_data.get('id_value', '').strip()
|
||||||
make_new = self.cleaned_data.get('make_new', False)
|
make_new = self.cleaned_data.get('make_new', False)
|
||||||
if not make_new:
|
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
|
return self.cleaned_data
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
|
|
|
@ -238,7 +238,12 @@ ul.fancytree-container {
|
||||||
|
|
||||||
{% else %}
|
{% else %}
|
||||||
{% if edition.work %}
|
{% 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' %}
|
{% 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 %}
|
{% else %}
|
||||||
Sorry, there's no work specified.
|
Sorry, there's no work specified.
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
|
@ -39,11 +39,7 @@
|
||||||
web: <a href="{{ edition.http_id }}">{{ edition.http_id }}</a><br />
|
web: <a href="{{ edition.http_id }}">{{ edition.http_id }}</a><br />
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% if not managing %}
|
{% if not managing %}
|
||||||
{% if user.is_staff %}
|
{% if user_can_edit_work %}
|
||||||
<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 %}
|
|
||||||
<a href="{% url 'new_edition' work_id edition.id %}">Edit this edition</a><br />
|
<a href="{% url 'new_edition' work_id edition.id %}">Edit this edition</a><br />
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% if user.is_authenticated %}
|
{% if user.is_authenticated %}
|
||||||
|
|
|
@ -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>
|
<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="#">
|
<form id="editform" enctype="multipart/form-data" method="POST" action="#">
|
||||||
{% csrf_token %}
|
{% csrf_token %}
|
||||||
{{ form.as_p }}
|
{{ form.as_p }}
|
||||||
|
|
|
@ -476,7 +476,7 @@
|
||||||
<ul id="kw_list"></ul>
|
<ul id="kw_list"></ul>
|
||||||
|
|
||||||
{% endif %}
|
{% 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 %}
|
<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" />
|
{{ 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>
|
</form>
|
||||||
|
@ -486,7 +486,7 @@
|
||||||
{% if alert %}
|
{% if alert %}
|
||||||
<div class="yikes"><br />{{ alert }}</div>
|
<div class="yikes"><br />{{ alert }}</div>
|
||||||
{% endif %}
|
{% 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>
|
<div><a href="{% url 'new_edition' work_id edition.id %}">Create a new edition for this work</a><br /><br /></div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
|
|
|
@ -397,6 +397,7 @@ def work(request, work_id, action='display'):
|
||||||
|
|
||||||
return render(request, 'work.html', {
|
return render(request, 'work.html', {
|
||||||
'work': work,
|
'work': work,
|
||||||
|
'user_can_edit_work': user_can_edit_work(request.user, work),
|
||||||
'premiums': premiums,
|
'premiums': premiums,
|
||||||
'ungluers': userlists.supporting_users(work, 5),
|
'ungluers': userlists.supporting_users(work, 5),
|
||||||
'claimform': claimform,
|
'claimform': claimform,
|
||||||
|
@ -642,6 +643,8 @@ def googlebooks(request, googlebooks_id):
|
||||||
if edition.new:
|
if edition.new:
|
||||||
# add related editions asynchronously
|
# add related editions asynchronously
|
||||||
tasks.populate_edition.delay(edition.isbn_13)
|
tasks.populate_edition.delay(edition.isbn_13)
|
||||||
|
if request.user.is_authenticated():
|
||||||
|
request.user.profile.works.add(edition.work)
|
||||||
except bookloader.LookupFailure:
|
except bookloader.LookupFailure:
|
||||||
logger.warning("failed to load googlebooks_id %s" % googlebooks_id)
|
logger.warning("failed to load googlebooks_id %s" % googlebooks_id)
|
||||||
return HttpResponseNotFound("failed looking up googlebooks id %s" % googlebooks_id)
|
return HttpResponseNotFound("failed looking up googlebooks id %s" % googlebooks_id)
|
||||||
|
|
|
@ -29,15 +29,19 @@ def user_can_edit_work(user, work):
|
||||||
'''
|
'''
|
||||||
Check if a user is allowed to edit the 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
|
return True
|
||||||
elif work and work.last_campaign():
|
elif work and work.last_campaign():
|
||||||
return user in work.last_campaign().managers.all()
|
return user in work.last_campaign().managers.all()
|
||||||
elif user.rights_holder.count() and (work == None or not work.last_campaign()):
|
elif user.rights_holder.count() and (work == None or not work.last_campaign()):
|
||||||
# allow rights holders to edit unless there is a campaign
|
# allow rights holders to edit unless there is a campaign
|
||||||
return True
|
return True
|
||||||
|
elif work and work.claim.all():
|
||||||
|
return True if work.claim.filter(user=user) else False
|
||||||
else:
|
else:
|
||||||
return False
|
return user.profile in work.contributors.all()
|
||||||
|
|
||||||
def safe_get_work(work_id):
|
def safe_get_work(work_id):
|
||||||
"""
|
"""
|
||||||
|
@ -68,6 +72,11 @@ def get_edition(edition_id):
|
||||||
except models.Edition.DoesNotExist:
|
except models.Edition.DoesNotExist:
|
||||||
raise Http404 (duplicate-code)
|
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):
|
def get_edition_for_id(id_type, id_value, user=None):
|
||||||
''' the identifier is assumed to not be in database '''
|
''' the identifier is assumed to not be in database '''
|
||||||
identifiers = {id_type: id_value}
|
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'):
|
if identifiers.has_key('goog'):
|
||||||
edition = add_by_googlebooks_id(identifiers['goog'])
|
edition = add_by_googlebooks_id(identifiers['goog'])
|
||||||
if edition:
|
if edition:
|
||||||
return edition
|
|
||||||
|
return user_edition(edition, user)
|
||||||
|
|
||||||
if identifiers.has_key('isbn'):
|
if identifiers.has_key('isbn'):
|
||||||
edition = add_by_isbn(identifiers['isbn'])
|
edition = add_by_isbn(identifiers['isbn'])
|
||||||
if edition:
|
if edition:
|
||||||
return edition
|
return user_edition(edition, user)
|
||||||
|
|
||||||
if identifiers.has_key('oclc'):
|
if identifiers.has_key('oclc'):
|
||||||
edition = add_by_oclc(identifiers['oclc'])
|
edition = add_by_oclc(identifiers['oclc'])
|
||||||
if edition:
|
if edition:
|
||||||
return edition
|
return user_edition(edition, user)
|
||||||
|
|
||||||
if identifiers.has_key('glue'):
|
if identifiers.has_key('glue'):
|
||||||
try:
|
try:
|
||||||
|
@ -108,7 +118,7 @@ def get_edition_for_id(id_type, id_value, user=None):
|
||||||
|
|
||||||
if identifiers.has_key('http'):
|
if identifiers.has_key('http'):
|
||||||
edition = add_by_webpage(identifiers['http'], user=user)
|
edition = add_by_webpage(identifiers['http'], user=user)
|
||||||
return edition
|
return user_edition(edition, user)
|
||||||
|
|
||||||
|
|
||||||
# return a dummy edition and identifier
|
# 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)
|
models.Identifier.objects.create(type=key, value=id_value, work=work, edition=None)
|
||||||
else:
|
else:
|
||||||
models.Identifier.objects.create(type=key, value=id_value, work=work, edition=edition)
|
models.Identifier.objects.create(type=key, value=id_value, work=work, edition=edition)
|
||||||
return edition
|
return user_edition(edition, user)
|
||||||
|
|
||||||
@login_required
|
@login_required
|
||||||
def new_edition(request, by=None):
|
def new_edition(request, by=None):
|
||||||
|
@ -138,7 +148,7 @@ def new_edition(request, by=None):
|
||||||
form = IdentifierForm(data=request.POST)
|
form = IdentifierForm(data=request.POST)
|
||||||
if form.is_valid():
|
if form.is_valid():
|
||||||
if form.cleaned_data.get('make_new', False):
|
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:
|
else:
|
||||||
id_type = form.cleaned_data['id_type']
|
id_type = form.cleaned_data['id_type']
|
||||||
id_value = form.cleaned_data['id_value']
|
id_value = form.cleaned_data['id_value']
|
||||||
|
@ -238,17 +248,14 @@ def edit_edition(request, work_id, edition_id, by=None):
|
||||||
ebookchange = True
|
ebookchange = True
|
||||||
if ebookchange:
|
if ebookchange:
|
||||||
form = EditionForm(instance=edition, data=request.POST, files=request.FILES)
|
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_name = request.POST['add_author'].strip()
|
||||||
new_author_relation = request.POST['add_author_relation']
|
new_author_relation = request.POST['add_author_relation']
|
||||||
try:
|
if (new_author_name, new_author_relation) not in edition.new_authors:
|
||||||
author = models.Author.objects.get(name=new_author_name)
|
edition.new_authors.append((new_author_name, new_author_relation))
|
||||||
except models.Author.DoesNotExist:
|
form = EditionForm(instance=edition, data=request.POST, files=request.FILES)
|
||||||
author = models.Author.objects.create(name=new_author_name)
|
if not request.POST.has_key('add_author_submit') and admin:
|
||||||
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 form.is_valid():
|
if form.is_valid():
|
||||||
form.save()
|
form.save()
|
||||||
if not work:
|
if not work:
|
||||||
|
|
Loading…
Reference in New Issue