コード例 #1
0
def demote_follower(request):
	resp, li, access = _list_access_from_post_pk(request, request.POST, need_edit = True)
	if resp: return resp
	try:
		access = ListAccess.objects.get(pk = int(request.POST['access_pk']))
	except KeyError:
		return notification(request, 'No access key found.')
	except ValueError:
		return notification(request, 'Access key "%s" is not a valid format found.' % request.POST['access_pk'])
	except ListAccess.DoesNotExist:
		return notification(request, 'Access not found for key %s.' % request.POST['access_pk'])
	if access.access == ListAccess.EDIT:
		if ListAccess.objects.filter(translations_list = li, access = ListAccess.EDIT).count() <= 1:
			return notification(request, 'You cannot remove the last editor from a list.')
		access.access = ListAccess.VIEW
		access.save()
		add_message(request, INFO, '"%s" was demoted to a follower of the list.' % access.learner)
	elif access.access == ListAccess.VIEW:
		if li.public:
			return notification(request, 'You cannot remove followers from a public list.')
		access.delete()
		add_message(request, INFO, '"%s" was removed from the list.' % access.learner)
	else:
		raise AssertionError('unknown access state')
	return redirect(request.POST['next'] or reverse('list_followers', kwargs = {'pk': li.pk, 'slug': li.slug}))
コード例 #2
0
def delete_phrase(request):
	try:
		phrase = Phrase.objects.get(pk = int(request.POST['pk']))
	except (KeyError, ValueError, Phrase.DoesNotExist):
		return notification(request, 'The phrase you were looking for was not found; the submitted data may be invalid.')
	if not (phrase.public_edit or phrase.learner == request.user):
		return notification(request, 'You don\'t have permission to delete this phrase.')
	phrase.delete()
	request.user.need_active_update = True
	request.user.save()
	return redirect(reverse('user_lists'))
コード例 #3
0
def remove_translation(request):
	resp, li, access = _list_access_from_post_pk(request, request.POST, need_edit = True)
	if resp: return resp
	try:
		translation = Translation.objects.get(pk = int(request.POST['trans_pk']))
	except KeyError:
		return notification(request, 'No translation key found.')
	except ValueError:
		return notification(request, 'Translation key "%s" is not a valid format found.' % request.POST['trans_pk'])
	except TranslationsList.DoesNotExist:
		return notification(request, 'Translation not found for key %s.' % request.POST['trans_pk'])
	li.translations.remove(translation)
	add_message(request, INFO, '"%s" was removed from the list.' % translation)
	return redirect(request.POST['next'] or li.get_absolute_url())
コード例 #4
0
def show_list(request, translations_list, slug = None):
	access_instance = None
	try:
		# learner = request.user should work here, but it doesn't, so use request.user.id as a kind of hack
		# http://stackoverflow.com/questions/15878860/int-argument-must-be-a-string-or-a-number-not-simplelazyobject
		access_instance = ListAccess.objects.get(translations_list = translations_list, learner = request.user.id)
	except ListAccess.DoesNotExist:
		if not translations_list.public:
			return notification(request, 'No access for list "%s".' % translations_list)
	translations = translations_list.translations.all()
	paginator = Paginator(translations, 50)
	page = request.GET.get('page', 1)
	try:
		items = paginator.page(page)
	except PageNotAnInteger:
		return redirect('%s?page=1' % request.path)
	except EmptyPage:
		return redirect('%s?page=%d' % (request.path, paginator.num_pages))
	return render(request, 'show_list.html', {
		'list': translations_list,
		'access': access_instance,
		'editable': access_instance.editable if access_instance else False,
		'items': items,
		'nearby_pages': _nearby_pages(items),
	})
