simplify some @repeat_on_conflict decorated methods
[mygpo.git] / mygpo / admin / views.py
blob09247cd1d61615f7596f15b157ea6573e00140b7
1 import re
2 from itertools import count
4 from django.shortcuts import render
5 from django.contrib import messages
6 from django.core.urlresolvers import reverse
7 from django.http import HttpResponseRedirect
8 from django.utils.translation import ugettext as _
9 from django.views.generic import TemplateView
10 from django.utils.decorators import method_decorator
12 from mygpo.admin.auth import require_staff
13 from mygpo.admin.group import PodcastGrouper
14 from mygpo.counter import Counter
15 from mygpo.maintenance.merge import PodcastMerger, IncorrectMergeException
16 from mygpo.users.models import User
17 from mygpo.admin.clients import UserAgentStats, ClientStats
18 from mygpo.api.httpresponse import JsonResponse
19 from mygpo.db.couchdb.episode import episode_count
20 from mygpo.db.couchdb.podcast import podcast_count, podcast_for_url
23 class AdminView(TemplateView):
25 @method_decorator(require_staff)
26 def dispatch(self, *args, **kwargs):
27 return super(AdminView, self).dispatch(*args, **kwargs)
30 class Overview(AdminView):
31 template_name = 'admin/overview.html'
34 class MergeSelect(AdminView):
35 template_name = 'admin/merge-select.html'
37 def get(self, request):
38 num = int(request.GET.get('podcasts', 2))
39 urls = [''] * num
41 return self.render_to_response({
42 'urls': urls,
46 class MergeBase(AdminView):
48 def _get_podcasts(self, request):
49 podcasts = []
50 for n in count():
51 podcast_url = request.POST.get('feed%d' % n, None)
52 if podcast_url is None:
53 break
55 if not podcast_url:
56 continue
58 podcast = podcast_for_url(podcast_url)
60 if not podcast:
61 raise InvalidPodcast(podcast_url)
63 podcasts.append(podcast_for_url(podcast_url))
65 return podcasts
68 class MergeVerify(MergeBase):
70 template_name = 'admin/merge-grouping.html'
72 def post(self, request):
74 try:
75 podcasts = self._get_podcasts(request)
77 except InvalidPodcast as ip:
78 messages.error(request,
79 _('No podcast with URL {url}').format(url=str(ip)))
81 grouper = PodcastGrouper(podcasts)
83 get_features = lambda (e_id, e): ((e.url, e.title), e_id)
85 num_groups = grouper.group(get_features)
87 return self.render_to_response({
88 'podcasts': podcasts,
89 'groups': num_groups,
93 class MergeProcess(MergeBase):
95 RE_EPISODE = re.compile(r'episode_([0-9a-fA-F]{32})')
97 def post(self, request):
99 try:
100 podcasts = self._get_podcasts(request)
102 except InvalidPodcast as ip:
103 messages.error(request,
104 _('No podcast with URL {url}').format(url=str(ip)))
106 grouper = PodcastGrouper(podcasts)
108 features = {}
109 for key, feature in request.POST.items():
110 m = self.RE_EPISODE.match(key)
111 if m:
112 episode_id = m.group(1)
113 features[episode_id] = feature
115 get_features = lambda (e_id, e): (features[e_id], e_id)
117 num_groups = grouper.group(get_features)
119 if 'renew' in request.POST:
120 return render(request, 'admin/merge-grouping.html', {
121 'podcasts': podcasts,
122 'groups': num_groups,
126 elif 'merge' in request.POST:
128 actions = Counter()
130 try:
131 # merge podcast, reassign episodes
132 pm = PodcastMerger(podcasts, actions, num_groups)
133 pm.merge()
135 except IncorrectMergeException as ime:
136 messages.error(request, str(ime))
137 return HttpResponseRedirect(reverse('admin-merge'))
139 return render(request, 'admin/merge-finished.html', {
140 'actions': actions.items(),
141 'podcast': podcasts[0],
146 class UserAgentStatsView(AdminView):
147 template_name = 'admin/useragents.html'
149 def get(self, request):
151 uas = UserAgentStats()
152 useragents = uas.get_entries()
154 return self.render_to_response({
155 'useragents': useragents.most_common(),
156 'max_users': uas.max_users,
157 'total': uas.total_users,
161 class ClientStatsView(AdminView):
162 template_name = 'admin/clients.html'
164 def get(self, request):
166 cs = ClientStats()
167 clients = cs.get_entries()
169 return self.render_to_response({
170 'clients': clients.most_common(),
171 'max_users': cs.max_users,
172 'total': cs.total_users,
176 class ClientStatsJsonView(AdminView):
177 def get(self, request):
179 cs = ClientStats()
180 clients = cs.get_entries()
182 return JsonResponse(map(self.to_dict, clients.most_common()))
184 def to_dict(self, res):
185 obj, count = res
187 if not isinstance(obj, tuple):
188 return obj, count
190 return obj._asdict(), count
193 class StatsView(AdminView):
194 """ shows general stats as HTML page """
196 template_name = 'admin/stats.html'
198 def _get_stats(self):
199 return {
200 'podcasts': podcast_count(),
201 'episodes': episode_count(),
202 'users': User.count(),
205 def get(self, request):
206 stats = self._get_stats()
207 return self.render_to_response({
208 'stats': stats,
212 class StatsJsonView(StatsView):
213 """ provides general stats as JSON """
215 def get(self, request):
216 stats = self._get_stats()
217 return JsonResponse(stats)