#497 Send message to group hubs depending on the hub config
Merged 6 years ago by abompard. Opened 6 years ago by abompard.
abompard/fedora-hubs feature/group-feed  into  develop

file modified
+60 -9
@@ -10,8 +10,8 @@ 

  import pymongo

  from fedmsg.encoding import loads, dumps

  

- from hubs.models import Hub, User, Association

- from hubs.utils import get_fedmsg_config

+ from hubs.models import Hub, User, HubConfig

+ from hubs.utils import get_fedmsg_config, pagure

  

  

  log = logging.getLogger(__name__)
@@ -19,23 +19,74 @@ 

  

  def get_hubs_for_msg(msg):

      hubs = []

+     # User hubs

      for username in fedmsg.meta.msg2usernames(msg):

          user = User.query.get(username)

          # Only act on existing users

          if user is None:

              log.debug("Message concerning an unknown user: %s", username)

              continue

+         if Hub.query.get(username) is None:

+             log.debug("User exists but has no personal hub: %s", username)

+             continue

          hubs.append(username)

-         group_hubs = Hub.query.filter(

-                 Hub.user_hub == False,  # noqa:E712

-             ).join(Association).filter(

-                 Association.user == user,

-                 Association.role.in_(["owner", "member"]),

-             )

-         hubs.extend([result[0] for result in group_hubs.values(Hub.name)])

+ 

+     # Group hubs

+     if ".meetbot.meeting." in msg["topic"]:

+         # Chat

+         hubs.extend(_get_group_hub_names_by_config(

+             HubConfig.key == "chat_channel",

+             HubConfig.value == msg["msg"]["channel"],

+         ))

+     elif ".mailman.receive" in msg["topic"]:

+         # Mailing-list

+         list_name = msg["msg"]["mlist"]["list_name"]

+         # TODO: deploy a new version of the mailman fedmsg plugin that adds

+         # this metadata:

+         # list_address = msg["msg"]["mlist"]["fqdn_listname"]

+         # in the meantime, we have to use a LIKE (which is very slow)

+         hubs.extend(_get_group_hub_names_by_config(

+             HubConfig.key == "mailing_list",

+             HubConfig.value.like("{}@%".format(list_name)),

+         ))

+     elif ".fedocal." in msg["topic"]:

+         # Calendar

+         hubs.extend(_get_group_hub_names_by_config(

+             HubConfig.key == "calendar",

+             HubConfig.value == msg["msg"]["calendar"]["calendar_name"],

+         ))

+     elif ".pagure." in msg["topic"]:

+         # Pagure

+         try:

+             project_name = pagure.msg2projectname(msg)

+         except KeyError:

+             pass

+         else:

+             hubs.extend(_get_group_hub_names_by_config(

+                 HubConfig.key == "pagure",

+                 HubConfig.value == project_name,

+             ))

+     elif ".github." in msg["topic"]:

+         # Github

+         try:

+             project_name = msg["msg"]["repository"]["full_name"]

+         except KeyError:

+             pass

+         else:

+             hubs.extend(_get_group_hub_names_by_config(

+                 HubConfig.key == "github",

+                 HubConfig.value == project_name,

+             ))

      return hubs

  

  

+ def _get_group_hub_names_by_config(*args):

+     query = Hub.query.filter(

+             Hub.user_hub == False,  # noqa:E712

+         ).join(HubConfig).filter(*args)

+     return [result[0] for result in query.values(Hub.name)]

+ 

+ 

  def on_new_notification(msg):

      """Only for FMN messages."""

      username = fedmsg.meta.msg2agent(msg)

file modified
+1 -1
@@ -201,7 +201,7 @@ 

                              # the config.

                              validated[key].append(v)

                              continue

-                         validated[key] = self.VALIDATORS[key](v)

+                         validated[key].append(self.VALIDATORS[key](v))

                  else:

                      if current_config[key] == value:

                          # optimization: don't validate if it's already in

