Permalink
Browse files

fixed more bugs related to upstream cards. added django contrib auth …

…option to REST API.
  • Loading branch information...
aehlke committed Apr 6, 2011
1 parent 378365d commit edca6ddea028053a7ec4af5de83d12b6f0a75c4c
View
4 TODO
@@ -102,6 +102,8 @@ per-day scheduling
~new stuff~
-----------
+upgrade errorlog app
+
option to hide furigana on cards
include maturity/newness status in 'next_cards_for_review' -- use to display tally in summary screen
@@ -142,8 +144,6 @@ reading generation for sentences is broken (see firebug, js error)
early review cut short
--NY isnt default timezone
-
ensure the next card up is the one that was undone
gray out the fields while fact submission is in progress (and make sure cmd-enter is disabled then too)
@@ -64,12 +64,11 @@ def review_start_context(request, deck=None):
with_upstream=True, deck=deck)
due_card_count = cards.due(user).count()
- new_card_count = cards.new(user).count()
+ new_card_count = cards.new_count(user)
card_count = cards.count()
- unspaced_new_card_count = Card.objects.next_cards_count(
- user, deck=deck, new_cards_only=True)
+ unspaced_new_card_count = cards.unspaced_new_count(user)
context = {
'card_count': card_count,
@@ -67,17 +67,23 @@ class Meta:
app_label = 'flashcards'
def __unicode__(self):
- from django.utils.html import strip_tags
+ from BeautifulSoup import BeautifulSoup
fields = dict((field.field_type.name, field)
for field in self.fact.field_contents)
card_context = {'fields': fields}
- front = render_to_string(
- self.template.front_template_name, card_context)
- back = render_to_string(
- self.template.back_template_name, card_context)
-
- return strip_tags(u'{0} | {1}'.format(front, back))
+ def format_(content):
+ page = BeautifulSoup(content)
+ for tag in page.findAll('script'):
+ tag.extract() # Remove the tag.
+ return u''.join(page.findAll(text=True)).replace('\n', '').strip()
+
+ front = format_(render_to_string(
+ self.template.front_template_name, card_context))
+ back = format_(render_to_string(
+ self.template.back_template_name, card_context))
+ return u'{0} | {1}'.format(front, back)
+
def to_api_dict(self):
'''
@@ -81,7 +81,7 @@ class Deck(models.Model):
def __unicode__(self):
- return self.name
+ return u'{0} ({1})'.format(self.name, self.owner)
class Meta:
app_label = 'flashcards'
@@ -130,6 +130,7 @@ def with_upstream(self, user, deck=None, tags=None):
if tags:
tagged_facts = usertagging.models.UserTaggedItem.objects.get_by_model(Fact, tags)
user_facts = user_facts.filter(id__in=tagged_facts)
+
subscriber_decks = decks.filter(synchronized_with__isnull=False)
subscribed_decks = [deck.synchronized_with for deck in subscriber_decks if deck.synchronized_with is not None]
#shared_facts = self.filter(deck_id__in=shared_deck_ids)
@@ -145,16 +146,20 @@ def add_new_facts_from_synchronized_decks(self, user, count, deck=None, tags=Non
'''
from cards import Card
from decks import Deck
+
if deck:
if not deck.synchronized_with:
return self.none()
- decks = Deck.objects.filter(id=deck.id)
+ decks = Deck.objects.filter(id=deck.synchronized_with_id)
else:
decks = Deck.objects.synchronized_decks(user)
+
user_facts = self.filter(deck__owner=user, deck__in=decks, active=True, parent_fact__isnull=True)
+
if tags:
tagged_facts = usertagging.models.UserTaggedItem.objects.get_by_model(Fact, tags)
user_facts = user_facts.filter(fact__in=tagged_facts)
+
#shared_deck_ids = [deck.synchronized_with_id for deck in decks if deck.synchronized_with_id]
new_shared_facts = self.filter(active=True, deck__in=decks.filter(synchronized_with__isnull=False)).exclude(id__in=user_facts)
new_shared_facts = new_shared_facts.order_by('new_fact_ordinal')
@@ -394,7 +399,7 @@ def copy_to_deck(self, deck, copy_field_contents=False, copy_subfacts=False, syn
copy = Fact(deck=deck, fact_type=self.fact_type, active=self.active, notes=self.notes, new_fact_ordinal=self.new_fact_ordinal)
if synchronize:
if self.synchronized_with:
- raise TypeError('Cannot synchronize with a fact that is already a synschronized fact.')
+ raise TypeError('Cannot synchronize with a fact that is already a synchronized fact.')
elif not self.deck.shared_at:
raise TypeError('This is not a shared fact - cannot synchronize with it.')
#TODO enforce deck synchronicity too
@@ -436,6 +441,7 @@ class Meta:
def __unicode__(self):
+ return unicode(self.id)
field_content_contents = []
for field_content in self.fieldcontent_set.all():
field_content_contents.append(field_content.content)
@@ -118,12 +118,13 @@ def _next_failed_not_due_cards(self, user, initial_query, count,
return card_query[:count]
def _next_new_cards(self, user, initial_query, count, review_time,
- excluded_ids=[], early_review=False,
- deck=None, tags=None):
+ excluded_ids=[], early_review=False, deck=None, tags=None,
+ add_upstream_facts_as_needed=True):
'''
Gets the next new cards for this user or deck.
'''
from flashcards.models.facts import Fact
+
if not count:
return []
@@ -163,19 +164,23 @@ def _next_new_cards2():
new_cards = _next_new_cards2()
- if len(new_cards) < count:
+ if add_upstream_facts_as_needed and len(new_cards) < count:
# Still have fewer cards than requested.
# See if we can get new cards from synchronized decks.
- facts_added = Fact.objects.add_new_facts_from_synchronized_decks(user, count - len(new_cards), deck=deck, tags=tags)
+ facts_added = Fact.objects.add_new_facts_from_synchronized_decks(
+ user, count - len(new_cards), deck=deck, tags=tags)
if len(facts_added):
- # got new facts from a synchronized deck. get cards from them by re-getting new cards
+ # Got new facts from a synchronized deck.
+ # Get cards from them by re-getting new cards
new_cards = _next_new_cards2()
eligible_ids = [card.id for card in new_cards]
if early_review and len(eligible_ids) < count:
- # queue up spaced cards if needed for early review
- eligible_ids.extend([card.id for card in new_card_query.exclude(id__in=eligible_ids).select_related()[:count - len(eligible_ids)]])
+ # Queue up spaced cards if needed for early review.
+ eligible_ids.extend([card.id for card in new_card_query.exclude(
+ id__in=eligible_ids).select_related()
+ [:count - len(eligible_ids)]])
# Return a query containing the eligible cards.
ret = self.filter(id__in=eligible_ids).order_by('new_card_ordinal')
@@ -235,31 +240,31 @@ def _next_cards(self, early_review=False):
#TODO not sure what this is necessary for, actually - it's used in one
# place and can probably be merged with something else.
- def next_cards_count(self, user, excluded_ids=[], session_start=False,
- deck=None, tags=None, early_review=False,
- new_cards_only=False):
- now = datetime.datetime.utcnow()
-
- if new_cards_only:
- card_funcs = [self._next_new_cards]
- else:
- card_funcs = self._next_cards(
- early_review=early_review)
-
- user_cards = self.common_filters(user,
- with_upstream=True,
- deck=deck, excluded_ids=excluded_ids, tags=tags)
-
- count = 0
- cards_left = 99999 #TODO find a more elegant approach
- for card_func in card_funcs:
- cards = card_func(
- user, user_cards, cards_left, now, excluded_ids,
- early_review=early_review,
- deck=deck,
- tags=tags)
- count += cards.count()
- return count
+ #def next_cards_count(self, user, excluded_ids=[], session_start=False,
+ # deck=None, tags=None, early_review=False,
+ # new_cards_only=False):
+ # now = datetime.datetime.utcnow()
+
+ # if new_cards_only:
+ # card_funcs = [self._next_new_cards]
+ # else:
+ # card_funcs = self._next_cards(
+ # early_review=early_review)
+
+ # user_cards = self.common_filters(user,
+ # with_upstream=True,
+ # deck=deck, excluded_ids=excluded_ids, tags=tags)
+
+ # count = 0
+ # cards_left = 99999 #TODO find a more elegant approach
+ # for card_func in card_funcs:
+ # cards = card_func(
+ # user, user_cards, cards_left, now, excluded_ids,
+ # early_review=early_review,
+ # deck=deck,
+ # tags=tags)
+ # count += cards.count()
+ # return count
def next_cards(self, user, count, excluded_ids=[],
session_start=False, deck=None, tags=None, early_review=False):
@@ -396,6 +401,26 @@ def new_count(self, user):
Any uncopied upstream cards are to be considered "new".
'''
return self.new(user).count() + self.of_upstream(user).count()
+
+ def unspaced_new_count(self, user):
+ '''
+ Same as `new_count`, except it subtracts new cards that
+ will be delayed due to sibling spacing.
+
+ Works properly with upstream cards.
+ '''
+ local_query = self.new(user)
+ desired_count = 999999 #TODO use more elegant solution.
+ now = datetime.datetime.utcnow()
+ local = self._next_new_cards(user, local_query, desired_count, now,
+ add_upstream_facts_as_needed=False).count()
+
+ # Count the number of upstream cards -- they are all "new".
+ # But only count one card per distinct fact, to simulate
+ # the effect of sibling spacing.
+ upstream = self.of_upstream(user).values('fact_id').distinct().count()
+
+ return local + upstream
def young(self, user):
return self.filter(
@@ -9,7 +9,7 @@
{% if user|is_lazy_user %}
<p class="new_user_info_box">
- <strong>Welcome to Manabi!</strong> First choose a deck of flashcards below that you want to study (or create your own).
+ <strong>Welcome to Manabi!</strong> First choose a deck below of flashcards that you want to study (or create your own).
</p>
{% endif %}
View
@@ -86,8 +86,6 @@
name='api-card'),
url(r'^cards_for_review/due_count/$', 'due_card_count',
name='api-due_card_count'),
- url(r'^cards_for_review/new_count/$', 'new_card_count',
- name='api-new_card_count'),
url(r'^cards_for_review/next_due_at/$', 'next_card_due_at',
name='api-next_card_due_at'),
url(r'^cards_for_review/hours_until_next_due/$', 'hours_until_next_card_due',
@@ -93,12 +93,6 @@ def due_card_count(request):
user = request.user
return Card.objects.common_filters(user).due(user).count()
-@api
-def new_card_count(request):
- user = request.user
- return Card.objects.common_filters(
- user, with_upstream=True).new(user).count()
-
@api
@has_card_query_filters
def hours_until_next_card_due(request, deck=None, tags=None):
@@ -34,7 +34,7 @@
UserResource, DeckResource, CardResource)
from catnap.exceptions import (HttpForbiddenException,
HttpTemporaryRedirectException)
-from catnap.auth import BasicAuthentication
+from catnap.auth import BasicAuthentication, DjangoContribAuthentication
from flashcards.contextprocessors import review_start_context
@@ -44,7 +44,8 @@ class ManabiRestView(JsonEmitterMixin, AutoContentTypeMixin, RestView):
'''
content_type_template_string = 'application/vnd.org.manabi.{0}+json'
- authenticator = BasicAuthentication(realm='manabi')
+ authenticators = (DjangoContribAuthentication(),
+ BasicAuthentication(realm='manabi'))
class CardQueryFiltersMixin(object):
@@ -48,7 +48,7 @@ def _overview_stat_counts(user, deck=None):
'total': cards.count(),
'young': cards.young(user).count(),
'mature': cards.mature(user).count(),
- 'new': cards.new(user).count(),
+ 'new': cards.new_count(user),
}
return context
@@ -737,13 +737,13 @@ ul.fact_form_tags {
/*background-color: #fffccb;*/
}
#lazy_user_landing_box .column.login_link {
- border-left: solid 5px lightgray;
+ border-left: solid 8px lightgray;
}
#lazy_user_landing_box .column, #lazy_user_landing_box {
height: 9.5em;
}
#lazy_user_landing_box .column {
- border-left: solid 5px #d21f00;
+ border-left: solid 8px #d21f00;
padding-left: 1em;
/*margin-left: .3em;*/
margin-right: 3em;

0 comments on commit edca6dd

Please sign in to comment.