import datetime import json import re from django.http import HttpResponse from django.utils import timezone from django.views.decorators.csrf import csrf_exempt from django.views.generic.base import TemplateView from django.views.generic.detail import DetailView from .models import Project, InstalledService, Module, InstalledVersion from .utils import CommitAndIssues, decorate_commit_line class ProjectDetailView(DetailView): model = Project def get_context_data(self, **kwargs): context = super(ProjectDetailView, self).get_context_data(**kwargs) platforms = self.object.platform_set.all() services = self.object.service_set.all() context['platforms'] = platforms context['services'] = services return context class ModuleDiffView(TemplateView): template_name = 'projects/diff.html' def get_context_data(self, name, commit1, commit2, **kwargs): context = super(ModuleDiffView, self).get_context_data(**kwargs) context['module'] = Module.objects.get(name=name) context['commit1'] = commit1 context['commit2'] = commit2 context['difflog'] = '\n'.join( [decorate_commit_line(line) for line in \ context['module'].get_diff_log(commit1, commit2).splitlines()]) return context class ModuleIssuesView(TemplateView): template_name = 'projects/issues.html' def get_context_data(self, name, commit1, commit2, **kwargs): context = super(ModuleIssuesView, self).get_context_data(**kwargs) context['module'] = Module.objects.get(name=name) context['commit1'] = commit1 context['commit2'] = commit2 commits = CommitAndIssues.get_for_commits( context['module'], commit1, commit2) issues = {} for commit in commits: for issue in commit.issues: if not int(issue.id) in issues: issues[int(issue.id)] = issue else: issue = issues[int(issue.id)] issue.add_commit(commit) issues_list = list(issues.items()) issues_list.sort() context['issues'] = [x[1] for x in issues_list] return context class ProjectHistoryView(DetailView): model = Project template_name_suffix = '_history' def get_context_data(self, **kwargs): context = super(ProjectHistoryView, self).get_context_data(**kwargs) installed_versions = InstalledVersion.objects.filter( service__platform__project=self.object).order_by('-timestamp')[:1000] context['installed_versions'] = installed_versions return context class ProjectSummaryHistoryView(DetailView): model = Project template_name_suffix = '_summary_history' # XXX: add an 'interesting' attribute to module model? interesting_modules = [ 'publik-base-theme', 'combo', 'wcs', 'hobo', 'authentic2', 'welco', 'chrono', 'corbo', 'passerelle', 'fargo', ] def get_context_data(self, **kwargs): context = super(ProjectSummaryHistoryView, self).get_context_data(**kwargs) platforms = list(self.get_object().platform_set.all()) platform = platforms[-1] installed_versions = list(InstalledVersion.objects.filter( timestamp__gt=timezone.now() - datetime.timedelta(days=120), version__module__name__in=self.interesting_modules, service__platform=platform).exclude( version__version='').order_by('-timestamp')[:1000]) installed_versions.reverse() versions_and_day = {} for installed in installed_versions: installed_day = installed.timestamp.strftime('%Y-%m-%d') if not installed_day in versions_and_day: versions_and_day[installed_day] = { 'modules': {}, 'day': installed.timestamp.date() } if installed.version.module.name in versions_and_day[installed_day]['modules']: continue versions_and_day[installed_day]['modules'][installed.version.module.name] = { 'name': installed.version.module.name, 'current_version': installed.version.version, } versions_sorted_by_day = list(versions_and_day.values()) versions_sorted_by_day.sort(key=lambda x: x.get('day')) previous_versions = {} for version_and_day in versions_sorted_by_day: for module_name, module_versions in list(version_and_day['modules'].items()): if module_name in previous_versions: module_versions['previous_version'] = previous_versions[module_name] if module_versions['previous_version'] == module_versions['current_version']: del version_and_day['modules'][module_name] else: del version_and_day['modules'][module_name] previous_versions[module_name] = module_versions['current_version'] if len(platforms) > 1: validation_platform = platforms[-2] future_versions = { 'modules': {}, 'day': 'future' } module_names = previous_versions.keys() for module_name in module_names: try: installed_version = InstalledVersion.objects.filter( version__module__name=module_name, service__platform=validation_platform).exclude( version__version='').order_by('-timestamp')[0] except IndexError: continue if not installed_version.version.version: continue if installed_version.version.version == previous_versions[module_name]: continue future_versions['modules'][module_name] = { 'name': module_name, 'previous_version': previous_versions[module_name], 'current_version': installed_version.version.version, } if future_versions['modules']: versions_sorted_by_day.append(future_versions) context['platform'] = platform context['history'] = reversed(versions_sorted_by_day) return context class ModulesView(TemplateView): template_name = 'projects/modules.html' def get_context_data(self, **kwargs): context = super(ModulesView, self).get_context_data(**kwargs) context['modules'] = Module.objects.all().order_by('name') return context def try_int(x): try: return int(x) except ValueError: return 0 version_re = re.compile(r'[\.\+-]d?e?v?') def cmp_version(v1, v2): return cmp([try_int(x) for x in version_re.split(v1.version.version)], [try_int(x) for x in version_re.split(v2.version.version)]) class ModuleDeploymentsView(TemplateView): template_name = 'projects/deployments.html' def get_context_data(self, name, **kwargs): context = super(ModuleDeploymentsView, self).get_context_data(**kwargs) context['versions'] = [] context['module'] = Module.objects.get(name=name) module = context['module'] for service in InstalledService.objects.all(): version = module.get_installed_version(service.platform, service.service) if version and not version in context['versions']: if version.version.version: context['versions'].append(version) context['versions'].sort(lambda x, y: cmp_version(x, y)) return context def module_deployments_json(request, name, **kwargs): response = HttpResponse(content_type='application/json') installed_versions = [] module = Module.objects.get(name=name) for service in InstalledService.objects.all(): version = module.get_installed_version(service.platform, service.service) if version and not version in installed_versions: installed_versions.append(version) json.dump([{'version': x.version.version, 'project': x.service.platform.project.slug, 'service': x.service.service.slug, 'platform': x.service.platform.slug} for x in installed_versions], response) return response class IssuesSnippet(TemplateView): template_name = 'projects/issues_snippet.html' @csrf_exempt def dispatch(self, *args, **kwargs): return super(IssuesSnippet, self).dispatch(*args, **kwargs) def post(self, request, *args, **kwargs): return self.get(request, *args, **kwargs) def get_context_data(self, **kwargs): context = super(IssuesSnippet, self).get_context_data(**kwargs) modules = json.loads(self.request.read().decode('utf-8')) issues = {} for module_info in modules.values(): module = Module.objects.get(name=module_info['name']) if not module.repository_url: continue commits = CommitAndIssues.get_for_commits( module, str(module_info.get('previous_version')), str(module_info.get('current_version'))) for commit in commits: for issue in commit.issues: if issue.subject == '---': # private issue continue if not int(issue.id) in issues: issues[int(issue.id)] = issue else: issue = issues[int(issue.id)] if not hasattr(issues[int(issue.id)], 'modules'): issues[int(issue.id)].modules = {} issues[int(issue.id)].modules[module_info['name']] = True context['issues'] = list(issues.values()) context['issues'].sort(key=lambda x: x.closed_on) context['issues'].reverse() # most recent on top return context def api_issues_json(request, *args, **kwargs): response = HttpResponse(content_type='application/json') data = {} for module in Module.objects.all(): try: git_log = module.get_git_log() except OSError: continue git_log_hashes = [x[0][:7] for x in git_log] for line in git_log: if not unicode(line[1], 'utf-8', 'ignore').endswith('#%s)' % kwargs.get('issue')): continue commit_hash = line[0][:7] fix_index = git_log_hashes.index(commit_hash) data = {'platforms': {}} for service in InstalledService.objects.all(): installed_version = module.get_installed_version(service.platform, service.service) if not installed_version or not installed_version.version: continue version_number = installed_version.version.version if not version_number: continue service_name = '%s / %s / %s' % ( installed_version.service.platform.project.title, installed_version.service.platform.title, installed_version.service.service.title) version_hash = module.get_version_hash(version_number) version_index = git_log_hashes.index(version_hash) data['platforms'][service_name] = { 'version': version_number, 'status': 'ok' if version_index <= fix_index else 'nok' } else: continue break json_str = json.dumps(data, indent=2) for variable in ('jsonpCallback', 'callback'): if variable in request.GET: response = HttpResponse(content_type='application/json') json_str = '%s(%s);' % (request.GET[variable], json_str) break response.write(json_str) return response