コード例 #5
0
ファイル: views.py プロジェクト: mverleg/WW
def add_translation_vote(request):
    try:
        translation = Translation.objects.get(pk=int(request.POST['trans_pk']))
        votes = TranslationVote.objects.filter(learner=request.user,
                                               translation=translation)
        up = bool(int(request.POST['up']))
    except (KeyError, ValueError, Translation.DoesNotExist):
        return notification(
            request,
            message=
            'The submitted data was not valid - translation and/or vote type were specified wrongly or not at all.'
        )
    if votes:
        vote = votes[0]
        if vote.up == up:
            vote.delete()
            add_message(request, INFO,
                        'Your vote for "%s" was removed.' % (translation.text))
        else:
            vote.up = up
            vote.save()
            add_message(
                request, INFO,
                'Your vote for "%s" was changed from %s to %s.' %
                (translation.text, 'down' if up else 'up',
                 'up' if up else 'down'))
    else:
        vote = TranslationVote(translation=translation,
                               up=up,
                               learner=request.user)
        vote.save()
        add_message(request, INFO,
                    'Your vote for "%s" was added.' % (translation.text))
    return redirect(request.POST['next']
                    or translation.phrase.get_absolute_url())
コード例 #6
0
def delete_list(request):
	resp, li, access = _list_access_from_post_pk(request, request.POST, need_edit = True)
	if resp: return resp
	if ListAccess.objects.filter(translations_list = li, access = ListAccess.EDIT).count() > 1:
		return notification(request, 'There are other editors for this list. This means you cannot delete it. Unfollow it instead.')
	li.delete()
	return redirect(reverse('user_lists'))
コード例 #7
0
def study_list_ask(request, translations_list, slug):
	"""
		Study a single list, mostly for demonstration purposes (so no account is needed). Doesn't save results,
		doesn't store state and easy to cheat with.
	"""
	translations = list(translations_list.translations.all()[:500])
	shuffle(translations)
	for translation in translations:
		if translation.language == request.KNOWN_LANG:
			correct_lang_trans = translation.phrase.translations.filter(language = request.LEARN_LANG)
		elif translation.language == request.LEARN_LANG:
			correct_lang_trans = translation.phrase.translations.filter(language = request.KNOWN_LANG)
		else:
			continue
		""" Find a translation of this one that is in the correct langauge """
		if not correct_lang_trans:
			continue
		shown, hidden = translation, correct_lang_trans[0]
		if random() > 0.5:
			shown, hidden = hidden, shown
		form = AnonStudyForm(None, initial = {
			'shown': shown,
			'hidden': hidden,
		})
		return render(request, 'study_question.html', {
			'shown': shown,
			'hidden_language': hidden.language_disp(),
			'form': form,
			'list': translations_list,
		})
	return notification(request, 'The list seems to contain no pairs of phrases in the languages you know and study.')
コード例 #8
0
def study_demo(request):
	"""
		Redirect to a list to study (the first public one).
	"""
	lis = TranslationsList.objects.filter(public = True).order_by('pk')
	if not lis:
		return notification(request, 'There is no public list to study, sorry...')
	return redirect(reverse('study_list_ask', kwargs = {'pk': lis[0].pk, 'slug': lis[0].slug}))
コード例 #9
0
def unfollow_list(request):
	#todo: only confirm if it's not public
	resp, li, access = _list_access_from_post_pk(request, request.POST, need_access = True, need_edit = False)
	if resp: return resp
	if access.access == ListAccess.EDIT:
		return notification(request, 'You are an editor for this list, you cannot unfollow it. First go to the followers page and hand over editorship. Or delete the list if you\re sure it\'s of no use to anyone.')
	access.delete()
	return redirect(request.POST['next'] or reverse('all_lists'))
コード例 #10
0
def follow_list(request):
	resp, li, access = _list_access_from_post_pk(request, request.POST, need_access = False)
	if resp: return resp
	if access:
		return notification(request, 'You are already following the list "%s"' % li.name)
	ListAccess(access = ListAccess.VIEW, translations_list = li, learner = request.user).save()
	add_message(request, INFO, 'You are now following the list "%s".' % li)
	return redirect(request.POST['next'] or li.get_absolute_url())