@@ -48,7 +48,12 @@ 

      const stillLoading = (

            typeof this.props.hubConfig.calendar === "undefined"

          );

-     const invalid = this.props.error ? this.props.error.fields.calendar : null;

+ 

+     let invalid = null;

+     if (this.props.error && this.props.error.fields) {

+       invalid = this.props.error.fields.calendar;

+     }

+ 

      return (

        <form onSubmit={(e) => {e.preventDefault();}}>

          <FormattedMessage {...messages.title} tagName="h3" />

@@ -71,7 +71,10 @@ 

        );

      }

  

-     const invalid = this.props.error ? this.props.error.fields.chat_channel : null;

+     let invalid = null;

+     if (this.props.error && this.props.error.fields) {

+       invalid = this.props.error.fields.chat_channel;

+     }

  

      return (

        <form onSubmit={(e) => {e.preventDefault();}}>

@@ -170,7 +170,7 @@ 

                  }

                </tbody>

              </table>

-             { this.props.error && this.props.error.fields.devplatform_project &&

+             { this.props.error && this.props.error.fields && this.props.error.fields.devplatform_project &&

                <div className="text-danger">

                  {this.props.error.fields.devplatform_project}

                </div>

@@ -73,12 +73,14 @@ 

      const stillLoading = (typeof this.props.hubConfig.summary === "undefined");

      const visibilities = this.props.globalConfig.hub_visibility || [];

      const right_width = this.props.hubConfig ? 12 - this.props.hubConfig.left_width : 4;

+ 

      let invalid = {};

-     if (this.props.error) {

+     if (this.props.error && this.props.error.fields) {

        ["summary", "left_width", "visibility", "avatar"].forEach((key) => {

          invalid[key] = this.props.error.fields[key];

        });

      }

+ 

      return (

        <form onSubmit={(e) => {e.preventDefault();}}>

          <FormattedMessage {...messages.title} tagName="h3" />

@@ -48,7 +48,11 @@ 

      const stillLoading = (

            typeof this.props.hubConfig.mailing_list === "undefined"

          );

-     const invalid = this.props.error ? this.props.error.fields.mailing_list : null;

+ 

+     let invalid = null;

+     if (this.props.error && this.props.error.fields) {

+       invalid = this.props.error.fields.mailing_list;

+     }

  

      return (

        <form onSubmit={(e) => {e.preventDefault();}}>

@@ -28,7 +28,9 @@ 

      return (

        <div className="Feed">

          { (items.length == 0 && this.props.loaded) ?

-           <FormattedMessage {...messages.no_items} tagName="i" />

+           <p className="m-2">

+             <FormattedMessage {...messages.no_items} tagName="i" />

+           </p>

            :

            items

          }

empty or binary file added
hubs/tests/models/test_hub.py hubs/tests/test_models.py
file renamed
+1 -126
@@ -6,32 +6,7 @@ 

  from hubs.authz import AccessLevel

  

  

- class ModelTest(hubs.tests.APPTest):

- 

-     def test_delete_user(self):

-         # verify user exists

-         username = 'ralph'

-         user = hubs.models.User.get(username)

-         self.assertIsNotNone(user)

- 

-         # check if association exists

-         hub = hubs.models.Hub.get(username)

-         assoc = hubs.models.Association.get(hub, user, 'owner')

-         self.assertIsNotNone(assoc)

- 

-         # delete the user

-         self.session.delete(user)

-         user = hubs.models.User.get(username)

-         self.assertIsNone(user)

- 

-         # checking to see if the hub is still intact

-         hub = hubs.models.Hub.get(username)

-         self.assertIsNotNone(hub)

-         self.assertEqual('ralph', hub.name)

- 

-         # check if widgets still are intact

-         widgets = hubs.models.Widget.by_hub_id_all(hub.name)

-         self.assertEqual(11, len(widgets))

+ class HubTest(hubs.tests.APPTest):

  

      def test_delete_hubs(self):

          # verify the hub exists
@@ -69,27 +44,6 @@ 

          self.assertIsNotNone(user)

          self.assertEqual('ralph', user.username)

  

-     def test_delete_user_then_hubs(self):

-         username = 'ralph'

-         user = hubs.models.User.get(username)

-         self.assertIsNotNone(user)

-         self.session.delete(user)

-         user = hubs.models.User.get(username)

-         self.assertIsNone(user)

- 

-         # checking to see if the hub is still intact

-         hub = hubs.models.Hub.get(username)

-         self.assertIsNotNone(hub)

- 

-         self.session.delete(hub)

- 

-         # check if widgets are removed

-         widgets = hubs.models.Widget.by_hub_id_all(hub.name)

-         self.assertEqual([], widgets)

- 

-         hub = hubs.models.Hub.get(username)

-         self.assertIsNone(hub)

- 

      def test_auth_hub_widget_access_level(self):

          username = 'ralph'

          ralph = hubs.models.User.get(username)
@@ -150,30 +104,6 @@ 

              self.assertEqual(

                  widget._get_auth_user_roles(ralph), {"ralph": [role]})

  

-     def test_auth_widget_permission_name(self):

-         hub = hubs.models.Hub.get("ralph")

-         widget = hubs.models.Widget.query.filter_by(

-             hub=hub, plugin="contact").one()

-         self.assertEqual(

-             widget._get_auth_permission_name("view"), "hub.public.view")

-         hub.config["visibility"] = "private"

-         self.session.commit()

-         self.assertEqual(

-             widget._get_auth_permission_name("view"), "hub.private.view")

-         hub.config["visibility"] = "preview"

-         assert widget.visibility == "public"

-         self.assertEqual(

-             widget._get_auth_permission_name("view"), "widget.public.view")

-         widget.visibility = "restricted"

-         self.assertEqual(

-             widget._get_auth_permission_name("view"), "widget.restricted.view")

- 

-     def test_widget_enabled(self):

-         hub = hubs.models.Hub.get("ralph")

-         widget = hubs.models.Widget(hub=hub, plugin="does-not-exist")

-         self.session.add(widget)

-         self.assertFalse(widget.enabled)

- 

      def test_unsubscribe_owner(self):

          # Owners must be turned into regular members when unsubscribed.

          hub = hubs.models.Hub.query.get("infra")
@@ -184,58 +114,3 @@ 

          hub.unsubscribe(ralph, role="owner")

          self.assertNotIn(ralph, hub.owners)

          self.assertIn(ralph, hub.members)

- 

- 

- class ModelBookmarksTest(hubs.tests.APPTest):

- 

-     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))

- 

-     def test_user_bookmarks(self):

-         """

-         test that when we add bookmarks they show up.

-         when adding bookmarks for different hubs, we should

-         see them all in the result.

-         """

-         commops = hubs.models.Hub(name="commops")

-         self.session.add(commops)

-         self._add_assoc("infra", "ralph", "stargazer")

-         self._add_assoc("i18n", "ralph", "member")

-         self._add_assoc("commops", "ralph", "subscriber")

-         ralph = hubs.models.User.query.get("ralph")

-         self.assertEquals(len(ralph.bookmarks["starred"]), 1)

-         self.assertEquals(ralph.bookmarks["starred"][0].name, "infra")

-         self.assertEquals(len(ralph.bookmarks["memberships"]), 1)

-         self.assertEquals(ralph.bookmarks["memberships"][0].name, "i18n")

-         self.assertEquals(len(ralph.bookmarks["subscriptions"]), 1)

-         self.assertEquals(ralph.bookmarks["subscriptions"][0].name, "commops")

- 

-     def test_user_bookmarks_star(self):

-         """

-         test that when when adding associations for the same hub,

-         we should just see the stargazer one.

-         """

-         self._add_assoc("infra", "ralph", "stargazer")

-         self._add_assoc("infra", "ralph", "member")

-         self._add_assoc("infra", "ralph", "subscriber")

-         ralph = hubs.models.User.query.get("ralph")

-         self.assertEquals(len(ralph.bookmarks["starred"]), 1)

-         self.assertEquals(ralph.bookmarks["starred"][0].name, "infra")

-         self.assertEquals(len(ralph.bookmarks["memberships"]), 0)

-         self.assertEquals(len(ralph.bookmarks["subscriptions"]), 0)

- 

-     def test_user_bookmarks_memberships(self):

-         """

-         test that when when adding associations for the same hub,

-         we should just see the memberships one.

-         """

-         self._add_assoc("infra", "ralph", "member")

-         self._add_assoc("infra", "ralph", "subscriber")

-         ralph = hubs.models.User.query.get("ralph")

-         self.assertEquals(len(ralph.bookmarks["starred"]), 0)

-         self.assertEquals(len(ralph.bookmarks["memberships"]), 1)

-         self.assertEquals(ralph.bookmarks["memberships"][0].name, "infra")

-         self.assertEquals(len(ralph.bookmarks["subscriptions"]), 0)

@@ -0,0 +1,19 @@ 

+ from __future__ import unicode_literals

+ 

+ from mock import patch

+ 

+ import hubs

+ import hubs.models

+ import hubs.tests

+ 

+ 

+ class HubConfigTest(hubs.tests.APPTest):

+ 

+     @patch.object(hubs.models.hubconfig.HubConfigProxy, "VALIDATORS",

+                   {"pagure": lambda v: v})

+     def test_validate_list(self):

+         hub = hubs.models.Hub.get("ralph")

+         self.assertEqual(

+             hub.config.validate({"pagure": ["testrepo"]}),

+             {"pagure": ["testrepo"]}

+         )

@@ -0,0 +1,88 @@ 

+ from __future__ import unicode_literals

+ 

+ import hubs

+ import hubs.models

+ import hubs.tests

+ 

+ 

+ class UserTest(hubs.tests.APPTest):

+ 

+     def test_delete_user(self):

+         # verify user exists

+         username = 'ralph'

+         user = hubs.models.User.get(username)

+         self.assertIsNotNone(user)

+ 

+         # check if association exists

+         hub = hubs.models.Hub.get(username)

+         assoc = hubs.models.Association.get(hub, user, 'owner')

+         self.assertIsNotNone(assoc)

+ 

+         # delete the user

+         self.session.delete(user)

+         user = hubs.models.User.get(username)

+         self.assertIsNone(user)

+ 

+         # checking to see if the hub is still intact

+         hub = hubs.models.Hub.get(username)

+         self.assertIsNotNone(hub)

+         self.assertEqual('ralph', hub.name)

+ 

+         # check if widgets still are intact

+         widgets = hubs.models.Widget.by_hub_id_all(hub.name)

+         self.assertEqual(11, len(widgets))

+ 

+ 

+ class BookmarksTest(hubs.tests.APPTest):

+ 

+     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))

+ 

+     def test_user_bookmarks(self):

+         """

+         test that when we add bookmarks they show up.

+         when adding bookmarks for different hubs, we should

+         see them all in the result.

+         """

+         commops = hubs.models.Hub(name="commops")

+         self.session.add(commops)

+         self._add_assoc("infra", "ralph", "stargazer")

+         self._add_assoc("i18n", "ralph", "member")

+         self._add_assoc("commops", "ralph", "subscriber")

+         ralph = hubs.models.User.query.get("ralph")

+         self.assertEquals(len(ralph.bookmarks["starred"]), 1)

+         self.assertEquals(ralph.bookmarks["starred"][0].name, "infra")

+         self.assertEquals(len(ralph.bookmarks["memberships"]), 1)

+         self.assertEquals(ralph.bookmarks["memberships"][0].name, "i18n")

+         self.assertEquals(len(ralph.bookmarks["subscriptions"]), 1)

+         self.assertEquals(ralph.bookmarks["subscriptions"][0].name, "commops")

+ 

+     def test_user_bookmarks_star(self):

+         """

+         test that when when adding associations for the same hub,

+         we should just see the stargazer one.

+         """

+         self._add_assoc("infra", "ralph", "stargazer")

+         self._add_assoc("infra", "ralph", "member")

+         self._add_assoc("infra", "ralph", "subscriber")

+         ralph = hubs.models.User.query.get("ralph")

+         self.assertEquals(len(ralph.bookmarks["starred"]), 1)

+         self.assertEquals(ralph.bookmarks["starred"][0].name, "infra")

+         self.assertEquals(len(ralph.bookmarks["memberships"]), 0)

+         self.assertEquals(len(ralph.bookmarks["subscriptions"]), 0)

+ 

+     def test_user_bookmarks_memberships(self):

+         """

+         test that when when adding associations for the same hub,

+         we should just see the memberships one.

+         """

+         self._add_assoc("infra", "ralph", "member")

+         self._add_assoc("infra", "ralph", "subscriber")

+         ralph = hubs.models.User.query.get("ralph")

+         self.assertEquals(len(ralph.bookmarks["starred"]), 0)

+         self.assertEquals(len(ralph.bookmarks["memberships"]), 1)

+         self.assertEquals(ralph.bookmarks["memberships"][0].name, "infra")

+         self.assertEquals(len(ralph.bookmarks["subscriptions"]), 0)

@@ -0,0 +1,32 @@ 

+ from __future__ import unicode_literals

+ 

+ import hubs

+ import hubs.models

+ import hubs.tests

+ 

+ 

+ class WidgetTest(hubs.tests.APPTest):

+ 

+     def test_auth_widget_permission_name(self):

+         hub = hubs.models.Hub.get("ralph")

+         widget = hubs.models.Widget.query.filter_by(

+             hub=hub, plugin="contact").one()

+         self.assertEqual(

+             widget._get_auth_permission_name("view"), "hub.public.view")

+         hub.config["visibility"] = "private"

+         self.session.commit()

+         self.assertEqual(

+             widget._get_auth_permission_name("view"), "hub.private.view")

+         hub.config["visibility"] = "preview"

+         assert widget.visibility == "public"

+         self.assertEqual(

+             widget._get_auth_permission_name("view"), "widget.public.view")

+         widget.visibility = "restricted"

+         self.assertEqual(

+             widget._get_auth_permission_name("view"), "widget.restricted.view")

+ 

+     def test_widget_enabled(self):

+         hub = hubs.models.Hub.get("ralph")

+         widget = hubs.models.Widget(hub=hub, plugin="does-not-exist")

+         self.session.add(widget)

+         self.assertFalse(widget.enabled)

file modified
+201 -14
@@ -120,20 +120,6 @@ 

          # User does not exist, no feed instance should have been created.

          mock_notifications.assert_not_called()

  

-     @patch("hubs.feed.fedmsg.meta.msg2usernames")

-     def test_get_hubs_for_msg(self, msg2usernames):

-         ralph = User.query.get("ralph")

-         infra = Hub.query.get("infra")

-         test_hub = Hub(name="testhub")

-         self.session.add(test_hub)

-         self.session.add(Association(hub=test_hub, user=ralph, role="member"))

-         self.session.add(Association(hub=infra, user=ralph, role="owner"))

-         msg2usernames.return_value = ["unknown_user", "ralph"]

-         self.assertListEqual(

-             sorted(get_hubs_for_msg({"msg_id": "testmsg"})),

-             ["infra", "ralph", "testhub"]

-             )

- 

      def test_add_dom_id(self):

          msg = {

              "msg_ids": {
@@ -168,3 +154,204 @@ 

              result["markup_subjective"],

              """your ticket was commented by <a href="/decause/">decause</a>"""

              )

+ 

+ 

+ class GetHubsForMsgTestCase(APPTest):

+ 

+     # See: http://fedora-fedmsg.readthedocs.io/en/latest/topics.html

+ 

+     def setUp(self):

+         super(GetHubsForMsgTestCase, self).setUp()

+         self.msg2usernames_patcher = patch(

+             "hubs.feed.fedmsg.meta.msg2usernames")

+         self.msg2usernames = self.msg2usernames_patcher.start()

+         self.msg2usernames.return_value = []

+         self.dummy_msg = {"msg_id": "testmsg", "topic": "testtopic"}

+ 

+     def tearDown(self):

+         self.msg2usernames_patcher.stop()

+         super(GetHubsForMsgTestCase, self).tearDown()

+ 

+     def test_unknown_user(self):

+         self.msg2usernames.return_value = ["unknown_user"]

+         self.assertListEqual(get_hubs_for_msg(self.dummy_msg), [])

+ 

+     def test_user_hub_owner(self):

+         self.msg2usernames.return_value = ["ralph"]

+         self.assertListEqual(

+             get_hubs_for_msg(self.dummy_msg), ["ralph"])

+ 

+     def test_group_hub_owner(self):

+         # Don't send a message to a group hub just because the user is the

+         # owner.

+         ralph = User.query.get("ralph")

+         infra = Hub.query.get("infra")

+         self.session.add(Association(hub=infra, user=ralph, role="owner"))

+         self.msg2usernames.return_value = ["ralph"]

+         self.assertListEqual(

+             get_hubs_for_msg(self.dummy_msg), ["ralph"])

+ 

+     def test_group_hub_member(self):

+         ralph = User.query.get("ralph")

+         test_hub = Hub(name="testhub", user_hub=False)

+         self.session.add(test_hub)

+         self.session.add(Association(hub=test_hub, user=ralph, role="member"))

+         self.msg2usernames.return_value = ["ralph"]

+         self.assertListEqual(

+             get_hubs_for_msg(self.dummy_msg), ["ralph"])

+ 

+     def test_group_hub_irc(self):

+         test_hub = Hub(name="testhub", user_hub=False)

+         self.session.add(test_hub)

+         test_hub.config["chat_network"] = "irc.freenode.net"

+         test_hub.config["chat_channel"] = "testchannel"

+         messages = [{

+             "msg_id": "testmsg",

+             "topic": "org.fedoraproject.prod.meetbot.meeting.start",

+             "msg": {

+                 "channel": "testchannel",

+                 },

+             }, {

+             "msg_id": "testmsg",

+             "topic": "org.fedoraproject.prod.meetbot.meeting.topic.update",

+             "msg": {

+                 "channel": "testchannel",

+                 },

+             }, {

+             "msg_id": "testmsg",

+             "topic": "org.fedoraproject.prod.meetbot.meeting.item.link",

+             "msg": {

+                 "channel": "testchannel",

+                 },

+             }, {

+             "msg_id": "testmsg",

+             "topic": "org.fedoraproject.prod.meetbot.meeting.item.help",

+             "msg": {

+                 "channel": "testchannel",

+                 },

+             }, {

+             "msg_id": "testmsg",

+             "topic": "org.fedoraproject.prod.meetbot.meeting.complete",

+             "msg": {

+                 "channel": "testchannel",

+                 },

+             }]

+         for msg in messages:

+             self.assertListEqual(get_hubs_for_msg(msg), ["testhub"])

+ 

+     def test_group_hub_mailinglist(self):

+         test_hub = Hub(name="testhub", user_hub=False)

+         self.session.add(test_hub)

+         test_hub.config["mailing_list"] = "testlist@lists.fpo"

+         msg = {

+             "msg_id": "testmsg",

+             "topic": "org.fedoraproject.prod.mailman.receive",

+             "msg": {

+                 "mlist": {"list_name": "testlist"},

+             },

+         }

+         self.assertListEqual(get_hubs_for_msg(msg), ["testhub"])

+ 

+     def test_group_hub_calendar(self):

+         test_hub = Hub(name="testhub", user_hub=False)

+         self.session.add(test_hub)

+         test_hub.config["calendar"] = "testcal"

+         topics = [

+             "calendar.clear", "calendar.delete", "calendar.new",

+             "calendar.update", "calendar.upload", "meeting.delete",

+             "meeting.new", "meeting.reminder", "meeting.update",

+             ]

+         for topic in topics:

+             msg = {

+                 "msg_id": "testmsg",

+                 "topic": "org.fedoraproject.prod.fedocal.{}".format(topic),

+                 "msg": {

+                     "calendar": {"calendar_name": "testcal"},

+                     },

+                 }

+             self.assertListEqual(get_hubs_for_msg(msg), ["testhub"])

+ 

+     def test_group_hub_pagure(self):

+         test_hub = Hub(name="testhub", user_hub=False)

+         self.session.add(test_hub)

+         projects_ok = [

+             "testproject-1",

+             "testproject-2",

+             "namespace/testproject-3",

+         ]

+         projects_fail = [

+             "testproject-3",

+             "testproject-4",

+             "namespace/testproject-1",

+         ]

+         test_hub.config["pagure"] = projects_ok

+ 

+         def _do_test_project(project, expected):

+             msg = {

+                 "msg_id": "testmsg",

+                 "topic": "io.pagure.prod.pagure.commit.flag.added",

+                 "msg": {

+                     "repo": {"fullname": project},

+                 },

+             }

+             self.assertListEqual(get_hubs_for_msg(msg), expected)

+             msg = {

+                 "msg_id": "testmsg",

+                 "topic": "io.pagure.prod.pagure.issue.assigned.added",

+                 "msg": {

+                     "project": {"fullname": project},

+                 },

+             }

+             self.assertListEqual(get_hubs_for_msg(msg), expected)

+             msg = {

+                 "msg_id": "testmsg",

+                 "topic": "io.pagure.prod.pagure.pull-request.closed",

+                 "msg": {

+                     "pullrequest": {"project": {"fullname": project}},

+                 },

+             }

+             self.assertListEqual(get_hubs_for_msg(msg), expected)

+         for project in projects_ok:

+             _do_test_project(project, ["testhub"])

+         for project in projects_fail:

+             _do_test_project(project, [])

+         # Handle new and/or differently formatted messages

+         msg = {

+             "msg_id": "testmsg",

+             "topic": "io.pagure.prod.pagure.dummy",

+             "msg": {},

+         }

+         self.assertListEqual(get_hubs_for_msg(msg), [])

+ 

+     def test_group_hub_github(self):

+         test_hub = Hub(name="testhub", user_hub=False)

+         self.session.add(test_hub)

+         projects_ok = [

+             "testgroup/testproject-1",

+             "testgroup/testproject-2",

+         ]

+         projects_fail = [

+             "testgroup/testproject-3",

+             "othergroup/testproject-1",

+         ]

+         test_hub.config["github"] = projects_ok

+ 

+         def _do_test_project(project, expected):

+             msg = {

+                 "msg_id": "testmsg",

+                 "topic": "org.fedoraproject.prod.github.commit_comment",

+                 "msg": {

+                     "repository": {"full_name": project},

+                 },

+             }

+             self.assertListEqual(get_hubs_for_msg(msg), expected)

+         for project in projects_ok:

+             _do_test_project(project, ["testhub"])

+         for project in projects_fail:

+             _do_test_project(project, [])

+         msg = {

+             "msg_id": "testmsg",

+             "topic": "org.fedoraproject.prod.github.webhook",

+             "msg": {},

+         }

+         self.assertListEqual(get_hubs_for_msg(msg), [])

@@ -26,8 +26,10 @@ 

          msg = {

              'topic': 'tests.pagure.pull-request.new',

              'msg': {

-                 "project": {

-                     "name": "fedora-hubs",

+                 "pullrequest": {

+                     "project": {

+                         "name": "fedora-hubs",

+                     },

                  },

              },

          }
@@ -35,8 +37,10 @@ 

          msg = {

              'topic': 'tests.pagure.pull-request.closed',

              'msg': {

-                 "project": {

-                     "name": "fedora-hubs",

+                 "pullrequest": {

+                     "project": {

+                         "name": "fedora-hubs",

+                     },

                  },

              },

          }
@@ -46,8 +50,10 @@ 

          msg = {

              'topic': 'tests.pagure.pull-request.new',

              'msg': {

-                 "project": {

-                     "name": "not-fedora-hubs",

+                 "pullrequest": {

+                     "project": {

+                         "name": "not-fedora-hubs",

+                     },

                  },

              },

          }

file added
+13
@@ -0,0 +1,13 @@ 

+ from __future__ import unicode_literals

+ 

+ 

+ PAGURE_URL = "https://pagure.io"

+ 

+ 

+ def msg2projectname(msg):

+     # Thanks Pagure for this very coherent API.

+     if ".pagure.commit.flag." in msg["topic"]:

+         return msg["msg"]["repo"]["fullname"]

+     if "pagure.pull-request" in msg["topic"]:

+         return msg["msg"]["pullrequest"]["project"]["fullname"]

+     return msg["msg"]["project"]["fullname"]

file modified
+8 -4
@@ -17,6 +17,7 @@ 

  import six

  

  from hubs.utils.github import github_org_is_valid, github_repo_is_valid

+ from hubs.utils.pagure import PAGURE_URL

  

  

  def Noop(value):
@@ -108,10 +109,13 @@ 

  

  def PagureRepo(value):

      """Fails if the Pagure repository name does not exist."""

-     response = requests.get("https://pagure.io/%s" % value, timeout=5)

-     if response.ok:

-         return value

-     raise ValueError('Invalid Pagure repo: {}'.format(value))

+     try:

+         response = requests.get("/".join([PAGURE_URL, value]), timeout=5)

+     except requests.exceptions.ReadTimeout:

+         raise ValueError("Could not connect to Pagure, please try again.")

+     if not response.ok:

+         raise ValueError('Invalid Pagure repo: {}'.format(value))

+     return value

  

  

  def CommaSeparatedList(value):

@@ -1,14 +1,12 @@ 

  from __future__ import unicode_literals

  

- from hubs.utils import validators

+ from hubs.utils import validators, pagure

  from hubs.widgets.base import Widget

  from hubs.widgets.view import RootWidgetView

  from hubs.widgets.caching import CachedFunction

  

  import requests

  

- pagure_url = "https://pagure.io/api/0"

- 

  # TODO: use a checkbox set to select which repos to use from the hub's

  # configuration.

  
@@ -43,7 +41,7 @@ 

  

      def execute(self):

          repo = self.instance.config["repo"]

-         url = '/'.join([pagure_url, repo, "pull-requests"])

+         url = '/'.join([pagure.PAGURE_URL, "api", "0", repo, "pull-requests"])

          response = requests.get(url)

          try:

              data = response.json()
@@ -79,7 +77,7 @@ 

             and ".pagure.pull-request.closed" not in message["topic"]):

              return False

          try:

-             project = message['msg']['project']['name']

+             project = message['msg']['pullrequest']['project']['name']

          except KeyError:

              return False

          return (project == self.instance.config['repo'])

@@ -2,13 +2,11 @@ 

  

  import requests

  

- from hubs.utils import validators

+ from hubs.utils import validators, pagure

  from hubs.widgets.base import Widget

  from hubs.widgets.view import RootWidgetView

  from hubs.widgets.caching import CachedFunction

  

- pagure_url = "https://pagure.io/api/0"

- 

  # TODO: use a checkbox set to select which repos to use from the hub's

  # configuration.

  
@@ -46,7 +44,7 @@ 

      def execute(self):

          repo = self.instance.config["repo"]

  

-         url = '/'.join([pagure_url, repo, "issues"])

+         url = '/'.join([pagure.PAGURE_URL, "api", "0", repo, "issues"])

          issue_response = requests.get(url)

          data = issue_response.json()

          total = data['total_issues']