diff --git a/pagure/lib/__init__.py b/pagure/lib/__init__.py index 22d974b..3781858 100644 --- a/pagure/lib/__init__.py +++ b/pagure/lib/__init__.py @@ -2368,6 +2368,233 @@ def search_projects( return query.all() +def list_users_projects( + session, username, + fork=None, tags=None, namespace=None, pattern=None, + start=None, limit=None, count=False, sort=None, + exclude_groups=None, private=None, acls=None): + '''List a users projects + ''' + projects = session.query( + sqlalchemy.distinct(model.Project.id) + ) + + if acls is None: + acls = ['main admin', 'admin', 'commit', 'ticket'] + + if username is not None: + + projects = projects.filter( + # User created the project + sqlalchemy.and_( + model.User.user == username, + model.User.id == model.Project.user_id, + ) + ) + if 'main admin' not in acls: + projects = projects.filter( + model.User.id != model.Project.user_id, + ) + + sub_q2 = session.query( + model.Project.id + ).filter( + # User got admin or commit right + sqlalchemy.and_( + model.User.user == username, + model.User.id == model.ProjectUser.user_id, + model.ProjectUser.project_id == model.Project.id, + model.ProjectUser.access.in_(acls) + ) + ) + sub_q3 = session.query( + model.Project.id + ).filter( + # User created a group that has admin or commit right + sqlalchemy.and_( + model.User.user == username, + model.PagureGroup.user_id == model.User.id, + model.PagureGroup.group_type == 'user', + model.PagureGroup.id == model.ProjectGroup.group_id, + model.Project.id == model.ProjectGroup.project_id, + model.ProjectGroup.access.in_(acls) + ) + ) + sub_q4 = session.query( + model.Project.id + ).filter( + # User is part of a group that has admin or commit right + sqlalchemy.and_( + model.User.user == username, + model.PagureUserGroup.user_id == model.User.id, + model.PagureUserGroup.group_id == model.PagureGroup.id, + model.PagureGroup.group_type == 'user', + model.PagureGroup.id == model.ProjectGroup.group_id, + model.Project.id == model.ProjectGroup.project_id, + model.ProjectGroup.access.in_(acls) + ) + ) + + # Exclude projects that the user has accessed via a group that we + # do not want to include + if exclude_groups: + sub_q3 = sub_q3.filter( + model.PagureGroup.group_name.notin_(exclude_groups) + ) + sub_q4 = sub_q4.filter( + model.PagureGroup.group_name.notin_(exclude_groups) + ) + + projects = projects.union(sub_q2).union(sub_q3).union(sub_q4) + + if not private: + projects = projects.filter( + model.Project.private == False # noqa: E712 + ) + # No filtering is done if private == username i.e if the owner of the + # project is viewing the project + elif isinstance(private, six.string_types) and private != username: + # All the public repo + subquery0 = session.query( + sqlalchemy.distinct(model.Project.id) + ).filter( + model.Project.private == False, # noqa: E712 + ) + sub_q1 = session.query( + sqlalchemy.distinct(model.Project.id) + ).filter( + sqlalchemy.and_( + model.Project.private == True, # noqa: E712 + model.User.id == model.Project.user_id, + model.User.user == private, + ) + ) + sub_q2 = session.query( + model.Project.id + ).filter( + # User got admin or commit right + sqlalchemy.and_( + model.Project.private == True, # noqa: E712 + model.User.user == private, + model.User.id == model.ProjectUser.user_id, + model.ProjectUser.project_id == model.Project.id, + model.ProjectUser.access.in_(acls) + ) + ) + sub_q3 = session.query( + model.Project.id + ).filter( + # User created a group that has admin or commit right + sqlalchemy.and_( + model.Project.private == True, # noqa: E712 + model.User.user == private, + model.PagureGroup.user_id == model.User.id, + model.PagureGroup.group_type == 'user', + model.PagureGroup.id == model.ProjectGroup.group_id, + model.Project.id == model.ProjectGroup.project_id, + model.ProjectGroup.access.in_(acls) + ) + ) + sub_q4 = session.query( + model.Project.id + ).filter( + # User is part of a group that has admin or commit right + sqlalchemy.and_( + model.Project.private == True, # noqa: E712 + model.User.user == private, + model.PagureUserGroup.user_id == model.User.id, + model.PagureUserGroup.group_id == model.PagureGroup.id, + model.PagureGroup.group_type == 'user', + model.PagureGroup.id == model.ProjectGroup.group_id, + model.Project.id == model.ProjectGroup.project_id, + model.ProjectGroup.access.in_(acls) + ) + ) + + # Exclude projects that the user has accessed via a group that we + # do not want to include + if exclude_groups: + sub_q3 = sub_q3.filter( + model.PagureGroup.group_name.notin_(exclude_groups) + ) + sub_q4 = sub_q4.filter( + model.PagureGroup.group_name.notin_(exclude_groups) + ) + + projects = projects.filter( + model.Project.id.in_( + subquery0.union(sub_q1).union(sub_q2).union(sub_q3).union( + sub_q4) + ) + ) + + if fork is not None: + if fork is True: + projects = projects.filter( + model.Project.is_fork == True # noqa: E712 + ) + elif fork is False: + projects = projects.filter( + model.Project.is_fork == False # noqa: E712 + ) + + if tags: + if not isinstance(tags, (list, tuple)): + tags = [tags] + + projects = projects.filter( + model.Project.id == model.TagProject.project_id + ).filter( + model.TagProject.tag.in_(tags) + ) + + if pattern: + pattern = pattern.replace('*', '%') + if '%' in pattern: + projects = projects.filter( + model.Project.name.ilike(pattern) + ) + else: + projects = projects.filter( + model.Project.name == pattern + ) + + if namespace: + projects = projects.filter( + model.Project.namespace == namespace + ) + + query = session.query( + model.Project + ).filter( + model.Project.id.in_(projects.subquery()) + ) + + if sort == 'latest': + query = query.order_by( + model.Project.date_created.desc() + ) + elif sort == 'oldest': + query = query.order_by( + model.Project.date_created.asc() + ) + else: + query = query.order_by( + asc(func.lower(model.Project.name)) + ) + + if start is not None: + query = query.offset(start) + + if limit is not None: + query = query.limit(limit) + + if count: + return query.count() + else: + return query.all() + + def _get_project(session, name, user=None, namespace=None): '''Get a project from the database ''' @@ -4630,6 +4857,28 @@ def get_user_activity_day(session, user, date, tz='UTC'): return [ev for ev in events if ev.date_tz(tz) == dt.date()] +def get_watchlist_messages(session, user, limit=None): + + watched = user_watch_list(session, user.username) + + watched_list = [watch.id for watch in watched] + + events = session.query( + model.PagureLog + ).filter( + model.PagureLog.project_id.in_(watched_list) + ).order_by( + model.PagureLog.id.desc() + ) + + if limit is not None: + events = events.limit(limit) + + events = events.all() + + return events + + def log_action(session, action, obj, user_obj): ''' Log an user action on a project/issue/PR. ''' project_id = None diff --git a/pagure/static/pagure.css b/pagure/static/pagure.css index bc7b24b..6c8b396 100644 --- a/pagure/static/pagure.css +++ b/pagure/static/pagure.css @@ -3,6 +3,10 @@ html font-size:14px; } +body{ + background-color:transparent; +} + .container{ max-width: 1100px!important; } @@ -127,7 +131,8 @@ z-index:1; } -#headerSearch .selectize-control.single .selectize-input::after +#headerSearch .selectize-control.single .selectize-input::after, +#userdash_searchform .selectize-control.single .selectize-input::after { content: "\f002"; font-family: "FontAwesome"; @@ -471,6 +476,10 @@ a.nav-link.btn{ color:#555!important; } +.text-ccc{ + color: #ccc!important; +} + .font-size-09{ font-size:0.9em; } @@ -541,4 +550,10 @@ a.nav-link.btn{ .hljs { padding: 0!important; background: #fff; + +.userdash-tabs .nav-sidetabs{ + background: #f3f3f3; + box-shadow: -2000px 0 0 2000px #f3f3f3; + position: relative; + z-index: 1; } diff --git a/pagure/templates/_render_issues.html b/pagure/templates/_render_issues.html index 49d7e3f..1b431bd 100644 --- a/pagure/templates/_render_issues.html +++ b/pagure/templates/_render_issues.html @@ -1,4 +1,4 @@ -{% macro render_issue_row(issue, repo, username) %} +{% macro render_issue_row(issue, repo, username, subtitle=True) %} {% if issue.status == 'Open' %} {% set status_color = "success" %} {% else %} @@ -24,6 +24,7 @@ {% endif %} + {% if subtitle %}
Opened {% if issue.priority is not none %} diff --git a/pagure/templates/_render_pullrequests.html b/pagure/templates/_render_pullrequests.html index 483f755..63baa79 100644 --- a/pagure/templates/_render_pullrequests.html +++ b/pagure/templates/_render_pullrequests.html @@ -1,4 +1,4 @@ -{% macro render_pullrequest_row(request, repo, username) %} +{% macro render_pullrequest_row(request, repo, username, subtitle=True) %} {% if request.status|lower == 'open' %} {% set status_color = "success" %} {% elif request.status|lower == 'merged' %} @@ -17,7 +17,7 @@ {{request.title}} @@ -25,6 +25,7 @@
+ {% if subtitle %}
{% if request.status|lower == 'merged'%} @@ -63,6 +64,7 @@ {% endif %}
+ {% endif %}
{% for tag in request.tags %} -
-
Activity
-
+
+
-{% endblock %} diff --git a/pagure/templates/master.html b/pagure/templates/master.html index 3c16f2c..9866694 100644 --- a/pagure/templates/master.html +++ b/pagure/templates/master.html @@ -107,7 +107,7 @@
-
+
{% with messages = get_flashed_messages(with_categories=true) %} {% if messages %} diff --git a/pagure/templates/userdash_activity.html b/pagure/templates/userdash_activity.html new file mode 100644 index 0000000..901c8b7 --- /dev/null +++ b/pagure/templates/userdash_activity.html @@ -0,0 +1,177 @@ +{% extends "userdash_master.html" %} + +{% block title %}Home{% endblock %} +{% set tag = "projects" %} +{% from "_browseheader.html" import browse_header %} +{% from "_render_repo.html" import pagination_link %} + + +{% from "_render_repo.html" import render_repos_as_card, render_activity_graph %} +{% from "_render_issues.html" import render_issue_row %} +{% from "_render_pullrequests.html" import render_pullrequest_row %} + + +{% block userdash %} +
+
+
+
+
+

My Projects

+ {{ userdash_counts['repos_length'] }} projects +
+
+
+
+
+ {{ render_activity_graph(username) }} +
+
+ {% macro render_reponame(repo) %} +
+ {% if repo.is_fork %}{{ repo.user.user }}/{% endif %}{% if repo.namespace %}{{ repo.namespace }}{% endif %}{{ repo.name }} + + {% endmacro %} + +
+
+
+ {% for log in messages%} +
+
+
+ {{ log.user.username | avatar(26) | safe }} + {% if log.issue %} + + {% elif log.pull_request %} + + {% elif not log.pull_request and not log.issue and log.log_type == 'created'%} + + {% elif self.log_type == 'committed' %} + + {% else %} + + {% endif%} +
+
+ {% if log.issue %} + {% set verb = { + 'created': 'opened', + 'commented': 'commented on', + 'closed': 'closed', + 'open': 'reopened', + } %} +
+
+ {{log.user.username if log.user.username != username else "you"}} + {{verb[log.log_type]}} + issue #{{log.issue.id}} + in + {{render_reponame(log.project)}} +
+
+ {{log.date_created|humanize}} +
+
+
+ {{render_issue_row(log.issue, log.project, log.user.username, subtitle=False)}} +
+ {% elif log.pull_request %} + {% set verb = { + 'created': 'opened', + 'commented': 'commented on', + 'closed': 'closed', + 'merged': 'merged' + } %} +
+
+ {{log.user.username if log.user.username != username else "you"}} + {{verb[log.log_type]}} + PR #{{log.pull_request.id}} + in + {{render_reponame(log.project)}} +
+
+ {{log.date_created|humanize}} +
+
+
+ {{render_pullrequest_row(log.pull_request, log.project, log.user.username, subtitle=False)}} +
+ {% elif not log.pull_request and not log.issue and log.log_type == 'created'%} +
+
+ {{log.user.username if log.user.username != username else "you"}} + created + {{render_reponame(log.project)}} +
+
+ {{log.date_created|humanize}} +
+
+ {% elif self.log_type == 'committed' %} + {{log}} + {% else %} + {{log}} + {% endif%} +
+
+
+ {% else %} +
+ no messages +
+ {% endfor %} +
+
+
+
+
+{% endblock %} + +{% block jscripts %} + {{ super() }} + +{% endblock %} diff --git a/pagure/templates/userdash_forks.html b/pagure/templates/userdash_forks.html new file mode 100644 index 0000000..b387783 --- /dev/null +++ b/pagure/templates/userdash_forks.html @@ -0,0 +1,107 @@ +{% extends "userdash_master.html" %} + +{% block title %}Home{% endblock %} +{% set tag = "projects" %} +{% from "_browseheader.html" import browse_header %} +{% from "_render_repo.html" import pagination_link %} + + +{% from "_render_repo.html" import render_repos_as_card %} + +{% block userdash %} +
+
+
+
+
+

My Forks

+ {{ userdash_counts['forks_length'] }} forks +
+
+
+
+
+ {% if forks %} +
+ {% for fork in forks %} +
+ {% set url = url_for( + 'ui_ns.view_repo', + repo=fork.name, + username=fork.user.username if fork.is_fork else None, + namespace=fork.namespace) %} + + + + {{fork.user.username}} / {{ fork.namespace + '/' if fork.namespace }}{{ fork.name }} + +
+ {% if fork.parent %} + forked from + + {{ fork.parent.namespace + '/' if fork.parent.namespace + }}{{fork.parent.name}} + + {% else %} + forked from a deleted repository + {% endif %} + {% if fork.settings.get('issue_tracker', True) %} + {% if fork.open_tickets_public == 0 %} + + + {{- fork.open_tickets_public }} + + {% else %} + + + {{- fork.open_tickets_public }} + + {% endif %} + {% endif %} + {% if fork.settings.get('pull_requests', True) %} + {% if fork.open_requests == 0 %} + + + {{- fork.open_requests}} + + {% else %} + + + {{- fork.open_requests}} + + {% endif %} + {% endif %} +
+
+ {% endfor %} + {% if repos_length and repos_length > 1 %} + {{ pagination_link('forkpage', forkpage, total_fork_page, repopage=repopage) }} + {% endif %} +
+ {% else %} +
+

You have no forks

+
+ {% endif %} + +
+
+
+
+{% endblock %} + +{% block jscripts %} + {{ super() }} +{% endblock %} diff --git a/pagure/templates/userdash_groups.html b/pagure/templates/userdash_groups.html new file mode 100644 index 0000000..8907587 --- /dev/null +++ b/pagure/templates/userdash_groups.html @@ -0,0 +1,58 @@ +{% extends "userdash_master.html" %} + +{% block title %}Home{% endblock %} +{% set tag = "projects" %} +{% from "_browseheader.html" import browse_header %} +{% from "_render_repo.html" import pagination_link %} + + +{% from "_render_repo.html" import render_repos_as_card %} + +{% block userdash %} +
+
+
+
+
+

My Groups

+ {{ userdash_counts['groups_length'] }} groups +
+
+
+
+
+
+ {% if groups %} +
+ {% for group in groups %} + + {% endfor %} +
+ {% endif %} +
+
+
+
+
+{% endblock %} + +{% block jscripts %} + {{ super() }} +{% endblock %} diff --git a/pagure/templates/userdash_master.html b/pagure/templates/userdash_master.html new file mode 100644 index 0000000..088cae0 --- /dev/null +++ b/pagure/templates/userdash_master.html @@ -0,0 +1,157 @@ +{% extends "master.html" %} + +{% block title %}{{ + repo.namespace + '/' if repo.namespace }}{{ repo.name }}{% endblock %} +{% set tag = "home" %} + +{% block header %} + +{% endblock %} + +{% block content %} +
+
+
+ +
+ +
+ {% block userdash %} + {% endblock %} +
+
+
+{% endblock %} + +{% block jscripts %} +{{ super() }} + + + +{% endblock %} diff --git a/pagure/templates/userdash_projects.html b/pagure/templates/userdash_projects.html new file mode 100644 index 0000000..1a420e7 --- /dev/null +++ b/pagure/templates/userdash_projects.html @@ -0,0 +1,351 @@ +{% extends "userdash_master.html" %} + +{% block title %}Home{% endblock %} +{% set tag = "projects" %} +{% from "_browseheader.html" import browse_header %} +{% from "_render_repo.html" import pagination_link %} + + +{% from "_render_repo.html" import render_repos_as_card %} + +{% block userdash %} +
+
+
+
+
+

My Projects

+ {{ userdash_counts['repos_length'] }} projects +
+
+
+
+
+ + +
+ +
+
+
+ + {{filtered_repos_count}} Projects + + +
+ + +
+
+
+
+ + + + + + + {% if repo_list %} + {% for r in repo_list %} + {% set repo = r["repo"]%} +
+
+
+ {% if repo.avatar_email %} +   + {% else %} + + {% endif %} + + {{ repo.namespace + '/' if repo.namespace }}{{ repo.name }} + +
+ {% if repo.private %} + + {% endif %} + {% if r['grouplist']%} + + + {% for group in r["grouplist"]%} + {{group["group_name"]}} ({{group["access"]}}) + {% endfor %} + + {% endif %} + {% if r["access"] %} + + {{r["access"] if r["access"] != "main admin" else "owner"}} + + {% endif %} + {#
+ {% for fork in repo.forks %} + {% if fork.user.user == g.fas_user.username %} + + + + + {% endif %} + {% endfor %} +
#} +
+ + {% if config.get('ENABLE_TICKETS', True) and repo.settings.get('issue_tracker', True) %} + + + {{- repo.open_tickets_public }} + + {% endif %} + + + + {{- repo.open_requests}} + +
+ +
+
+ {% endfor %} + {% if total_repo_page > 1 %} + {{ pagination_link('repopage', repopage, total_repo_page, forkpage=forkpage) }} + {% endif %} + + {% else %} + {% if userdash_counts['repos_length'] == 0 %} +
+
You have no projects
+
+ {% if config.get('ENABLE_NEW_PROJECTS', True) and + config.get('ENABLE_UI_NEW_PROJECTS', True) %} + + Create a Project + + {% endif %} +
+
+ {% else %} +
+
No Projects match this filter
+
+ {% endif %} + {% endif %} +
+
+
+
+
+{% endblock %} + +{% block jscripts %} + {{ super() }} + +{% endblock %} diff --git a/pagure/templates/userdash_template.html b/pagure/templates/userdash_template.html new file mode 100644 index 0000000..f00229e --- /dev/null +++ b/pagure/templates/userdash_template.html @@ -0,0 +1,286 @@ +{% extends "userdash_master.html" %} + +{% block title %}Home{% endblock %} +{% set tag = "projects" %} +{% from "_browseheader.html" import browse_header %} +{% from "_render_repo.html" import pagination_link %} + + +{% block header %} + +{% endblock %} + + +{% from "_render_repo.html" import render_repos_as_card, render_activity_graph %} + +{% block userdash %} +
+
+
+
+ + {{ render_activity_graph(username) }} + +
+
+ My Projects {{ repos_length }} + {% if config.get('ENABLE_NEW_PROJECTS', True) and + config.get('ENABLE_UI_NEW_PROJECTS', True) and repos %} + + + + + + {% endif %} +
+ {% if repos %} +
+ {% for repo in repos %} +
+ {% set url = url_for( + 'ui_ns.view_repo', + repo=repo.name, + username=repo.user.username if repo.is_fork else None, + namespace=repo.namespace) %} + + {% if repo.avatar_email %} +   + {% else %} + + {% endif %} + {{ repo.namespace + '/' if repo.namespace }}{{ repo.name }} + + {% if repo.private %} + + {% endif %} +
+ {% if config.get('ENABLE_TICKETS', True) and repo.settings.get('issue_tracker', True) %} + {% if repo.open_tickets_public == 0 %} + + + {{- repo.open_tickets_public }} + + {% else %} + + + {{- repo.open_tickets_public }} + + {% endif %} + {% endif %} + + {% if repo.open_requests == 0 %} + + + {{- repo.open_requests}} + + {% else %} + + + {{- repo.open_requests}} + + {% endif %} + +
+
+ {% endfor %} + {% if repos_length and repos_length > 1 %} + {{ pagination_link('repopage', repopage, total_repo_page, forkpage=forkpage) }} + {% endif %} +
+ {% else %} +
+
You have no projects
+
+ {% if config.get('ENABLE_NEW_PROJECTS', True) and + config.get('ENABLE_UI_NEW_PROJECTS', True) %} + + Create a Project + + {% endif %} +
+
+ {% endif %} +
+ +
+
+ My Forks {{ forks_length }} +
+ {% if forks %} +
+ {% for fork in forks %} +
+ {% set url = url_for( + 'ui_ns.view_repo', + repo=fork.name, + username=fork.user.username if fork.is_fork else None, + namespace=fork.namespace) %} + + + + {{fork.user.username}}/{{ fork.namespace + '/' if fork.namespace }}{{ fork.name }} + +
+ {% if fork.parent %} + forked from + + {{ fork.parent.namespace + '/' if fork.parent.namespace + }}{{fork.parent.name}} + + {% else %} + forked from a deleted repository + {% endif %} + {% if fork.settings.get('issue_tracker', True) %} + {% if fork.open_tickets_public == 0 %} + + + {{- fork.open_tickets_public }} + + {% else %} + + + {{- fork.open_tickets_public }} + + {% endif %} + {% endif %} + {% if fork.settings.get('pull_requests', True) %} + {% if fork.open_requests == 0 %} + + + {{- fork.open_requests}} + + {% else %} + + + {{- fork.open_requests}} + + {% endif %} + {% endif %} +
+
+ {% endfor %} + {% if repos_length and repos_length > 1 %} + {{ pagination_link('forkpage', forkpage, total_fork_page, repopage=repopage) }} + {% endif %} +
+ {% else %} +
+

You have no forks

+
+ {% endif %} +
+ +
+
+
+
+ My Groups {{ user.groups }} + + {% if config.get('ENABLE_GROUP_MNGT') %} + + + + {% endif %} + +
+ {% for group in user.groups %} + + {% else %} +
+

No group found

+
+ {% endfor %} +
+
+
+ My Watch List {{ watch_list | count }} +
+ {% for repo in watch_list %} + + {% else %} +
+

No project in watch list

+
+ {% endfor %} +
+
+
+
+
+{% endblock %} + +{% block jscripts %} + {{ super() }} + +{% endblock %} diff --git a/pagure/templates/userdash_watchlist.html b/pagure/templates/userdash_watchlist.html new file mode 100644 index 0000000..139dfda --- /dev/null +++ b/pagure/templates/userdash_watchlist.html @@ -0,0 +1,67 @@ +{% extends "userdash_master.html" %} + +{% block title %}Home{% endblock %} +{% set tag = "projects" %} +{% from "_browseheader.html" import browse_header %} +{% from "_render_repo.html" import pagination_link %} + + +{% from "_render_repo.html" import render_repos_as_card %} + +{% block userdash %} +
+
+
+
+
+

My Watchlist

+ {{ userdash_counts['watchlist_length'] }} projects & forks +
+
+
+
+
+ {% for repo in watch_list %} + {% if repo.is_fork %} + +
+ + +  {{ repo.user.username }}/{{ + repo.namespace + '/' if repo.namespace + }}{{ repo.name }} + +
+
+ {% else %} + +
+ + +  {{ repo.namespace + '/' if repo.namespace + }}{{ repo.name }} + +
+
+ {% endif %} + {% else %} +
+

No project in watch list

+
+ {% endfor %} +
+ +
+
+
+
+{% endblock %} + +{% block jscripts %} + {{ super() }} +{% endblock %} diff --git a/pagure/ui/app.py b/pagure/ui/app.py index e2b729f..80c7834 100644 --- a/pagure/ui/app.py +++ b/pagure/ui/app.py @@ -42,25 +42,17 @@ def _filter_acls(repos, acl, user): """ Filter the given list of repositories to return only the ones where the user has the specified acl. """ - if acl == 'commit': + if acl.lower() == 'main admin': repos = [ repo for repo in repos - if user in repo.committers - or user.username == repo.user.username - ] - elif acl == 'admin': - repos = [ - repo - for repo in repos - if user in repo.admins - or user.username == repo.user.username + if user.username == repo.user.username ] - elif acl == 'main admin': + elif acl.lower() == 'ticket' or 'commit' or 'admin': repos = [ repo for repo in repos - if user.username == repo.user.username + if user in repo.contributors[acl.lower()] ] return repos @@ -73,7 +65,8 @@ def index(): """ Front page of the application. """ if authenticated() and flask.request.path == '/': - return index_auth() + return flask.redirect( + flask.url_for('ui_ns.userdash_projects')) sorting = flask.request.args.get('sorting') or None page = flask.request.args.get('page', 1) @@ -118,6 +111,271 @@ def index(): ) +def get_userdash_common(user): + userdash_counts = {} + + userdash_counts['repos_length'] = pagure.lib.list_users_projects( + flask.g.session, + username=flask.g.fas_user.username, + exclude_groups=None, + fork=False, + private=flask.g.fas_user.username, + count=True, + ) + + userdash_counts['forks_length'] = pagure.lib.search_projects( + flask.g.session, + username=flask.g.fas_user.username, + fork=True, + private=flask.g.fas_user.username, + count=True, + ) + + userdash_counts['watchlist_length'] = len(pagure.lib.user_watch_list( + flask.g.session, + user=flask.g.fas_user.username, + exclude_groups=pagure_config.get('EXCLUDE_GROUP_INDEX'), + )) + + userdash_counts['groups_length'] = len(user.groups) + + search_data = pagure.lib.list_users_projects( + flask.g.session, + username=flask.g.fas_user.username, + private=flask.g.fas_user.username, + ) + + return userdash_counts, search_data + + +@UI_NS.route('/dashboard/projects/') +@UI_NS.route('/dashboard/projects') +@login_required +def userdash_projects(): + """ User Dashboard page listing projects for the user + """ + user = _get_user(username=flask.g.fas_user.username) + userdash_counts, search_data = get_userdash_common(user) + + groups = [] + + for group in user.groups: + groups.append(pagure.lib.search_groups(flask.g.session, + group_name=group, + group_type='user')) + + acl = flask.request.args.get('acl', '').strip().lower() or None + search_pattern = flask.request.args.get('search_pattern', None) + if search_pattern == "": + search_pattern = None + + limit = pagure_config['ITEM_PER_PAGE'] + + repopage = flask.request.args.get('repopage', 1) + try: + repopage = int(repopage) + if repopage < 1: + repopage = 1 + except ValueError: + repopage = 1 + + pattern = "*" + search_pattern + "*" if search_pattern else search_pattern + + start = limit * (repopage - 1) + repos = pagure.lib.list_users_projects( + flask.g.session, + username=flask.g.fas_user.username, + exclude_groups=None, + fork=False, + pattern=pattern, + private=flask.g.fas_user.username, + start=start, + limit=limit, + acls=[acl] if acl else None, + ) + + filtered_repos_count = pagure.lib.list_users_projects( + flask.g.session, + username=flask.g.fas_user.username, + exclude_groups=None, + fork=False, + pattern=pattern, + private=flask.g.fas_user.username, + count=True, + acls=[acl] if acl else None, + ) + + repo_list = [] + for repo in repos: + access = "" + if repo.user.user == user.username: + access = "main admin" + else: + for repoaccess in repo.contributors: + for repouser in repo.contributors[repoaccess]: + if repouser.username == user.username: + access = repoaccess + grouplist = [] + for group in groups: + if repo in group.projects: + thegroup = {"group_name": "", "access": ""} + thegroup['group_name'] = group.group_name + for a in repo.contributor_groups: + for gr in repo.contributor_groups[a]: + if group.group_name == gr.group_name: + thegroup["access"] = a + grouplist.append(thegroup) + repo_list.append({ + "repo": repo, + "grouplist": grouplist, + "access": access, + }) + + total_repo_page = int( + ceil(filtered_repos_count / + float(limit)) if filtered_repos_count > 0 else 1) + + return flask.render_template( + 'userdash_projects.html', + username=flask.g.fas_user.username, + user=user, + select="projects", + repo_list=repo_list, + repopage=repopage, + total_repo_page=total_repo_page, + userdash_counts=userdash_counts, + search_data=search_data, + acl=acl, + filtered_repos_count=filtered_repos_count, + search_pattern=search_pattern, + ) + + +@UI_NS.route('/dashboard/activity/') +@UI_NS.route('/dashboard/activity') +@login_required +def userdash_activity(): + """ User Dashboard page listing user activity + """ + user = _get_user(username=flask.g.fas_user.username) + userdash_counts, search_data = get_userdash_common(user) + + messages = pagure.lib.get_watchlist_messages(flask.g.session, + user, + limit=20) + + return flask.render_template( + 'userdash_activity.html', + username=flask.g.fas_user.username, + user=user, + select="activity", + messages=messages, + userdash_counts=userdash_counts, + search_data=search_data, + ) + + +@UI_NS.route('/dashboard/groups/') +@UI_NS.route('/dashboard/groups') +@login_required +def userdash_groups(): + """ User Dashboard page listing a user's groups + """ + user = _get_user(username=flask.g.fas_user.username) + userdash_counts, search_data = get_userdash_common(user) + + groups = [] + + for group in user.groups: + groups.append(pagure.lib.search_groups(flask.g.session, + group_name=group, + group_type='user')) + + return flask.render_template( + 'userdash_groups.html', + username=flask.g.fas_user.username, + user=user, + select="groups", + groups=groups, + userdash_counts=userdash_counts, + search_data=search_data, + ) + + +@UI_NS.route('/dashboard/forks/') +@UI_NS.route('/dashboard/forks') +@login_required +def userdash_forks(): + """ Forks tab of the user dashboard + """ + user = _get_user(username=flask.g.fas_user.username) + userdash_counts, search_data = get_userdash_common(user) + + limit = pagure_config['ITEM_PER_PAGE'] + + # FORKS + forkpage = flask.request.args.get('forkpage', 1) + try: + forkpage = int(forkpage) + if forkpage < 1: + forkpage = 1 + except ValueError: + forkpage = 1 + + start = limit * (forkpage - 1) + forks = pagure.lib.search_projects( + flask.g.session, + username=flask.g.fas_user.username, + fork=True, + private=flask.g.fas_user.username, + start=start, + limit=limit, + ) + + total_fork_page = int( + ceil(userdash_counts['forks_length'] / + float(limit)) if userdash_counts['forks_length'] > 0 else 1) + + return flask.render_template( + 'userdash_forks.html', + username=flask.g.fas_user.username, + user=user, + select="forks", + forks=forks, + forkpage=forkpage, + total_fork_page=total_fork_page, + userdash_counts=userdash_counts, + search_data=search_data, + ) + + +@UI_NS.route('/dashboard/watchlist/') +@UI_NS.route('/dashboard/watchlist') +@login_required +def userdash_watchlist(): + """ User Dashboard page for a user's watchlist + """ + + watch_list = pagure.lib.user_watch_list( + flask.g.session, + user=flask.g.fas_user.username, + exclude_groups=pagure_config.get('EXCLUDE_GROUP_INDEX'), + ) + + user = _get_user(username=flask.g.fas_user.username) + userdash_counts, search_data = get_userdash_common(user) + + return flask.render_template( + 'userdash_watchlist.html', + username=flask.g.fas_user.username, + user=user, + select="watchlist", + watch_list=watch_list, + userdash_counts=userdash_counts, + search_data=search_data, + ) + + def index_auth(): """ Front page for authenticated user. """ @@ -198,7 +456,7 @@ def index_auth(): ) return flask.render_template( - 'index_auth.html', + 'userdash_projects.html', username=flask.g.fas_user.username, user=user, forks=forks, diff --git a/pagure/utils.py b/pagure/utils.py index 7332514..1d647d8 100644 --- a/pagure/utils.py +++ b/pagure/utils.py @@ -94,12 +94,15 @@ def is_admin(): return not groups.isdisjoint(admins) -def is_repo_admin(repo_obj): +def is_repo_admin(repo_obj, username=None): """ Return whether the user is an admin of the provided repo. """ if not authenticated(): return False - user = flask.g.fas_user.username + if username: + user = username + else: + user = flask.g.fas_user.username if is_admin(): return True @@ -114,12 +117,15 @@ def is_repo_admin(repo_obj): ) or (user in usergrps) -def is_repo_committer(repo_obj): +def is_repo_committer(repo_obj, username=None): """ Return whether the user is a committer of the provided repo. """ if not authenticated(): return False - user = flask.g.fas_user.username + if username: + user = username + else: + user = flask.g.fas_user.username if is_admin(): return True @@ -149,12 +155,15 @@ def is_repo_committer(repo_obj): ) or (user in usergrps) -def is_repo_user(repo_obj): +def is_repo_user(repo_obj, username=None): """ Return whether the user has some access in the provided repo. """ if not authenticated(): return False - user = flask.g.fas_user.username + if username: + user = username + else: + user = flask.g.fas_user.username if is_admin(): return True @@ -169,6 +178,25 @@ def is_repo_user(repo_obj): ) or (user in usergrps) +def get_user_repo_access(repo_obj, username): + """ return a string of the highest level of access + a user has on a repo. + """ + if repo_obj.user.username == username: + return "main admin" + + if is_repo_admin(repo_obj, username): + return "admin" + + if is_repo_committer(repo_obj, username): + return "commit" + + if is_repo_user(repo_obj, username): + return "ticket" + + return None + + def login_required(function): """ Flask decorator to retrict access to logged in user. If the auth system is ``fas`` it will also require that the user sign diff --git a/tests/test_pagure_flask_api_ui_private_repo.py b/tests/test_pagure_flask_api_ui_private_repo.py index f950cfc..df5e43d 100644 --- a/tests/test_pagure_flask_api_ui_private_repo.py +++ b/tests/test_pagure_flask_api_ui_private_repo.py @@ -416,18 +416,20 @@ class PagurePrivateRepotest(tests.Modeltests): user = tests.FakeUser(username='foo') with tests.user_set(self.app.application, user): - output = self.app.get('/') + output = self.app.get('/', follow_redirects=True) output_text = output.get_data(as_text=True) self.assertIn( - 'My Projects 2', + '

My Projects

', output_text) self.assertIn( - 'Forks 0', + '2 projects', + output_text) + self.assertNotIn( + 'Forks', output_text) self.assertEqual( - output_text.count('

No group found

'), 1) - self.assertEqual( - output_text.count('
'), 6) + output_text.count('Groups'), 0) + def test_view_user(self): """ Test the view_user endpoint. """ @@ -487,7 +489,7 @@ class PagurePrivateRepotest(tests.Modeltests): self.assertEqual( output_text.count('

No group found

'), 1) self.assertEqual( - output_text.count('
'), 5) + output_text.count('
'), 3) user.username = 'pingou' with tests.user_set(self.app.application, user): @@ -502,23 +504,24 @@ class PagurePrivateRepotest(tests.Modeltests): self.assertEqual( output_text.count('

No group found

'), 1) self.assertEqual( - output_text.count('
'), 5) + output_text.count('
'), 3) # Check pingou has 0 projects user.username = 'pingou' with tests.user_set(self.app.application, user): - output = self.app.get('/') + output = self.app.get('/', follow_redirects=True) output_text = output.get_data(as_text=True) self.assertIn( - 'My Projects 0', + '

My Projects

', output_text) self.assertIn( - 'Forks 0', + '0 projects', + output_text) + self.assertNotIn( + 'Forks', output_text) self.assertEqual( - output_text.count('

No group found

'), 1) - self.assertEqual( - output_text.count('
'), 6) + output_text.count('Groups'), 0) repo = pagure.lib._get_project(self.session, 'test3') @@ -534,18 +537,19 @@ class PagurePrivateRepotest(tests.Modeltests): # New user added to private projects user.username = 'pingou' with tests.user_set(self.app.application, user): - output = self.app.get('/') + output = self.app.get('/', follow_redirects=True) output_text = output.get_data(as_text=True) self.assertIn( - 'My Projects 1', + '

My Projects

', output_text) self.assertIn( - 'Forks 0', + '1 projects
', + output_text) + self.assertNotIn( + 'Forks', output_text) self.assertEqual( - output_text.count('

No group found

'), 1) - self.assertEqual( - output_text.count('
'), 6) + output_text.count('Groups'), 0) @patch('pagure.decorators.admin_session_timedout') def test_private_settings_ui(self, ast): diff --git a/tests/test_pagure_flask_ui_app.py b/tests/test_pagure_flask_ui_app.py index 3a508a8..fca5ba8 100644 --- a/tests/test_pagure_flask_ui_app.py +++ b/tests/test_pagure_flask_ui_app.py @@ -40,30 +40,18 @@ class PagureFlaskApptests(tests.Modeltests): user = tests.FakeUser(username='pingou') with tests.user_set(self.app.application, user): - output = self.app.get('/') + output = self.app.get('/', follow_redirects=True) output_text = output.get_data(as_text=True) self.assertIn( '
You have no projects
', output_text) - self.assertIn( - '

You have no forks

', - output_text) - self.assertIn( - '

No project in watch list

', - output_text) tests.create_projects(self.session) - output = self.app.get('/') + output = self.app.get('/', follow_redirects=True) output_text = output.get_data(as_text=True) self.assertIn( - 'My Projects 3', - output_text) - self.assertIn( - 'My Forks 0', - output_text) - self.assertIn( - 'My Watch List 3', + '

My Projects

', output_text) def test_view_users(self): @@ -157,11 +145,11 @@ class PagureFlaskApptests(tests.Modeltests): user = tests.FakeUser(username='foo') with tests.user_set(self.app.application, user): - output = self.app.get('/') + output = self.app.get('/', follow_redirects=True) self.assertEqual(output.status_code, 200) output_text = output.get_data(as_text=True) self.assertIn( - 'My Projects 0', + '

My Projects

', output_text) # master template self.assertNotIn( @@ -180,11 +168,11 @@ class PagureFlaskApptests(tests.Modeltests): user = tests.FakeUser(username='pingou') with tests.user_set(self.app.application, user): - output = self.app.get('/') + output = self.app.get('/', follow_redirects=True) self.assertEqual(output.status_code, 200) output_text = output.get_data(as_text=True) self.assertIn( - 'My Projects 3', + '

My Projects

', output_text) # master template self.assertNotIn( diff --git a/tests/test_pagure_flask_ui_app_index.py b/tests/test_pagure_flask_ui_app_index.py index 4ae2e0d..0646436 100644 --- a/tests/test_pagure_flask_ui_app_index.py +++ b/tests/test_pagure_flask_ui_app_index.py @@ -56,7 +56,10 @@ class PagureFlaskAppIndextests(tests.Modeltests): output.get_data(as_text=True)) def test_index_logged_in(self): - """ Test the index endpoint when logged in. """ + """ + Test the index endpoint when logged in. + It should redirect to the userdash. + """ tests.create_projects(self.session) # Add a 3rd project with a long description @@ -71,458 +74,18 @@ class PagureFlaskAppIndextests(tests.Modeltests): user = tests.FakeUser(username='foo') with tests.user_set(self.app.application, user): - output = self.app.get('/?repopage=abc&forkpage=def') + output = self.app.get('/', follow_redirects=True) self.assertEqual(output.status_code, 200) output_text = output.get_data(as_text=True) self.assertIn( - 'Projects 1', + '' + '1 projects\n', output_text) - self.assertIn( - 'Forks 0', - output_text) - self.assertEqual( - output_text.count('

No group found

'), 1) - self.assertEqual( - output_text.count('
'), 6) - - def test_index_commit_access_while_admin(self): - """ Test the index endpoint filter for commit access only when user - is an admin. """ - tests.create_projects(self.session) - - # Add a 3rd project just for foo - item = pagure.lib.model.Project( - user_id=2, # foo - name='test3', - description='test project #3 with a very long description', - hook_token='aaabbbeeefff', - ) - self.session.add(item) - self.session.commit() - - user = tests.FakeUser(username='foo') - with tests.user_set(self.app.application, user): - # Before - output = self.app.get('/?acl=commit') - self.assertEqual(output.status_code, 200) - output_text = output.get_data(as_text=True) - self.assertIn( - 'Projects 1', - output_text) - self.assertIn( - 'Forks 0', - output_text) - self.assertEqual( - output_text.count('

No group found

'), 1) - self.assertEqual( - output_text.count('
'), 6) - - # Add foo to test with admin level - project = pagure.lib._get_project(self.session, 'test') - msg = pagure.lib.add_user_to_project( - self.session, - project=project, - new_user='foo', - user='pingou', - access='admin') - self.session.commit() - self.assertEqual(msg, 'User added') - - # After - output = self.app.get('/?acl=commit') - self.assertEqual(output.status_code, 200) - output_text = output.get_data(as_text=True) - self.assertIn( - 'Projects 2', - output_text) - self.assertIn( - 'Forks 0', - output_text) - self.assertEqual( - output_text.count('

No group found

'), 1) - self.assertEqual( - output_text.count('
'), 6) - - def test_index_commit_access_while_commit(self): - """ Test the index endpoint filter for commit access only when user - is an committer. """ - tests.create_projects(self.session) - - # Add a 3rd project just for foo - item = pagure.lib.model.Project( - user_id=2, # foo - name='test3', - description='test project #3 with a very long description', - hook_token='aaabbbeeefff', - ) - self.session.add(item) - self.session.commit() - - user = tests.FakeUser(username='foo') - with tests.user_set(self.app.application, user): - # Before - output = self.app.get('/?acl=commit') - self.assertEqual(output.status_code, 200) - output_text = output.get_data(as_text=True) - self.assertIn( - 'Projects 1', - output_text) - self.assertIn( - 'Forks 0', - output_text) - self.assertEqual( - output_text.count('

No group found

'), 1) - self.assertEqual( - output_text.count('
'), 6) - - # Add foo to test with commit level - project = pagure.lib._get_project(self.session, 'test') - msg = pagure.lib.add_user_to_project( - self.session, - project=project, - new_user='foo', - user='pingou', - access='commit') - self.session.commit() - self.assertEqual(msg, 'User added') - - # After - output = self.app.get('/?acl=commit') - self.assertEqual(output.status_code, 200) - output_text = output.get_data(as_text=True) - self.assertIn( - 'Projects 2', - output_text) - self.assertIn( - 'Forks 0', - output_text) - self.assertEqual( - output_text.count('

No group found

'), 1) - self.assertEqual( - output_text.count('
'), 6) - - def test_index_commit_access_while_ticket(self): - """ Test the index endpoint filter for commit access only when user - is has ticket access. """ - tests.create_projects(self.session) - - # Add a 3rd project just for foo - item = pagure.lib.model.Project( - user_id=2, # foo - name='test3', - description='test project #3 with a very long description', - hook_token='aaabbbeeefff', - ) - self.session.add(item) - self.session.commit() - - user = tests.FakeUser(username='foo') - with tests.user_set(self.app.application, user): - # Before - output = self.app.get('/?acl=ticket') - self.assertEqual(output.status_code, 200) - output_text = output.get_data(as_text=True) - self.assertIn( - 'Projects 1', - output_text) - self.assertIn( - 'Forks 0', - output_text) - self.assertEqual( - output_text.count('

No group found

'), 1) - self.assertEqual( - output_text.count('
'), 6) - - # Add foo to test with ticket level - project = pagure.lib._get_project(self.session, 'test') - msg = pagure.lib.add_user_to_project( - self.session, - project=project, - new_user='foo', - user='pingou', - access='ticket') - self.session.commit() - self.assertEqual(msg, 'User added') - - # After - projects with ticket access aren't shown - output = self.app.get('/?acl=ticket') - self.assertEqual(output.status_code, 200) - output_text = output.get_data(as_text=True) - self.assertIn( - 'Projects 1', - output_text) - self.assertIn( - 'Forks 0', - output_text) - self.assertEqual( - output_text.count('

No group found

'), 1) - self.assertEqual( - output_text.count('
'), 6) - - def test_index_admin_access_while_admin(self): - """ Test the index endpoint filter for admin access only when user - is an admin. """ - tests.create_projects(self.session) - - # Add a 3rd project just for foo - item = pagure.lib.model.Project( - user_id=2, # foo - name='test3', - description='test project #3 with a very long description', - hook_token='aaabbbeeefff', - ) - self.session.add(item) - self.session.commit() - - user = tests.FakeUser(username='foo') - with tests.user_set(self.app.application, user): - # Before - output = self.app.get('/?acl=admin') - self.assertEqual(output.status_code, 200) - output_text = output.get_data(as_text=True) - self.assertIn( - 'Projects 1', - output_text) - self.assertIn( - 'Forks 0', - output_text) - self.assertEqual( - output_text.count('

No group found

'), 1) - self.assertEqual( - output_text.count('
'), 6) - - # Add foo to test with commit level - project = pagure.lib._get_project(self.session, 'test') - msg = pagure.lib.add_user_to_project( - self.session, - project=project, - new_user='foo', - user='pingou', - access='admin') - self.session.commit() - self.assertEqual(msg, 'User added') - - # After - output = self.app.get('/?acl=admin') - self.assertEqual(output.status_code, 200) - output_text = output.get_data(as_text=True) - self.assertIn( - 'Projects 2', - output_text) - self.assertIn( - 'Forks 0', - output_text) - self.assertEqual( - output_text.count('

No group found

'), 1) - self.assertEqual( - output_text.count('
'), 6) - - def test_index_admin_access_while_commit(self): - """ Test the index endpoint filter for admin access only when user - is an committer. """ - tests.create_projects(self.session) - - # Add a 3rd project just for foo - item = pagure.lib.model.Project( - user_id=2, # foo - name='test3', - description='test project #3 with a very long description', - hook_token='aaabbbeeefff', - ) - self.session.add(item) - self.session.commit() - - user = tests.FakeUser(username='foo') - with tests.user_set(self.app.application, user): - # Before - output = self.app.get('/?acl=admin') - self.assertEqual(output.status_code, 200) - output_text = output.get_data(as_text=True) - self.assertIn( - 'Projects 1', - output_text) - self.assertIn( - 'Forks 0', - output_text) - self.assertEqual( - output_text.count('

No group found

'), 1) - self.assertEqual( - output_text.count('
'), 6) - - # Add foo to test with commit level - project = pagure.lib._get_project(self.session, 'test') - msg = pagure.lib.add_user_to_project( - self.session, - project=project, - new_user='foo', - user='pingou', - access='commit') - self.session.commit() - self.assertEqual(msg, 'User added') - - # After - output = self.app.get('/?acl=admin') - self.assertEqual(output.status_code, 200) - output_text = output.get_data(as_text=True) - # The total number no longer changes - self.assertIn( - 'Projects 2', - output_text) - self.assertIn( - 'Forks 0', - output_text) - self.assertEqual( - output_text.count('

No group found

'), 1) - self.assertEqual( - output_text.count('
'), 6) - - def test_index_main_admin_access_while_commit(self): - """ Test the index endpoint filter for main admin access only when - user is an committer. """ - tests.create_projects(self.session) - - # Add a 3rd project just for foo - item = pagure.lib.model.Project( - user_id=2, # foo - name='test3', - description='test project #3 with a very long description', - hook_token='aaabbbeeefff', - ) - self.session.add(item) - self.session.commit() - - user = tests.FakeUser(username='foo') - with tests.user_set(self.app.application, user): - # Before - output = self.app.get('/?acl=main admin') - self.assertEqual(output.status_code, 200) - output_text = output.get_data(as_text=True) - self.assertIn( - 'Projects 1', - output_text) - self.assertIn( - 'Forks 0', - output_text) - self.assertEqual( - output_text.count('

No group found

'), 1) - self.assertEqual( - output_text.count('
'), 6) - - # Add foo to test with commit level - project = pagure.lib._get_project(self.session, 'test') - msg = pagure.lib.add_user_to_project( - self.session, - project=project, - new_user='foo', - user='pingou', - access='commit') - self.session.commit() - self.assertEqual(msg, 'User added') - - # After - output = self.app.get('/?acl=main admin') - self.assertEqual(output.status_code, 200) - output_text = output.get_data(as_text=True) - self.assertIn( - 'Projects 2', - output_text) - self.assertIn( - 'Forks 0', - output_text) - self.assertEqual( - output_text.count('

No group found

'), 1) - self.assertEqual( - output_text.count('
'), 6) - - def test_index_fork_without_parent(self): - """ Test the index view: forks should display either their parent - project or mention that it was deleted. """ - tests.create_projects(self.session) - - # Add a 3rd project just for foo - item = pagure.lib.model.Project( - user_id=2, # foo - name='test3', - description='test project #3', - hook_token='aaabbbeeefff', - is_fork=True, - parent_id=1, - ) - self.session.add(item) - self.session.commit() - - user = tests.FakeUser(username='foo') - with tests.user_set(self.app.application, user): - # Before - output = self.app.get('/') - self.assertEqual(output.status_code, 200) - output_text = output.get_data(as_text=True) - self.assertIn( - 'My Forks 1', - output_text) - segment = output_text.split('My Forks')[1].split('My Groups')[0] - six.assertRegex( - self, - segment, - r'foo/test3(\s*<[^>]+?>\s*)*?forked from(\s*<[^>]+?>\s*)*?test' - ) - - # Delete the parent (or fake it) - proj = pagure.lib._get_project(self.session, 'test3', user='foo') - proj.parent_id = None - self.session.add(proj) - self.session.commit() - - # Check page again - output = self.app.get('/') - self.assertEqual(output.status_code, 200) - output_text = output.get_data(as_text=True) - self.assertIn( - 'My Forks 1', - output_text) - segment = output_text.split('My Forks')[1].split('My Groups')[0] - six.assertRegex( - self, - segment, - r'foo/test3(\s*<[^>]+?>\s*)*?forked from a deleted repository' - ) - - @patch.dict('pagure.config.config', {'PRIVATE_PROJECTS': True}) - def test_index_logged_in_private_project(self): - """ Test the index endpoint when logged in with a private project. """ - tests.create_projects(self.session) - - # Add a 3rd project with a long description - item = pagure.lib.model.Project( - user_id=2, # foo - name='test3', - description='test project #3 with a very long description', - hook_token='aaabbbeeefff', - private=True, - ) - self.session.add(item) - self.session.commit() - - user = tests.FakeUser(username='foo') - with tests.user_set(self.app.application, user): - output = self.app.get('/') - self.assertEqual(output.status_code, 200) - output_text = output.get_data(as_text=True) - self.assertIn( - 'Projects 1', - output_text) - self.assertIn( - '', - output_text) - self.assertEqual(output_text.count('title="Private project"'), 1) - self.assertIn( - 'Forks 0', + self.assertNotIn( + '

All Projects ' + '3

', output_text) - self.assertEqual( - output_text.count('

No group found

'), 1) - self.assertEqual( - output_text.count('
'), 6) if __name__ == '__main__': diff --git a/tests/test_pagure_flask_ui_app_userdash.py b/tests/test_pagure_flask_ui_app_userdash.py new file mode 100644 index 0000000..4765f6b --- /dev/null +++ b/tests/test_pagure_flask_ui_app_userdash.py @@ -0,0 +1,364 @@ +# -*- coding: utf-8 -*- + +""" + (c) 2018 - Copyright Red Hat Inc + + Authors: + Pierre-Yves Chibon + Ryan Lerch +""" + +from __future__ import unicode_literals + +__requires__ = ['SQLAlchemy >= 0.8'] +import pkg_resources + +import datetime +import unittest +import shutil +import sys +import os + +import six +import json +import pygit2 +from mock import patch, MagicMock + +sys.path.insert(0, os.path.join(os.path.dirname( + os.path.abspath(__file__)), '..')) + +import pagure.lib +import tests + + +class PagureFlaskAppUserdashTests(tests.Modeltests): + """ Tests for the index page of flask app controller of pagure """ + + def test_index_commit_access_while_admin(self): + """ Test the index endpoint filter for commit access only when user + is an admin. """ + tests.create_projects(self.session) + + # Add a 3rd project just for foo + item = pagure.lib.model.Project( + user_id=2, # foo + name='test3', + description='test project #3 with a very long description', + hook_token='aaabbbeeefff', + ) + self.session.add(item) + self.session.commit() + + user = tests.FakeUser(username='foo') + with tests.user_set(self.app.application, user): + # Before + output = self.app.get('/dashboard/projects?acl=commit') + self.assertEqual(output.status_code, 200) + output_text = output.get_data(as_text=True) + self.assertIn( + '1 projects', + output_text) + self.assertIn( + '
No Projects match this filter
', + output_text) + + + + # Add foo to test with admin level + project = pagure.lib._get_project(self.session, 'test') + msg = pagure.lib.add_user_to_project( + self.session, + project=project, + new_user='foo', + user='pingou', + access='admin') + self.session.commit() + self.assertEqual(msg, 'User added') + + # After + self.assertIn( + '1 projects', + output_text) + self.assertIn( + '
No Projects match this filter
', + output_text) + + def test_index_commit_access_while_commit(self): + """ Test the index endpoint filter for commit access only when user + is an committer. """ + tests.create_projects(self.session) + + # Add a 3rd project just for foo + item = pagure.lib.model.Project( + user_id=2, # foo + name='test3', + description='test project #3 with a very long description', + hook_token='aaabbbeeefff', + ) + self.session.add(item) + self.session.commit() + + user = tests.FakeUser(username='foo') + with tests.user_set(self.app.application, user): + # Before + output = self.app.get('/dashboard/projects?acl=commit') + self.assertEqual(output.status_code, 200) + output_text = output.get_data(as_text=True) + self.assertIn( + '

My Projects

\n' + ' 1 projects\n', + output_text) + + # Add foo to test with commit level + project = pagure.lib._get_project(self.session, 'test') + msg = pagure.lib.add_user_to_project( + self.session, + project=project, + new_user='foo', + user='pingou', + access='commit') + self.session.commit() + self.assertEqual(msg, 'User added') + + # After + output = self.app.get('/dashboard/projects?acl=commit') + self.assertEqual(output.status_code, 200) + output_text = output.get_data(as_text=True) + self.assertIn( + '

My Projects

\n' + ' 2 projects\n', + output_text) + + def test_index_commit_access_while_ticket(self): + """ Test the index endpoint filter for commit access only when user + is has ticket access. """ + tests.create_projects(self.session) + + # Add a 3rd project just for foo + item = pagure.lib.model.Project( + user_id=2, # foo + name='test3', + description='test project #3 with a very long description', + hook_token='aaabbbeeefff', + ) + self.session.add(item) + self.session.commit() + + user = tests.FakeUser(username='foo') + with tests.user_set(self.app.application, user): + # Before + output = self.app.get('/dashboard/projects?acl=ticket') + self.assertEqual(output.status_code, 200) + output_text = output.get_data(as_text=True) + self.assertIn( + '

My Projects

\n' + ' 1 projects\n', + output_text) + + # Add foo to test with ticket level + project = pagure.lib._get_project(self.session, 'test') + msg = pagure.lib.add_user_to_project( + self.session, + project=project, + new_user='foo', + user='pingou', + access='ticket') + self.session.commit() + self.assertEqual(msg, 'User added') + + # After - projects with ticket access aren't shown + output = self.app.get('/dashboard/projects?acl=ticket') + self.assertEqual(output.status_code, 200) + output_text = output.get_data(as_text=True) + self.assertIn( + '

My Projects

\n' + ' 2 projects\n', + output_text) + + def test_index_admin_access_while_admin(self): + """ Test the index endpoint filter for admin access only when user + is an admin. """ + tests.create_projects(self.session) + + # Add a 3rd project just for foo + item = pagure.lib.model.Project( + user_id=2, # foo + name='test3', + description='test project #3 with a very long description', + hook_token='aaabbbeeefff', + ) + self.session.add(item) + self.session.commit() + + user = tests.FakeUser(username='foo') + with tests.user_set(self.app.application, user): + # Before + output = self.app.get('/dashboard/projects?acl=admin') + self.assertEqual(output.status_code, 200) + output_text = output.get_data(as_text=True) + self.assertIn( + '

My Projects

\n' + ' 1 projects\n', + output_text) + + # Add foo to test with admin level + project = pagure.lib._get_project(self.session, 'test') + msg = pagure.lib.add_user_to_project( + self.session, + project=project, + new_user='foo', + user='pingou', + access='admin') + self.session.commit() + self.assertEqual(msg, 'User added') + + # After + output = self.app.get('/dashboard/projects?acl=admin') + self.assertEqual(output.status_code, 200) + output_text = output.get_data(as_text=True) + self.assertIn( + '

My Projects

\n' + ' 2 projects\n', + output_text) + + def test_index_admin_access_while_commit(self): + """ Test the index endpoint filter for admin access only when user + is an committer. """ + tests.create_projects(self.session) + + # Add a 3rd project just for foo + item = pagure.lib.model.Project( + user_id=2, # foo + name='test3', + description='test project #3 with a very long description', + hook_token='aaabbbeeefff', + ) + self.session.add(item) + self.session.commit() + + user = tests.FakeUser(username='foo') + with tests.user_set(self.app.application, user): + # Before + output = self.app.get('/dashboard/projects?acl=commit') + self.assertEqual(output.status_code, 200) + output_text = output.get_data(as_text=True) + self.assertIn( + '

My Projects

\n' + ' 1 projects\n', + output_text) + + # Add foo to test with commit level + project = pagure.lib._get_project(self.session, 'test') + msg = pagure.lib.add_user_to_project( + self.session, + project=project, + new_user='foo', + user='pingou', + access='commit') + self.session.commit() + self.assertEqual(msg, 'User added') + + # After + output = self.app.get('/dashboard/projects?acl=commit') + self.assertEqual(output.status_code, 200) + output_text = output.get_data(as_text=True) + # The total number no longer changes + self.assertIn( + '

My Projects

\n' + ' 2 projects\n', + output_text) + + def test_index_main_admin_access_while_commit(self): + """ Test the index endpoint filter for main admin access only when + user is an committer. """ + tests.create_projects(self.session) + + # Add a 3rd project just for foo + item = pagure.lib.model.Project( + user_id=2, # foo + name='test3', + description='test project #3 with a very long description', + hook_token='aaabbbeeefff', + ) + self.session.add(item) + self.session.commit() + + user = tests.FakeUser(username='foo') + with tests.user_set(self.app.application, user): + # Before + output = self.app.get('/dashboard/projects?acl=main admin') + self.assertEqual(output.status_code, 200) + output_text = output.get_data(as_text=True) + self.assertIn( + '

My Projects

\n' + ' 1 projects\n', + output_text) + + # Add foo to test with commit level + project = pagure.lib._get_project(self.session, 'test') + msg = pagure.lib.add_user_to_project( + self.session, + project=project, + new_user='foo', + user='pingou', + access='commit') + self.session.commit() + self.assertEqual(msg, 'User added') + + # After + output = self.app.get('/dashboard/projects?acl=main admin') + self.assertEqual(output.status_code, 200) + output_text = output.get_data(as_text=True) + self.assertIn( + '

My Projects

\n' + ' 2 projects\n', + output_text) + + + @patch.dict('pagure.config.config', {'PRIVATE_PROJECTS': True}) + def test_index_logged_in_private_project(self): + """ Test the index endpoint when logged in with a private project. """ + tests.create_projects(self.session) + + # Add a 3rd project with a long description + item = pagure.lib.model.Project( + user_id=2, # foo + name='test3', + description='test project #3 with a very long description', + hook_token='aaabbbeeefff', + private=True, + ) + self.session.add(item) + self.session.commit() + + user = tests.FakeUser(username='foo') + with tests.user_set(self.app.application, user): + output = self.app.get('/dashboard/projects') + self.assertEqual(output.status_code, 200) + output_text = output.get_data(as_text=True) + self.assertIn( + '

My Projects

\n' + ' 1 projects\n', + output_text) + self.assertIn( + '', + output_text) + self.assertEqual(output_text.count('title="Private project"'), 1) + + +if __name__ == '__main__': + unittest.main(verbosity=2) diff --git a/tests/test_pagure_flask_ui_groups.py b/tests/test_pagure_flask_ui_groups.py index 27c9e1e..8a205a4 100644 --- a/tests/test_pagure_flask_ui_groups.py +++ b/tests/test_pagure_flask_ui_groups.py @@ -39,27 +39,6 @@ class PagureFlaskGroupstests(tests.Modeltests): ' Groups 0', output.get_data(as_text=True)) - def test_add_group_index_auth(self): - """ Test the presence of the add group button on the front page. """ - user = tests.FakeUser(username='foo') - with tests.user_set(self.app.application, user): - output = self.app.get('/') - self.assertEqual(output.status_code, 200) - self.assertIn( - 'title="Create New Group" aria-hidden="true">', - output.get_data(as_text=True)) - - @patch.dict('pagure.config.config', {'ENABLE_GROUP_MNGT': False}) - def test_not_add_group_index_auth(self): - """ Test the presence of the add group button on the front page. """ - user = tests.FakeUser(username='foo') - with tests.user_set(self.app.application, user): - output = self.app.get('/') - self.assertEqual(output.status_code, 200) - self.assertNotIn( - 'title="Create New Group" aria-hidden="true">', - output.get_data(as_text=True)) - def test_add_group(self): """ Test the add_group endpoint. """ output = self.app.get('/group/add') diff --git a/tests/test_pagure_flask_ui_login.py b/tests/test_pagure_flask_ui_login.py index c1727cc..f000729 100644 --- a/tests/test_pagure_flask_ui_login.py +++ b/tests/test_pagure_flask_ui_login.py @@ -313,7 +313,7 @@ class PagureFlaskLogintests(tests.SimplePagureTest): # versions of Flask. self.assertIn( '', output_text) + 'href="/logout/?next=http://localhost/dashboard/projects">', output_text) @patch.dict('pagure.config.config', {'PAGURE_AUTH': 'local'}) @patch.dict('pagure.config.config', {'CHECK_SESSION_IP': False}) @@ -854,7 +854,8 @@ class PagureFlaskLogintests(tests.SimplePagureTest): # Due to the way the tests are running we do not actually # log out self.assertIn( - 'Log Out', + 'Log Out', output.get_data(as_text=True)) @patch.dict('pagure.config.config', {'PAGURE_AUTH': 'local'}) @@ -916,7 +917,6 @@ class PagureFlaskLogintests(tests.SimplePagureTest): # We should now get redirected to index, because our session became # invalid output = self.app.get('/settings') - self.assertEqual(output.status_code, 302) self.assertEqual(output.headers['Location'], 'http://localhost/') @@ -924,7 +924,7 @@ class PagureFlaskLogintests(tests.SimplePagureTest): # valid user.login_time = datetime.datetime.utcnow() output = self.app.get('/') - self.assertEqual(output.status_code, 200) + self.assertEqual(output.status_code, 302) if __name__ == '__main__': diff --git a/tests/test_pagure_flask_ui_repo.py b/tests/test_pagure_flask_ui_repo.py index 6f587ee..c008b52 100644 --- a/tests/test_pagure_flask_ui_repo.py +++ b/tests/test_pagure_flask_ui_repo.py @@ -130,7 +130,7 @@ class PagureFlaskRepotests(tests.Modeltests): # Need to do this un-authentified since our fake user isn't in the DB # Check the message flashed during the redirect - output = self.app.get('/') + output = self.app.get('/', follow_redirects=True) self.assertEqual(output.status_code, 200) output_text = output.get_data(as_text=True) self.assertIn( @@ -258,7 +258,7 @@ class PagureFlaskRepotests(tests.Modeltests): # Need to do this un-authentified since our fake user isn't in the DB # Check the message flashed during the redirect - output = self.app.get('/') + output = self.app.get('/', follow_redirects=True) self.assertEqual(output.status_code, 200) output_text = output.get_data(as_text=True) self.assertIn( @@ -447,7 +447,7 @@ class PagureFlaskRepotests(tests.Modeltests): # Need to do this un-authentified since our fake user isn't in the DB # Check the message flashed during the redirect - output = self.app.get('/') + output = self.app.get('/', follow_redirects=True) self.assertEqual(output.status_code, 200) output_text = output.get_data(as_text=True) self.assertIn( @@ -3192,14 +3192,14 @@ index 0000000..fb7093d os.path.join(self.path, 'requests'), bare=True) # Check repo was created - output = self.app.get('/') + output = self.app.get('/', follow_redirects=True) self.assertEqual(output.status_code, 200) output_text = output.get_data(as_text=True) self.assertIn( - '
\n My Projects 6', output_text) - self.assertIn( - 'Forks 0', + '6 projects', output_text) + self.assertNotIn( + 'Forks ', output_text) # add issues @@ -3285,14 +3285,14 @@ index 0000000..fb7093d self.assertEqual(msg, 'Comment added') # Check before deleting the project - output = self.app.get('/') + output = self.app.get('/', follow_redirects=True) self.assertEqual(output.status_code, 200) output_text = output.get_data(as_text=True) self.assertIn( - '
\n My Projects 6', output_text) - self.assertIn( - 'Forks 0', + '6 projects', output_text) + self.assertNotIn( + 'Forks ', output_text) output = self.app.post('/test/delete', follow_redirects=True) @@ -3323,14 +3323,18 @@ index 0000000..fb7093d os.path.join(self.path, 'tickets', 'pingou', 'test3.git')) # Check before deleting the fork - output = self.app.get('/') + output = self.app.get('/', follow_redirects=True) self.assertEqual(output.status_code, 200) output_text = output.get_data(as_text=True) self.assertIn( - '
\n My Projects 6', output_text) + '6 projects', output_text) self.assertIn( - 'Forks 1', +' Forks \n' +' \n' +'
\n' +' \n' +' 1', output_text) output = self.app.post( @@ -3504,14 +3508,14 @@ index 0000000..fb7093d os.path.join(self.path, 'requests'), bare=True) # Check repo was created - output = self.app.get('/') + output = self.app.get('/', follow_redirects=True) self.assertEqual(output.status_code, 200) output_text = output.get_data(as_text=True) self.assertIn( - '
\n My Projects 3', output_text) - self.assertIn( - 'Forks 0', + '3 projects', output_text) + self.assertNotIn( + 'Forks ', output_text) # add issues @@ -3597,14 +3601,14 @@ index 0000000..fb7093d self.assertEqual(msg, 'Comment added') # Check before deleting the project - output = self.app.get('/') + output = self.app.get('/', follow_redirects=True) self.assertEqual(output.status_code, 200) output_text = output.get_data(as_text=True) self.assertIn( - '
\n My Projects 3', output_text) - self.assertIn( - 'Forks 0', + '3 projects', output_text) + self.assertNotIn( + 'Forks ', output_text) output = self.app.post('/test/delete', follow_redirects=True) @@ -3643,14 +3647,18 @@ index 0000000..fb7093d os.path.join(self.path, 'tickets', 'pingou', 'test3.git')) # Check before deleting the fork - output = self.app.get('/') + output = self.app.get('/', follow_redirects=True) self.assertEqual(output.status_code, 200) output_text = output.get_data(as_text=True) self.assertIn( - '
\n My Projects 2', output_text) + '2 projects', output_text) self.assertIn( - 'Forks 1', +' Forks \n' +' \n' +'
\n' +' \n' +' 1\n', output_text) output = self.app.post( @@ -3683,14 +3691,14 @@ index 0000000..fb7093d user = tests.FakeUser(username='pingou') with tests.user_set(self.app.application, user): # Check before deleting the project - output = self.app.get('/') + output = self.app.get('/', follow_redirects=True) self.assertEqual(output.status_code, 200) output_text = output.get_data(as_text=True) self.assertIn( - '
\n My Projects 3', output_text) - self.assertIn( - 'Forks 0', + '3 projects', output_text) + self.assertNotIn( + 'Forks ', output_text) # Delete the project @@ -3737,14 +3745,14 @@ index 0000000..fb7093d os.path.join(self.path, 'requests'), bare=True) # Check repo was created - output = self.app.get('/') + output = self.app.get('/', follow_redirects=True) self.assertEqual(output.status_code, 200) output_text = output.get_data(as_text=True) self.assertIn( - '
\n My Projects 1', output_text) - self.assertIn( - 'Forks 0', + '1 projects', output_text) + self.assertNotIn( + 'Forks ', output_text) # add user @@ -3766,14 +3774,14 @@ index 0000000..fb7093d self.session.commit() # Check before deleting the project - output = self.app.get('/') + output = self.app.get('/', follow_redirects=True) self.assertEqual(output.status_code, 200) output_text = output.get_data(as_text=True) self.assertIn( - '
\n My Projects 1', output_text) - self.assertIn( - 'Forks 0', + '1 projects', output_text) + self.assertNotIn( + 'Forks ', output_text) repo = pagure.lib.get_authorized_project(self.session, 'test') self.assertNotEqual(repo, None) @@ -3828,14 +3836,14 @@ index 0000000..fb7093d os.path.join(self.path, 'requests'), bare=True) # Check repo was created - output = self.app.get('/') + output = self.app.get('/', follow_redirects=True) self.assertEqual(output.status_code, 200) output_text = output.get_data(as_text=True) self.assertIn( - '
\n My Projects 1', output_text) - self.assertIn( - 'Forks 0', + '1 projects', output_text) + self.assertNotIn( + 'Forks ', output_text) # Create group @@ -3875,14 +3883,14 @@ index 0000000..fb7093d self.assertEqual(len(repo.projects_groups), 1) # Check before deleting the project - output = self.app.get('/') + output = self.app.get('/', follow_redirects=True) self.assertEqual(output.status_code, 200) output_text = output.get_data(as_text=True) self.assertIn( - '
\n My Projects 1', output_text) - self.assertIn( - 'Forks 0', + '1 projects', output_text) + self.assertNotIn( + 'Forks ', output_text) repo = pagure.lib.get_authorized_project(self.session, 'test') self.assertNotEqual(repo, None) @@ -3933,14 +3941,14 @@ index 0000000..fb7093d os.path.join(self.path, 'requests'), bare=True) # Check repo was created - output = self.app.get('/') + output = self.app.get('/', follow_redirects=True) self.assertEqual(output.status_code, 200) output_text = output.get_data(as_text=True) self.assertIn( - '
\n My Projects 1', output_text) - self.assertIn( - 'Forks 0', + '1 projects', output_text) + self.assertNotIn( + 'Forks ', output_text) # Create the issue @@ -3969,14 +3977,14 @@ index 0000000..fb7093d self.assertEqual(msg, 'Issue tagged with: tag1') # Check before deleting the project - output = self.app.get('/') + output = self.app.get('/', follow_redirects=True) self.assertEqual(output.status_code, 200) output_text = output.get_data(as_text=True) self.assertIn( - '
\n My Projects 1', output_text) - self.assertIn( - 'Forks 0', + '1 projects', output_text) + self.assertNotIn( + 'Forks ', output_text) repo = pagure.lib.get_authorized_project(self.session, 'test') self.assertNotEqual(repo, None) @@ -4884,7 +4892,7 @@ index 0000000..fb7093d # Test when the session timed-out output = self.app.post('/test/token/new/', data=data) self.assertEqual(output.status_code, 302) - output = self.app.get('/') + output = self.app.get('/', follow_redirects=True) self.assertEqual(output.status_code, 200) output_text = output.get_data(as_text=True) self.assertIn( @@ -4963,7 +4971,7 @@ index 0000000..fb7093d # Test when the session timed-out output = self.app.post('/test/token/revoke/123', data=data) self.assertEqual(output.status_code, 302) - output = self.app.get('/') + output = self.app.get('/', follow_redirects=True) self.assertEqual(output.status_code, 200) output_text = output.get_data(as_text=True) self.assertIn( @@ -5057,7 +5065,7 @@ index 0000000..fb7093d # Test when the session timed-out output = self.app.post('/test/token/renew/123', data=data) self.assertEqual(output.status_code, 302) - output = self.app.get('/') + output = self.app.get('/', follow_redirects=True) self.assertEqual(output.status_code, 200) output_text = output.get_data(as_text=True) self.assertIn(