コード例 #11
0
def create_translation(request):
	if not request.POST['language'].strip():
		add_message(request, ERROR, 'You need to provide the language for this phrase.')
		return redirect(request.POST['next'] or '/')
	form = CreateTranslationForm(request.POST)
	if form.is_valid():
		phrase = form.cleaned_data['phrase']
		if not (phrase.public_edit or phrase.learner == request.user):
			return notification(request, 'You don\'t have permission to add translations to this phrase.')
		if Translation.objects.filter(text = form.cleaned_data['text'], phrase = form.cleaned_data['phrase'], language = form.cleaned_data['language']):
			add_message(request, WARNING, 'This exact translation was already included and has been skipped.')
		else:
			add_message(request, INFO, 'Your translation "%s" has been added!' % form.cleaned_data['phrase'])
			form.save()
			request.user.need_active_update = True
			request.user.save()
		return redirect(request.POST['next'] or phrase.get_absolute_url())
	return notification(request, 'The submitted phrase was not valid, sorry. %s' % ' '.join('%s: %s' % (field, msg) for field, msg in list(form.errors.items())))
コード例 #12
0
def logout(request, next):
	if not request.method == 'POST':
		return redirect(to = reverse('home'))
	if not request.user.is_authenticated():
		return redirect(to = reverse('login'))
	form = LogoutForm(data = request.POST)
	if form.is_valid():
		auth_logout(request)
		add_message(request, INFO, 'You have been logged out. See you soon!')
		return redirect(to = request.POST['next'] or LOGIN_REDIRECT_URL)
	return notification(request, 'There was something wrong with the logout request. You have not been logged out.')
コード例 #13
0
def promote_follower(request):
	resp, li, access = _list_access_from_post_pk(request, request.POST, need_edit = True)
	if resp: return resp
	try:
		access = ListAccess.objects.get(pk = int(request.POST['access_pk']))
	except KeyError:
		return notification(request, 'No access key found.')
	except ValueError:
		return notification(request, 'Access key "%s" is not a valid format found.' % request.POST['access_pk'])
	except ListAccess.DoesNotExist:
		return notification(request, 'Access not found for key %s.' % request.POST['access_pk'])
	if access.access == ListAccess.EDIT:
		return notification(request, 'User %s already has all privileges.' % access.learner)
	elif access.access == ListAccess.VIEW:
		access.access = ListAccess.EDIT
		access.save()
	else:
		raise AssertionError('unknown access state')
	add_message(request, INFO, '"%s" was promoted to editor of the list.' % access.learner)
	return redirect(request.POST['next'] or reverse('list_followers', kwargs = {'pk': li.pk, 'slug': li.slug}))
コード例 #14
0
def edit_phrase(request, phrase, next = None):
	if not (phrase.public_edit or phrase.learner == request.user):
		return notification(request, 'You don\'t have permission to edit this phrase.')
	phrase_form = EditPhraseForm(request.POST or None, instance = phrase)
	if phrase_form.is_valid():
		phrase_form.save()
		""" No need for actives_update here, doesn't affect translations. """
		return redirect(request.POST['next'] or phrase.get_absolute_url())
	return render(request, 'edit_phrase.html', {
		'phrase': phrase,
		'phrase_form': phrase_form,
		'next': next,
	})
コード例 #15
0
def delete_translation(request):
	try:
		translation = Translation.objects.get(pk = int(request.POST['pk']))
	except (KeyError, ValueError, Translation.DoesNotExist):
		return notification(request, 'The translation you were looking for was not found; the submitted data may be invalid.')
	next = request.POST['next'] or translation.phrase.get_absolute_url()
	if translation.score >= 0 and not translation.phrase.learner == request.user:
		add_message(request, ERROR, 'You can only remove translations that have a negative vote score (unless you\'re the owner)')
	else:
		add_message(request, INFO, 'The translation has been deleted')
		translation.delete()
		request.user.need_active_update = True
		request.user.save()
	return redirect(next)
