2 from itertools
import count
3 from collections
import Counter
5 from django
.shortcuts
import render
6 from django
.contrib
import messages
7 from django
.core
.urlresolvers
import reverse
8 from django
.http
import HttpResponseRedirect
9 from django
.utils
.translation
import ugettext
as _
10 from django
.views
.generic
import TemplateView
11 from django
.utils
.decorators
import method_decorator
13 from mygpo
.admin
.auth
import require_staff
14 from mygpo
.admin
.group
import PodcastGrouper
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
.admin
.tasks
import merge_podcasts
19 from mygpo
.api
.httpresponse
import JsonResponse
20 from mygpo
.db
.couchdb
.episode
import episode_count
21 from mygpo
.db
.couchdb
.podcast
import podcast_count
, podcast_for_url
24 class InvalidPodcast(Exception):
25 """ raised when we try to merge a podcast that doesn't exist """
27 class AdminView(TemplateView
):
29 @method_decorator(require_staff
)
30 def dispatch(self
, *args
, **kwargs
):
31 return super(AdminView
, self
).dispatch(*args
, **kwargs
)
34 class Overview(AdminView
):
35 template_name
= 'admin/overview.html'
38 class MergeSelect(AdminView
):
39 template_name
= 'admin/merge-select.html'
41 def get(self
, request
):
42 num
= int(request
.GET
.get('podcasts', 2))
45 return self
.render_to_response({
50 class MergeBase(AdminView
):
52 def _get_podcasts(self
, request
):
55 podcast_url
= request
.POST
.get('feed%d' % n
, None)
56 if podcast_url
is None:
62 podcast
= podcast_for_url(podcast_url
)
65 raise InvalidPodcast(podcast_url
)
67 podcasts
.append(podcast_for_url(podcast_url
))
72 class MergeVerify(MergeBase
):
74 template_name
= 'admin/merge-grouping.html'
76 def post(self
, request
):
79 podcasts
= self
._get
_podcasts
(request
)
81 except InvalidPodcast
as ip
:
82 messages
.error(request
,
83 _('No podcast with URL {url}').format(url
=str(ip
)))
85 grouper
= PodcastGrouper(podcasts
)
87 get_features
= lambda (e_id
, e
): ((e
.url
, e
.title
), e_id
)
89 num_groups
= grouper
.group(get_features
)
91 return self
.render_to_response({
97 class MergeProcess(MergeBase
):
99 RE_EPISODE
= re
.compile(r
'episode_([0-9a-fA-F]{32})')
101 def post(self
, request
):
104 podcasts
= self
._get
_podcasts
(request
)
106 except InvalidPodcast
as ip
:
107 messages
.error(request
,
108 _('No podcast with URL {url}').format(url
=str(ip
)))
110 grouper
= PodcastGrouper(podcasts
)
113 for key
, feature
in request
.POST
.items():
114 m
= self
.RE_EPISODE
.match(key
)
116 episode_id
= m
.group(1)
117 features
[episode_id
] = feature
119 get_features
= lambda (e_id
, e
): (features
[e_id
], e_id
)
121 num_groups
= grouper
.group(get_features
)
123 if 'renew' in request
.POST
:
124 return render(request
, 'admin/merge-grouping.html', {
125 'podcasts': podcasts
,
126 'groups': num_groups
,
130 elif 'merge' in request
.POST
:
132 podcast_ids
= [p
.get_id() for p
in podcasts
]
133 num_groups
= list(num_groups
)
135 res
= merge_podcasts
.delay(podcast_ids
, num_groups
)
137 return HttpResponseRedirect(reverse('admin-merge-status',
141 class MergeStatus(AdminView
):
142 """ Displays the status of the merge operation """
144 template_name
= 'admin/merge-status.html'
146 def get(self
, request
, task_id
):
147 result
= merge_podcasts
.AsyncResult(task_id
)
149 if not result
.ready():
150 return self
.render_to_response({
156 actions
, podcast
= result
.get()
158 except IncorrectMergeException
as ime
:
159 messages
.error(request
, str(ime
))
160 return HttpResponseRedirect(reverse('admin-merge'))
162 return render(request
, 'admin/merge-status.html', {
164 'actions': actions
.items(),
170 class UserAgentStatsView(AdminView
):
171 template_name
= 'admin/useragents.html'
173 def get(self
, request
):
175 uas
= UserAgentStats()
176 useragents
= uas
.get_entries()
178 return self
.render_to_response({
179 'useragents': useragents
.most_common(),
180 'max_users': uas
.max_users
,
181 'total': uas
.total_users
,
185 class ClientStatsView(AdminView
):
186 template_name
= 'admin/clients.html'
188 def get(self
, request
):
191 clients
= cs
.get_entries()
193 return self
.render_to_response({
194 'clients': clients
.most_common(),
195 'max_users': cs
.max_users
,
196 'total': cs
.total_users
,
200 class ClientStatsJsonView(AdminView
):
201 def get(self
, request
):
204 clients
= cs
.get_entries()
206 return JsonResponse(map(self
.to_dict
, clients
.most_common()))
208 def to_dict(self
, res
):
211 if not isinstance(obj
, tuple):
214 return obj
._asdict
(), count
217 class StatsView(AdminView
):
218 """ shows general stats as HTML page """
220 template_name
= 'admin/stats.html'
222 def _get_stats(self
):
224 'podcasts': podcast_count(),
225 'episodes': episode_count(),
226 'users': User
.count(),
229 def get(self
, request
):
230 stats
= self
._get
_stats
()
231 return self
.render_to_response({
236 class StatsJsonView(StatsView
):
237 """ provides general stats as JSON """
239 def get(self
, request
):
240 stats
= self
._get
_stats
()
241 return JsonResponse(stats
)