diff --git a/ployst/celery.py b/ployst/celery.py index b760b90..58f9af8 100644 --- a/ployst/celery.py +++ b/ployst/celery.py @@ -7,7 +7,7 @@ # set the default Django settings module for the 'celery' program. os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'ployst.settings.dev') -from django.conf import settings +from django.conf import settings # noqa app = Celery('ployst') diff --git a/ployst/core/accounts/serializers.py b/ployst/core/accounts/serializers.py index f32088f..b52d98a 100644 --- a/ployst/core/accounts/serializers.py +++ b/ployst/core/accounts/serializers.py @@ -27,7 +27,8 @@ class Meta: class ProjectSerializer(serializers.ModelSerializer): - users = ProjectUserSerializer(source='projectuser_set', many=True) + users = ProjectUserSerializer(source='projectuser_set', many=True, + read_only=True) am_manager = serializers.SerializerMethodField('managed_by_me') extra_data = serializers.ReadOnlyField() diff --git a/ployst/github/github_client.py b/ployst/github/github_client.py index 6b42d56..8bfaba8 100644 --- a/ployst/github/github_client.py +++ b/ployst/github/github_client.py @@ -49,6 +49,13 @@ def org_repos(self, org): """ return list(org.iter_repos()) + def repo_issues(self, org, repo): + """ + Return all repos from the given organisation. + + """ + return list(self.gh.iter_repo_issues(org, repo)) + def create_hook(self, org, repo, url): """ Create a hook for the given org and repo. diff --git a/ployst/github/static/github/github-app.js b/ployst/github/static/github/github-app.js index df73b9d..90fa58d 100644 --- a/ployst/github/static/github/github-app.js +++ b/ployst/github/static/github/github-app.js @@ -23,6 +23,17 @@ angular.module('ployst.github', [ ); } ]) + .factory('github.RepoIssues', [ + '$resource', + function($resource) { + return $resource( + '/github/repo-issues/:org/:repo', { + org: '@org', + repo: '@repo' + } + ); + } + ]) .factory('github.Token', [ '$resource', function($resource) { @@ -153,4 +164,86 @@ angular.module('ployst.github', [ } }; } + ]) + .controller('GithubIssuesController', [ + '$scope', 'github.Token', 'Repos', 'github.RepoIssues', + + function($scope, GHToken, Repos, GHRepoIssues) + { + $scope.hasToken = null; + $scope.repos = null; + $scope.allIssues = []; + $scope.issues = []; + $scope.count = 0; + $scope.groupings = {}; + $scope.groupBy = null; + + var buildGroupings = function(repoIssues) { + angular.forEach(repoIssues, function(issue) { + angular.forEach(issue['labels'], function(label) { + if(label.name.indexOf(':') !== -1) { + var keyval = label.name.split(':'), + key = keyval[0], + val = keyval[1]; + if($scope.groupings[key] === undefined) { + $scope.groupings[key] = {}; + } + if($scope.groupings[key][val] === undefined) { + $scope.groupings[key][val] = []; + } + $scope.groupings[key][val].push(issue); + } + }); + }); + }; + + var loadData = function() { + $scope.issues = []; + Repos.query({project: $scope.project.id}, function(projectRepos) { + $scope.repos = projectRepos; + angular.forEach(projectRepos, function(repo) { + GHRepoIssues.query( + {org: repo.owner, repo: repo.name}, + function(repoIssues) { + $scope.issues = $scope.issues.concat(repoIssues); + buildGroupings(repoIssues); + $scope.allIssues = $scope.issues; + } + ); + }); + }); + }; + + $scope.setGroupBy = function(key) { + $scope.groupBy = key; + if(key === null) { + $scope.issues = $scope.allIssues; + } else { + $scope.issues = $scope.groupings[key]; + } + }; + + GHToken.query(function(token) { + if (token.length > 0) { + loadData(); + $scope.hasToken = true; + } else { + $scope.hasToken = false; + } + }); + } + ]) + .directive('githubIssues', [ + 'Django', + + function(Django) { + return { + controller: 'GithubIssuesController', + restrict: 'E', + templateUrl: Django.URL.STATIC + 'github/github-issues.html', + scope: { + project: '=' + } + }; + } ]); diff --git a/ployst/github/static/github/github-issues.html b/ployst/github/static/github/github-issues.html new file mode 100644 index 0000000..643d307 --- /dev/null +++ b/ployst/github/static/github/github-issues.html @@ -0,0 +1,65 @@ +