コード例 #16
0
def _list_access_from_post_pk(request, post, need_access = True, need_edit = True):
	"""
		:return: response, list, access (either the first or the other two are None)
	"""
	if not need_access: need_edit = False
	try:
		list_instance = TranslationsList.objects.get(pk = int(request.POST['pk']))
	except KeyError:
		return notification(request, 'No list key found.'), None, None
	except ValueError:
		return notification(request, 'List key "%s" is not a valid format found.' % request.POST['pk']), None, None
	except TranslationsList.DoesNotExist:
		return notification(request, 'List not found for key %s.' % request.POST['pk']), None, None
	try:
		access_instance = ListAccess.objects.get(translations_list = list_instance, learner = request.user)
	except ListAccess.DoesNotExist:
		if need_access:
			return notification(request, 'No access for list "%s".' % list_instance), None, None
		else:
			access_instance = None
	if need_edit:
		if not access_instance.access == ListAccess.EDIT:
			return notification(request, 'You don\'t have edit access for list %s.' % list_instance), None, None
	return None, list_instance, access_instance
コード例 #17
0
def edit_list(request, translations_list, slug = None, next = None):
	list_form = ListForm(request.POST or None, instance = translations_list)
	try:
		access_instance = ListAccess.objects.get(translations_list = translations_list, learner = request.user)
	except ListAccess.DoesNotExist:
		return notification(request, 'No access for list "%s".' % translations_list)
	access_form = ListAccessForm(request.POST or None, instance = access_instance)
	if access_instance.editable:
		if list_form.is_valid() and access_form.is_valid():
			list_form.save()
			access_form.save()
			return redirect(request.POST['next'] or translations_list.get_absolute_url())
	else:
		if list_form.is_valid() and access_form.is_valid():
			access_form.save()
			return redirect(request.POST['next'] or translations_list.get_absolute_url())
	return render(request, 'edit_list.html', {
		'list_form': list_form,
		'access_form': access_form,
		'add': False,
		'list': translations_list,
		'access': access_instance,
		'next': next,
	})
コード例 #18
0
ファイル: views.py プロジェクト: mverleg/WW
def import_hackingchinese_radicals(request):

	"""
		It would be much better to let this heavy work be done by a seperate process, one that is sufficiently
		detached to let Apache finish the request while the seperate process works. This would be much better
		for the user (now it loads a really long time) and performance (if a bunch of people upload files (more
		than Apache has worker processes) the server is unreachable until some are done. Implementing the better way
		would require not only a separate process (Celery?) but also some way to notify the user when done.
	""" #todo

	def parse(txt):
		data = []
		for line in txt.splitlines():
			if line:
				parts = line.split('\t')
				data.append((
					'{0} [radical]'.format(parts[0]),  # radical
					'{0}'.format(parts[4].strip(' ()')),  # pinyin
					'{0} [radical] e.g. {1} ; note: {2}'.format(parts[3], parts[5], parts[6]),  # definition
				))
		return data

	@transaction.atomic
	def make_list(data, learner, show_pinyin):
		if show_pinyin:
			li = TranslationsList(name = 'top 100 radicals (hackingchinese) show pinyin', public = True, language = CNY)
		else:
			li = TranslationsList(name = 'top 100 radicals (hackingchinese) hide pinyin', public = True, language = CNY)
		li.save()
		ListAccess(translations_list = li, learner = learner, access = ListAccess.EDIT).save()
		for radical, pinyin, definition in data:
			phrase = Phrase(learner = learner, public_edit = False)
			phrase.save()
			if show_pinyin:
				trans_cny = Translation(phrase = phrase, language = CNY, text = '%s %s' % (radical, pinyin))
				trans_en = Translation(phrase = phrase, language = EN, text = definition)
			else:
				trans_cny = Translation(phrase = phrase, language = CNY, text = '%s' % radical)
				trans_en = Translation(phrase = phrase, language = EN, text = '%s ; %s' % (pinyin, definition))
			trans_cny.save()
			trans_en.save()
			li.translations.add(trans_cny)
		return li

	form = ImportForm(request.POST or None, request.FILES or None)
	if form.is_valid():
		parse(form.get_content())
		try:
			data = parse(form.get_content())
		except Exception:
			return notification(request, 'Sorry, there was a problem parsing this file.')
		""" Make the first list, which shows Pinyin """
		if not len(data):
			return notification(request, 'No data found')
		list_show_pinyin = make_list(data = data, learner = request.user, show_pinyin = True)
		list_hide_pinyin = make_list(data = data, learner = request.user, show_pinyin = False)
		return notification(request, 'Succesfully imported %d phrases! See the lists with <a href="%s">visible</a> and <a href="%s">hidden</a> pinyin.' % (
			list_show_pinyin.translations.count(),
			reverse('show_list', kwargs = {'pk': list_show_pinyin.pk}),
			reverse('show_list', kwargs = {'pk': list_hide_pinyin.pk}),
		))
	return render(request, 'import_form.html', {
		'message': 'Import the top 100 most common radicals from <a href="http://www.hackingchinese.com/kickstart-your-character-learning-with-the-100-most-common-radicals/">hackingchinese.com</a>.',
		'form': form,
	})
