From 07ec473ffcd587927e84cd60ced5707e64ef5979 Mon Sep 17 00:00:00 2001 From: Ryan Lerch Date: Dec 13 2017 11:41:12 +0000 Subject: get basic allgroups page working --- diff --git a/hubs/static/client/app/components/AllGroupsPage.js b/hubs/static/client/app/components/AllGroupsPage.js new file mode 100644 index 0000000..9ccdd32 --- /dev/null +++ b/hubs/static/client/app/components/AllGroupsPage.js @@ -0,0 +1,81 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import { connect } from 'react-redux'; +import { + defineMessages, + FormattedMessage, + } from 'react-intl'; +import PageStructure from './PageStructure'; +import { monogramColour } from '../core/utils'; + + +class AllGroupsPage extends React.Component { + + render() { + return ( + +
+

Groups

+

Summary of available team hubs

+
+ + } + content={ +
+
+
+ {this.props.hubslist.hubs.map(function(hub, i) { + return ( + +
+ { !hub.config.avatar ? +
+ {hub.name.charAt(0).toUpperCase()} +
+ : + + } +
+

{hub.name}

+
{hub.config.summary}
+
+
+
+
+
Members
+
{hub.member_count}
+
+
+
Subscribers
+
{hub.subscriber_count}
+
+
+
+ ); + })} +
+
+
+ } + /> + ); + } +} + +const mapStateToProps = (state) => { + return { + hubslist: state.hubslist, + } + }; + + export default connect(mapStateToProps)(AllGroupsPage); diff --git a/hubs/static/client/app/core/Pages.js b/hubs/static/client/app/core/Pages.js index 67aee23..bfe19dc 100644 --- a/hubs/static/client/app/core/Pages.js +++ b/hubs/static/client/app/core/Pages.js @@ -14,6 +14,10 @@ const Streams = makeLoadable( "Loading...", "Sorry, there was a problem loading the page." ); +const Groups = makeLoadable( + () => import(/* webpackChunkName: "page-allgroups" */ '../components/AllGroupsPage'), + "Loading...", + "Sorry, there was a problem loading the page." +); - -export {Hub, Streams}; +export {Hub, Streams, Groups}; diff --git a/hubs/static/client/app/core/reducers/index.js b/hubs/static/client/app/core/reducers/index.js index 61bb90e..acb6644 100644 --- a/hubs/static/client/app/core/reducers/index.js +++ b/hubs/static/client/app/core/reducers/index.js @@ -40,6 +40,7 @@ const rootReducer = combineReducers({ globalConfig: noop, urls: noop, currentUser: userReducer, + hubslist: noop, ui, entities, }); diff --git a/hubs/static/css/style.css b/hubs/static/css/style.css index dae5273..defa6b5 100644 --- a/hubs/static/css/style.css +++ b/hubs/static/css/style.css @@ -401,16 +401,16 @@ header h5.m-b-1 { } /*Move these color defs into fedora-bootstrap*/ -.bg-fedora-blue{background-color:#3c6eb4;} -.bg-fedora-magenta{background-color: #db3279;} -.bg-fedora-orange{background-color: #e59728;} -.bg-fedora-green{background-color: #79db32;} -.bg-fedora-purple{background-color: #a07cbc;} -.text-fedora-blue-dark{color: #294a7a;} -.text-fedora-magenta-dark{color: #9a1b51;} -.text-fedora-orange-dark{color: #9a6213;} -.text-fedora-green-dark{color: #488b18;} -.text-fedora-purple-dark{color: #70488f;} +.bg-fedora-blue{background-color:#3c6eb4!important;} +.bg-fedora-magenta{background-color: #db3279!important;} +.bg-fedora-orange{background-color: #e59728!important;} +.bg-fedora-green{background-color: #79db32!important;} +.bg-fedora-purple{background-color: #a07cbc!important;} +.text-fedora-blue-dark{color: #294a7a!important;} +.text-fedora-magenta-dark{color: #9a1b51!important;} +.text-fedora-orange-dark{color: #9a6213!important;} +.text-fedora-green-dark{color: #488b18!important;} +.text-fedora-purple-dark{color: #70488f!important;} .typeahead, .twitter-typeahead { width: 100%!important; diff --git a/hubs/templates/groups.html b/hubs/templates/groups.html deleted file mode 100644 index 50b5710..0000000 --- a/hubs/templates/groups.html +++ /dev/null @@ -1,60 +0,0 @@ -{% extends "master.html" %} - -{% block title %}Groups{% endblock %} - - -{% block header %} -

Groups

-

Summary of available team hubs

-{% endblock header %} - - -{% block content %} - -
-
- {% for group in promoted %} - {{group.name}} - is a promoted group, and it has {{ - group.subscribers | length }} subscribers and {{ - group.members | length }} members, and {{ - group.owners | length }} owners - {% endfor %} -
-
- -
- -
-
- ZOMG - {{ hub_of_the_month.name }} is the Hub Of The Month!
- It has {{ hub_of_the_month.subscribers | length }} subscribers and {{ - hub_of_the_month.members | length }} members, and {{ - hub_of_the_month.owners | length }} owners -
group owners
- {% for owner in hub_of_the_month.owners %} - - {% endfor %} -
-
- -
- -
-
- {% for group in secondary %} - {{group.name}} - is not a promoted group - but it has {{ group.subscribers | length }} subscribers and {{ - group.members | length }} members, and {{ - group.owners | length }} owners -
- {% endfor %} -
-
- - -{% endblock content %} diff --git a/hubs/tests/views/test_root.py b/hubs/tests/views/test_root.py index 1288c6b..8394783 100644 --- a/hubs/tests/views/test_root.py +++ b/hubs/tests/views/test_root.py @@ -1,7 +1,10 @@ from __future__ import unicode_literals from six.moves.urllib.parse import urlparse +import mock +import json +import hubs from hubs.app import app from hubs.tests import APPTest, FakeAuthorization, auth_set @@ -41,11 +44,71 @@ class RootTestCase(APPTest): # this will redirect to fedora.login self.assertEqual(urlparse(result.location).path, "/") - def test_groups_logged_in(self): + +class RootGroupsTestCase(APPTest): + def _parse_setuppage_json(self, result): + result = result.get_data(as_text=True) + result = result.partition('function() {\n Hubs.setupPage("page", ')[2] + result = result.partition(');\n})();\n')[0] + return json.loads(result) + + def _add_assoc(self, hubname, username, role): + hub = hubs.models.Hub.query.get(hubname) + user = hubs.models.User.query.get(username) + self.session.add(hubs.models.Association( + hub=hub, user=user, role=role)) + + @mock.patch('hubs.views.root.log.warning') + def test_groups_HOTM_not_found(self, warning): + """ + Test we log a warning if the HUB_OF_THE_MONTH value + set in the config does not name a hub that exists. + The config in the base tests sets commops, as the + HOTM, but this hub doesnt exist in the base testcase + """ user = FakeAuthorization('ralph') with auth_set(app, user): result = self.app.get('/groups/', follow_redirects=True) - # assert the status code of the response + data = self._parse_setuppage_json(result) + + self.assertEqual(result.status_code, 200) + warning.assert_called_once_with("The hub (commops) set as the " + "HUB_OF_THE_MONTH in the config " + "does not exist") + self.assertEquals(data["hubslist"]["hub_of_the_month"], None) + + @mock.patch('hubs.views.root.log.warning') + @mock.patch('hubs.app.app.config.get', return_value="infra") + def test_groups_HOTM_found(self, config, warning): + """ + Test that we return the HOTM in the JSON we give to + the react component + """ + user = FakeAuthorization('ralph') + with auth_set(app, user): + result = self.app.get('/groups/', follow_redirects=True) + data = self._parse_setuppage_json(result) + + self.assertEqual(result.status_code, 200) + warning.assert_not_called() + self.assertEquals(data["hubslist"] + ["hub_of_the_month"] + ["name"], "infra") + + def test_groups(self): + """ + Test that we return the correct groups list + in the JSON we give to the react component + """ + user = FakeAuthorization('ralph') + self._add_assoc("infra", "ralph", "stargazer") + self._add_assoc("infra", "ralph", "member") + self._add_assoc("infra", "ralph", "subscriber") + with auth_set(app, user): + result = self.app.get('/groups/', follow_redirects=True) + data = self._parse_setuppage_json(result) self.assertEqual(result.status_code, 200) - self.assertIn("ZOMG - is the Hub Of The Month!", - result.get_data(as_text=True)) + self.assertEqual(len(data["hubslist"]["hubs"]), 3) + self.assertEqual(data["hubslist"]["hubs"][0]["name"], "i18n") + self.assertEqual(data["hubslist"]["hubs"][1]["name"], "infra") + self.assertEqual(data["hubslist"]["hubs"][2]["name"], "old") diff --git a/hubs/views/root.py b/hubs/views/root.py index cae9996..c4c525d 100644 --- a/hubs/views/root.py +++ b/hubs/views/root.py @@ -1,10 +1,16 @@ from __future__ import unicode_literals, absolute_import +import logging import flask import hubs.models from hubs.app import app, OIDC -from hubs.utils.views import authenticated, is_safe_url, login_required +from hubs.utils import hubname2monogramcolour +from hubs.utils.views import (authenticated, is_safe_url, + login_required, get_user_details) + + +log = logging.getLogger("hubs") @app.route('/') @@ -21,21 +27,53 @@ def index(): @app.route('/groups/') @login_required def groups(): - # Get the list of promoted and non-promoted group hubs from the DB - promoted_names = app.config.get('PROMOTED_GROUPS') + current_user = get_user_details() + urls = { + "allGroups": flask.url_for("groups"), + } + flash_messages = [ + {"msg": msg[1], "type": msg[0]} for msg in + flask.get_flashed_messages(with_categories=True) + ] + groups = hubs.models.Hub.all_group_hubs() - promoted = [g for g in groups if g.name in promoted_names] - secondary = [g for g in groups if g.name not in promoted_names] + hubslist = [] + for group in groups: + hub = group.get_props() + hub["monogram_colour"] = hubname2monogramcolour(hub["name"]) + hub["hub_url"] = flask.url_for('hub', name=hub["name"]) + + member_count = len(hub["users"]["member"]) + owner_count = len(hub["users"]["owner"]) + hub["member_count"] = member_count + owner_count + + subscriber_count = len(hub["users"]["subscriber"]) + hub["subscriber_count"] = subscriber_count + + hubslist.append(hub) name_of_the_month = app.config.get('HUB_OF_THE_MONTH') hub_of_the_month = hubs.models.Hub.by_name(name_of_the_month) + if hub_of_the_month: + hub_of_the_month = hub_of_the_month.get_props() + else: + log.warning("The hub (%s) set as the HUB_OF_THE_MONTH " + "in the config does not exist" % name_of_the_month) return flask.render_template( - 'groups.html', - promoted=promoted, - secondary=secondary, - hub_of_the_month=hub_of_the_month, - ) + 'react.html', + page_title="All Groups", + initial_state=dict( + ui=dict( + page="Groups", + flashMessages=flash_messages, + ), + urls=urls, + currentUser=current_user, + hubslist={"hubs": hubslist, + "hub_of_the_month": hub_of_the_month} + ), + ) @app.route('/login/', methods=('GET', 'POST'))