+ Loading... +

+ +
+

You still haven't authorised ployst to access your Github account.

+ Assimilate Github account +
+ + +
+
+

Filter: + +

+

Group by: + + + {{ key }} +   + + + (no groups) + +

+
+ + + +
+

Grouping by {{groupBy}}

+
+

{{value}}

+ +
+
+ +
diff --git a/ployst/github/urls.py b/ployst/github/urls.py index 52491e8..edc0c5d 100644 --- a/ployst/github/urls.py +++ b/ployst/github/urls.py @@ -23,4 +23,7 @@ url(r'^org-repos/(?P\w+)', github_data.OrganisationRepos.as_view(), name='org-repos'), + url(r'^repo-issues/(?P[-_\w]+)/(?P[-_\w]+)', + github_data.RepoIssues.as_view(), + name='repo-issues'), ) diff --git a/ployst/github/views/github_data.py b/ployst/github/views/github_data.py index f6c04b1..72df79f 100644 --- a/ployst/github/views/github_data.py +++ b/ployst/github/views/github_data.py @@ -56,3 +56,38 @@ def get_repos(self): org_name = self.kwargs['name'] org = self.gh.gh.organization(org_name) return self.gh.org_repos(org) + + +class RepoIssues(APIView): + """ + Retrieve all issues for a given repo. + + The organisation name is kwarg ``org`` in the URL pattern. + The repo name is kwarg ``repo`` in the URL pattern. + """ + keys = [ + 'number', 'title', 'html_url', 'labels', 'milestone', + # 'id', 'state', + ] + + def get(self, request, org, repo): + self.gh = GithubClient(request.user.id) + issues = self.gh.repo_issues(org, repo) + filtered_issues = [] + for issue in issues: + issue = restrict_keys(issue.to_json(), self.keys) + issue['owner'] = org + issue['repo'] = repo + issue['labels'] = [ + {'name': label['name'], 'color': label['color']} + for label in issue['labels'] + ] + # Add milestone as a label: + if 'milestone' in issue and issue['milestone']: + milestone = issue['milestone']['title'] + issue['labels'].append({ + 'name': 'milestone:{0}'.format(milestone), + 'color': '777777', + }) + filtered_issues.append(issue) + return Response(filtered_issues) diff --git a/ployst/templates/navbar.html b/ployst/templates/navbar.html index 3073925..0678b33 100644 --- a/ployst/templates/navbar.html +++ b/ployst/templates/navbar.html @@ -26,6 +26,9 @@
  • Profile
  • +
  • + Projects +
  • Logout diff --git a/ployst/ui/static/projects/ployst.projects.js b/ployst/ui/static/projects/ployst.projects.js index 28ccf94..bc89821 100644 --- a/ployst/ui/static/projects/ployst.projects.js +++ b/ployst/ui/static/projects/ployst.projects.js @@ -22,6 +22,12 @@ angular.module('ployst.projects', [ templateUrl: Django.URL.STATIC + 'projects/project-activity.html', menu: 'projects' }) + .state('projects.issues', { + url: '/issues', + parent: 'projects', + templateUrl: Django.URL.STATIC + 'projects/project-issues.html', + menu: 'projects' + }) .state('projects.repos', { url: '/repos', templateUrl: Django.URL.STATIC + 'projects/project-repos.html', diff --git a/ployst/ui/static/projects/project-issues.html b/ployst/ui/static/projects/project-issues.html new file mode 100644 index 0000000..b285fec --- /dev/null +++ b/ployst/ui/static/projects/project-issues.html @@ -0,0 +1 @@ + diff --git a/ployst/ui/static/projects/project.html b/ployst/ui/static/projects/project.html index 675e8b0..c62fe6d 100644 --- a/ployst/ui/static/projects/project.html +++ b/ployst/ui/static/projects/project.html @@ -10,11 +10,6 @@

    Project {{ ps.project.name }}