コード例 #19
0
def study(request):
	#todo: show the last X results while studying (easy with Result)
	learner = request.user
	result_form = SolutionForm(request.POST)
	if learner.study_state == Learner.ASKING and 'solution' in request.POST:
		"""
			The user submitted a solution.
		"""
		if not result_form.is_valid():
			add_message(request, ERROR, 'Could not find or understand the answer, sorry. Sending back to question.')
			return redirect(reverse('study_ask'))
		learner.study_answer = result_form.cleaned_data['solution'].strip()
		if learner.study_answer == learner.study_hidden.text.strip() and not request.POST.get('idk', '').strip() == 'idk':
			#todo: also check other languages in the future maybe
			""" Update the score (so it can be set to 'verified') but only go on to next card when user click 'go on'. """
			update_score(learner, Result.CORRECT, verified = True)
			learner.study_state = Learner.JUDGED
		else:
			learner.study_state = Learner.REVEALED
			if request.POST.get('idk', '').strip() == 'idk':
				update_score(learner, Result.INCORRECT, verified = True)
				learner.study_state = Learner.JUDGED
		learner.save()
	if learner.study_state in [Learner.REVEALED, Learner.JUDGED] and 'result' in request.POST:
		"""
			The user judged the result, process it and go to the next question.
		"""
		result_map = {'correct': Result.CORRECT, 'notquite': Result.CLOSE, 'incorrect': Result.INCORRECT}
		try:
			result = result_map[request.POST['result']]
		except KeyError:
			return notification(request, 'The result you submitted, "%s", was not of expected format.' % request.POST['result'])
		if learner.study_state == Learner.REVEALED:
			update_score(learner, result)
		learner.study_shown = learner.study_hidden = None
		learner.study_answer = ''
		learner.phrase_index += 1
		learner.study_state = Learner.ASKING
		learner.save()
		""" Skip the judged page; set to asking and match later. """
	if learner.study_state in [Learner.REVEALED, Learner.JUDGED]:
		"""
			Show the solution.
		"""
		#correct = learner.study_answer == learner.study_hidden.text.strip()
		judge = not learner.study_state == Learner.JUDGED# else learner.study_state == Learner.REVEALED
		return render(request, 'study_result.html', {
			'hidden': learner.study_hidden,
			'shown': learner.study_shown,
			'correct': learner.study_answer == learner.study_hidden.text.strip(),
			'judge': judge,
			'answer': learner.study_answer,
			'result_form': result_form,
			'list': None,
		})
	if learner.study_state == Learner.NOTHING:
		learner.study_state = Learner.ASKING
		learner.save()
	if learner.study_state == Learner.ASKING:
		"""
			Since there's no solution in POST, the user just wants to see the question.
		"""
		msgs = []
		if not learner.study_shown or not learner.study_hidden:
			add_more_active_phrases(learner = learner, lang = request.LEARN_LANG, msgs = msgs)
			update_learner_actives(learner = learner)
			try:
				learner.study_active, learner.study_hidden, learner.study_shown, msgs = get_next_question(
					learner = learner, known_language = request.KNOWN_LANG, learn_language = request.LEARN_LANG)
			except ActiveTranslation.DoesNotExist:
				add_message(request, ERROR, 'There are no phrases on your lists which are available in both your known and study languages. Please select some.')
				return redirect(to = reverse('list_activities'))
			learner.save()
		for lvl, txt in msgs:
			add_message(request, lvl, txt)
		form = SolutionForm(None)
		active_lists = ListAccess.objects.filter(active = True, learner = request.user).order_by('-priority')
		return render(request, 'study_question.html', {
			'shown': learner.study_shown,
			'hidden_language': learner.study_hidden.language_disp(),
			'form': form,
			'list': None,
			'active_lists': active_lists,
		})
	raise Exception('nothing matched')
