Skip to content
Browse files

add importer

  • Loading branch information...
1 parent 338c320 commit 3553aa1fa9938e35252daf3af14893823778a640 @aehlke committed Mar 12, 2012
View
13 apps/books/models.py
@@ -1,9 +1,13 @@
+from functools import wraps
+from urllib2 import URLError
+
from django.db import models
from model_utils.managers import manager_from
from amazonproduct import API as AmazonAPI
-from functools import wraps
-import settings
+
from apps.utils.slugs import slugify
+import settings
+
amazon_api = AmazonAPI(settings.AWS_KEY, settings.AWS_SECRET_KEY, 'us')
@@ -38,7 +42,10 @@ class Meta:
app_label = 'flashcards'
def __unicode__(self):
- return self.get_basic_info()['title'] + u' [{0}]'.format(self.isbn)
+ try:
+ return self.get_basic_info()['title'] + u' [{0}]'.format(self.isbn)
+ except URLError:
+ return 'ISBN: {0}'.format(self.isbn)
def save(self, *args, **kwargs):
title = self.get_basic_info()['title']
View
2 apps/books/urls.py
@@ -4,7 +4,6 @@
from django.views.generic.list_detail import object_list, object_detail
-
urlpatterns = patterns('books.views',
url(r'^$', 'book_list',
name='book_list'),
@@ -15,4 +14,3 @@
name='book_detail_with_slug'),
)
-
View
10 apps/books/views.py
@@ -4,14 +4,16 @@
from django.http import HttpResponse
from django.shortcuts import get_object_or_404, render_to_response, redirect
from django.template import RequestContext, loader
-from models import Textbook
-from flashcards.views.shortcuts import get_deck_or_404
from django.views.decorators.http import require_POST
-from flashcards.forms import TextbookSourceForm
-from forms import TextbookForm
from dojango.decorators import json_response
from dojango.util import to_dojo_data, json_decode, json_encode
+from flashcards.forms import TextbookSourceForm
+from flashcards.views.shortcuts import get_deck_or_404
+from forms import TextbookForm
+from models import Textbook
+
+
def book_list(request):
context = {
'books': Textbook.decked_objects.all()
View
2 apps/flashcards/models/cards.py
@@ -47,7 +47,7 @@ class Card(models.Model):
ease_factor = models.FloatField(null=True, blank=True)
interval = models.FloatField(null=True, blank=True, db_index=True) #days
due_at = models.DateTimeField(null=True, blank=True, db_index=True)
-
+
last_ease_factor = models.FloatField(null=True, blank=True)
last_interval = models.FloatField(null=True, blank=True)
last_due_at = models.DateTimeField(null=True, blank=True)
View
24 apps/flashcards/models/cardtemplates.py
@@ -2,9 +2,33 @@
from django.contrib.auth.models import User
from django.forms import ModelForm
from django.forms.util import ErrorList
+from model_utils.managers import manager_from
+class _CardTemplateManager(object):
+ # Unfortunately hard-coded for now, since we have a ton of
+ # extensability built into the system, but very little usage of it.
+ @property
+ def recognition(self):
+ return self.get(name='Recognition')
+
+ @property
+ def production(self):
+ return self.get(name='Production')
+
+ @property
+ def kanji_reading(self):
+ return self.get(name='Kanji Reading')
+
+ @property
+ def kanji_writing(self):
+ return self.get(name='Kanji Writing')
+
+CardTemplateManager = lambda: manager_from(_CardTemplateManager)
+
class CardTemplate(models.Model):
+ objects = CardTemplateManager()
+
fact_type = models.ForeignKey('flashcards.FactType')
name = models.CharField(max_length=50)
View
15 apps/flashcards/models/facts.py
@@ -61,7 +61,6 @@ class Meta:
app_label = 'flashcards'
-
class FactManager(models.Manager):
def all_tags_per_user(self, user):
'''
@@ -196,11 +195,6 @@ def add_new_facts_from_synchronized_decks(self, user, count, deck=None, tags=Non
return new_shared_facts
-
-
-
-
-
class Fact(models.Model):
objects = FactManager()
deck = models.ForeignKey('flashcards.Deck',
@@ -225,13 +219,16 @@ class Fact(models.Model):
parent_fact = models.ForeignKey('self',
blank=True, null=True, related_name='child_facts')
+ def roll_ordinal(self):
+ if not self.new_fact_ordinal:
+ self.new_fact_ordinal = random.randrange(
+ 0, MAX_NEW_CARD_ORDINAL)
+
def save(self, *args, **kwargs):
'''
Set a random sorting index for new cards.
'''
- if not self.new_fact_ordinal:
- self.new_fact_ordinal = random.randrange(
- 0, MAX_NEW_CARD_ORDINAL)
+ self.roll_ordinal()
super(Fact, self).save(*args, **kwargs)
def delete_for_user(self, user):
View
33 apps/flashcards/models/fields.py
@@ -1,9 +1,11 @@
-from apps.utils.templatetags.japanese import strip_ruby_bottom, strip_ruby_text
+import pickle
+
from cachecow.cache import cached_function
-from constants import ISO_639_2_LANGUAGES
from django.db import models, transaction
from model_utils.managers import manager_from
-import pickle
+
+from apps.utils.templatetags.japanese import strip_ruby_bottom, strip_ruby_text
+from constants import ISO_639_2_LANGUAGES
OPTIONAL_CHARACTER_RESTRICTIONS = (
@@ -21,7 +23,28 @@
)
+class _FieldTypeManager(object):
+ @property
+ def expression(self):
+ from apps.flashcards.models import FactType
+ return self.get(name='expression', fact_type=FactType.objects.japanese)
+
+ @property
+ def reading(self):
+ from apps.flashcards.models import FactType
+ return self.get(name='reading', fact_type=FactType.objects.japanese)
+
+ @property
+ def meaning(self):
+ from apps.flashcards.models import FactType
+ return self.get(name='meaning', fact_type=FactType.objects.japanese)
+
+FieldTypeManager = lambda: manager_from(_FieldTypeManager)
+
+
class FieldType(models.Model):
+ objects = FieldTypeManager()
+
fact_type = models.ForeignKey('flashcards.FactType')
# Used for referencing fields by name in code, instead of by id
@@ -33,7 +56,7 @@ class FieldType(models.Model):
transliteration_field_type = models.OneToOneField('self',
blank=True, null=True,
related_name='reverse_transliteration_field_type')
-
+
#constraints
unique = models.BooleanField(default=True)
blank = models.BooleanField(default=False)
@@ -110,7 +133,6 @@ class Meta:
app_label = 'flashcards'
-
class FieldContent(models.Model):
fact = models.ForeignKey('flashcards.Fact', db_index=True)
field_type = models.ForeignKey(FieldType)
@@ -230,7 +252,6 @@ class Meta:
# one field content per field per fact
app_label = 'flashcards'
-
def copy_to_fact(self, fact):
'''
Returns a new FieldContent copy which belongs
View
0 apps/importer/__init__.py
No changes.
View
0 apps/importer/models.py
No changes.
View
69 apps/importer/templates/importer/importer.html
@@ -0,0 +1,69 @@
+{% extends "site_base.html" %}
+
+{% load xhrlinks %}
+{% load i18n lazysignup_tags %}
+{% load cache %}
+
+{% block content_class %}importer{% endblock %}
+
+{% block content %}
+
+<h1>Import a Deck</h1>
+
+{% if request.method == "POST" %}
+
+Created {{ cards_created }} cards. <a href="{{ deck.get_absolute_url }}">View the new deck</a>.
+
+{% else %}
+
+<form method="POST">
+ {% csrf_token %}
+ <p>
+ Paste a tab-separated list of cards: Japanese expression, reading, and meaning.
+ </p>
+ <p>
+ <label for="deck_name">Deck name:</label><br>
+ <input id="deck_name" type="text" name="deck_name" value="{{ deck_name|default:"" }}">
+ </p>
+ <p>
+ <input type="checkbox" name="recognition" id="recognition" checked="checked">
+ <label for="recognition">Recognition</label>
+ <input type="checkbox" name="production" id="production">
+ <label for="production">Production</label>
+ <input type="checkbox" name="kanji_reading" id="kanji_reading">
+ <label for="kanji_reading">Kanji Reading</label>
+ <input type="checkbox" name="kanji_writing" id="kanji_writing">
+ <label for="kanji_writing">Kanji Writing</label>
+ </p>
+ <div>
+ <label for="col0">First:</label>
+ <select name="col0" id="col0">
+ <option name="expression" value="expression" selected="true">Expression</option>
+ <option name="reading" value="reading">Reading</option>
+ <option name="meaning" value="meaning">Meaning</option>
+ </select>
+ <label for="col0">Second:</label>
+ <select name="col1" id="col1">
+ <option name="expression" value="expression">Expression</option>
+ <option name="reading" value="reading" selected="true">Reading</option>
+ <option name="meaning" value="meaning">Meaning</option>
+ </select>
+ <label for="col0">Third:</label>
+ <select name="col2" id="col2">
+ <option name="expression" value="expression">Expression</option>
+ <option name="reading" value="reading">Reading</option>
+ <option name="meaning" value="reading" selected="true">Meaning</option>
+ </select>
+ </div>
+ <p>
+ <textarea id="facts" name="facts" class="full_width" style="height:40em"></textarea>
+ </p>
+
+ <input type="submit" value="Submit">
+
+</form>
+
+{% endif %}
+
+{% endblock %}
+
View
0 apps/importer/tests.py
No changes.
View
6 apps/importer/urls.py
@@ -0,0 +1,6 @@
+from django.conf.urls.defaults import *
+
+urlpatterns = patterns('importer.views',
+ url(r'^$', 'importer'),
+)
+
View
85 apps/importer/views.py
@@ -0,0 +1,85 @@
+import urllib
+
+from django.contrib.auth.decorators import login_required
+from django.http import HttpResponse
+from django.shortcuts import get_object_or_404, render_to_response, redirect
+from django.template import RequestContext, loader
+from django.core.urlresolvers import reverse
+
+from apps.flashcards.models import (Deck, FactType, CardTemplate, Card,
+ FieldContent, FieldType, Fact)
+
+
+@login_required
+def importer(request):
+ context = {}
+
+ if request.method == 'POST':
+ import_facts = []
+ lines = request.POST['facts'].split('\n')
+ for line in lines:
+ if not line.strip():
+ continue
+
+ fields = line.split('\t')
+ import_facts.append({
+ request.POST['col0']: fields[0],
+ request.POST['col1']: fields[1],
+ request.POST['col2']: fields[2],
+ })
+
+ if not len(import_facts):
+ query = ''
+ if request.POST['deck_name'].strip():
+ query = '?' + urllib.urlencode({
+ 'deck_name': request.POST['deck_name'],
+ })
+ return redirect(reverse('importer.views.importer') + query)
+
+ # Now let's import it all.
+
+ deck = Deck.objects.create(
+ name=request.POST['deck_name'],
+ owner=request.user,
+ )
+
+ fact_type = FactType.objects.japanese
+
+ card_templates = []
+ card_template_names = ['recognition', 'production',
+ 'kanji_reading', 'kanji_writing']
+ for template in card_template_names:
+ if request.POST.get(template) == 'on':
+ card_templates.append(getattr(CardTemplate.objects, template))
+
+ for import_fact in import_facts:
+ fact = Fact(
+ deck=deck,
+ fact_type=fact_type,
+ )
+ fact.save()
+
+ for field_name, text in import_fact.iteritems():
+ field_type = getattr(FieldType.objects, field_name)
+ content = FieldContent(
+ fact=fact,
+ field_type=field_type,
+ content=text,
+ )
+ content.save()
+
+ for template in card_templates:
+ card = Card.objects.create(
+ fact=fact,
+ template=template,
+ )
+ card.randomize_new_order()
+
+ context.update({
+ 'cards_created': deck.card_count,
+ 'deck': deck,
+ })
+ return render_to_response('importer/importer.html', context,
+ context_instance=RequestContext(request))
+
+
View
3 static/css/misc.css
@@ -146,6 +146,9 @@ hr {
.inner_body_contents:not(.wide) > *:not(.wide):not(hr) {
max-width: 57.2em;
}
+.full_width {
+ width: 57.2em;
+}
#body {
width: 100%;
padding: 0px;
View
2 templates/credits.html
@@ -1,7 +1,5 @@
-
{% extends base_template_name %}
-
{% block content %}
<h2>Credits</h2>
View
1 templates/tos.html
@@ -1,6 +1,5 @@
{% extends base_template_name %}
-
{% block content %}
<h2>Terms of Service</h2>
View
1 urls.py
@@ -74,6 +74,7 @@
(r'^dojango/', include('dojango.urls')),
(r'^flashcards/', include('flashcards.urls')),
(r'^textbooks/', include('books.urls')),
+ (r'^importer/', include('importer.urls')),
(r'^jdic/', include('jdic.urls')),
(r'^kanjivg/', include('kanjivg.urls')),
(r'^stats/', include('stats.urls')),
View
6 views.py
@@ -12,7 +12,6 @@
from django.views.decorators.cache import cache_page
-
def index(request):
'''Entry point to the site.'''
context = {
@@ -45,8 +44,3 @@ def home(request):
return render_to_response('home.html', context,
context_instance=RequestContext(request, processors=[card_existence_context]))
-
-
-
-
-

0 comments on commit 3553aa1

Please sign in to comment.
Something went wrong with that request. Please try again.