コード例 #20
0
ファイル: views.py プロジェクト: mverleg/WW
def delete_translation_comment(request):
    return notification(request, 'Not implemented')
コード例 #21
0
def import_hackingchinese_radicals(request):

    """
		It would be much better to let this heavy work be done by a seperate process, one that is sufficiently
		detached to let Apache finish the request while the seperate process works. This would be much better
		for the user (now it loads a really long time) and performance (if a bunch of people upload files (more
		than Apache has worker processes) the server is unreachable until some are done. Implementing the better way
		would require not only a separate process (Celery?) but also some way to notify the user when done.
	""" #todo

    def parse(txt):
        data = []
        for line in txt.splitlines():
            if line:
                parts = line.split('\t')
                data.append((
                    '{0} [radical]'.format(parts[0]),  # radical
                    '{0}'.format(parts[4].strip(' ()')),  # pinyin
                    '{0} [radical] e.g. {1} ; note: {2}'.format(
                        parts[3], parts[5], parts[6]),  # definition
                ))
        return data

    @transaction.atomic
    def make_list(data, learner, show_pinyin):
        if show_pinyin:
            li = TranslationsList(
                name='top 100 radicals (hackingchinese) show pinyin',
                public=True,
                language=CNY)
        else:
            li = TranslationsList(
                name='top 100 radicals (hackingchinese) hide pinyin',
                public=True,
                language=CNY)
        li.save()
        ListAccess(translations_list=li,
                   learner=learner,
                   access=ListAccess.EDIT).save()
        for radical, pinyin, definition in data:
            phrase = Phrase(learner=learner, public_edit=False)
            phrase.save()
            if show_pinyin:
                trans_cny = Translation(phrase=phrase,
                                        language=CNY,
                                        text='%s %s' % (radical, pinyin))
                trans_en = Translation(phrase=phrase,
                                       language=EN,
                                       text=definition)
            else:
                trans_cny = Translation(phrase=phrase,
                                        language=CNY,
                                        text='%s' % radical)
                trans_en = Translation(phrase=phrase,
                                       language=EN,
                                       text='%s ; %s' % (pinyin, definition))
            trans_cny.save()
            trans_en.save()
            li.translations.add(trans_cny)
        return li

    form = ImportForm(request.POST or None, request.FILES or None)
    if form.is_valid():
        parse(form.get_content())
        try:
            data = parse(form.get_content())
        except Exception:
            return notification(
                request, 'Sorry, there was a problem parsing this file.')
        """ Make the first list, which shows Pinyin """
        if not len(data):
            return notification(request, 'No data found')
        list_show_pinyin = make_list(data=data,
                                     learner=request.user,
                                     show_pinyin=True)
        list_hide_pinyin = make_list(data=data,
                                     learner=request.user,
                                     show_pinyin=False)
        return notification(
            request,
            'Succesfully imported %d phrases! See the lists with <a href="%s">visible</a> and <a href="%s">hidden</a> pinyin.'
            % (
                list_show_pinyin.translations.count(),
                reverse('show_list', kwargs={'pk': list_show_pinyin.pk}),
                reverse('show_list', kwargs={'pk': list_hide_pinyin.pk}),
            ))
    return render(
        request, 'import_form.html', {
            'message':
            'Import the top 100 most common radicals from <a href="http://www.hackingchinese.com/kickstart-your-character-learning-with-the-100-most-common-radicals/">hackingchinese.com</a>.',
            'form': form,
        })