123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210 |
- import celery
- import json
- import pagure
- import rdflib
- from .. import activitypub
- from .. import model
- from .. import settings
- from . import broker
- from . import broker_url
- from . import database_session
- log = celery.utils.log.get_task_logger(__name__)
- log.setLevel(settings.LOG_LEVEL)
- # The following is a decorator that accepts a Pagure notification ID as input,
- # for example "issue.new", and adds it to _USER_ACTIONS_ together with the
- # decorated function. _USER_ACTIONS_ is a dictionary mapping Pagure notification
- # IDs to a function to be executed when a new notification is received.
- _USER_ACTIONS_ = {}
- def action(notification_id):
- def closure(func):
-
- def decorator(*args, **kwargs):
- func(*args, **kwargs)
-
- global _USER_ACTIONS_
- _USER_ACTIONS_[notification_id] = decorator
-
- return decorator
- return closure
- @broker.task
- def handle_pagure_signal(notification_id, message):
- """
- This task receives notifications from Pagure about events that happen on
- the instance, creates a new activity, and schedules their delivery.
- """
-
- if notification_id not in _USER_ACTIONS_:
- log.debug('Unhandled user action {}.'.format(notification_id))
- return
-
- log.debug('New Pagure notification: {}\n{}'.format(notification_id,
- json.dumps(message, indent=4, sort_keys=True)))
-
- with database_session() as database:
-
- # Handle the user action
- return _USER_ACTIONS_[notification_id](database, message)
- @action('issue.new')
- def new_issue(database, message):
- """
- A user has created a new Issue.
- """
- person = database \
- .query(model.Person) \
- .filter(model.Person.user == message['issue']['user']['name']) \
- .one_or_none()
-
- project = database \
- .query(model.Project) \
- .filter(model.Project.id == message['project']['id']) \
- .one_or_none()
-
- issue = database \
- .query(pagure.lib.model.Issue) \
- .filter(pagure.lib.model.Issue.id == message['issue']['id'],
- pagure.lib.model.Issue.project_id == message['project']['id']) \
- .one_or_none()
-
- # This should never raise an error otherwise there's a bug in Pagure
- assert person and issue and project, \
- "User, Issue, or Project doesn't exist."
-
- # Check if this tracker is only used to interact with a remote one
- same_as = database.query(database.SameAs) \
- .filter(database.SameAs.local_uri == project.local_uri) \
- .one_or_none()
-
- if same_as:
- log.debug('Sending new issue to remote tracker...')
-
- ticket = database \
- .query(model.Ticket) \
- .filter(model.Ticket.id == issue.id,
- model.Ticket.project_id == issue.project_id) \
- .one_or_none()
-
- # Offer a new ticket to the remote tracker
- # person.offer(ticket.jsonld, to=same_as.remote_uri)
- @action('issue.comment.added')
- def new_issue_comment(database, message):
- # A user has commented on an issue
-
- # The Pagure notification contains *all* the comments of the issue
- # in an ordered list, so we extract the last one from the list of
- # comments.
- comment = pagure_db \
- .query(model.TicketComment) \
- .filter(model.TicketComment.id == message['issue']['comments'][-1]['id']) \
- .one_or_none()
-
- person = pagure_db \
- .query(model.Person) \
- .filter(model.Person.id == comment.user.id) \
- .one_or_none()
-
- project = pagure_db \
- .query(model.Project) \
- .filter(model.Project.id == message['project']['id']) \
- .one_or_none()
-
- # Our local ticket
- ticket = pagure_db \
- .query(model.Ticket) \
- .filter(model.Ticket.id == message['issue']['id'],
- model.Ticket.project_id == message['project']['id']) \
- .one_or_none()
-
- # Check if this tracker is only used to interact with a remote one
- same_as = forgefed_db.query(database.SameAs) \
- .filter(database.SameAs.local_uri == project.local_uri) \
- .one_or_none()
-
- if same_as:
- log.debug('Sending new comment to remote tracker...')
-
- assert ticket.remote_uri, 'Ticket not linked to remote ticket.'
-
- # Notify the remote tracker about the new comment
- person.create(comment.jsonld, to=same_as.remote_uri)
-
- else:
- log.debug('Not a remote tracker. Will send new comment to tracker followers '
- + 'and watchers.')
-
- # Retrieve the pagure "watchlist"
- watchlist = pagure.lib.query.get_watch_list(pagure_db, ticket)
- actors = []
-
- for username in watchlist:
- actor = pagure_db \
- .query(model.Person) \
- .filter(model.Person.user == username) \
- .one_or_none()
-
- actors.append(actor.uri)
-
- # Send the Activity
- person.create(comment.jsonld, to=actors)
- @action('issue.edit')
- def edit_issue(database, message):
- if topic == 'issue.edit' \
- and 'status' in message['fields'] \
- and message['issue']['status'].upper() == 'CLOSED':
- # A user has closed an issue
-
- # The Ticket that was modified
- ticket = pagure_db \
- .query(model.Ticket) \
- .filter(model.Ticket.id == message['issue']['id'],
- model.Ticket.project_id == message['project']['id']) \
- .one_or_none()
-
- # The user that edited the Ticket
- person = pagure_db \
- .query(model.Person) \
- .filter(model.Person.user == message['agent']) \
- .one_or_none()
-
- project = pagure_db \
- .query(model.Project) \
- .filter(model.Project.id == message['project']['id']) \
- .one_or_none()
-
- # If the user has edited the Ticket of a remote tracker, we just
- # send the Activity to the tracker
- if ticket.is_remote:
- log.debug('Local user has closed the remote Ticket {}'.format(ticket.uri))
-
- person.resolve(ticket.uri, to=project.remote_uri)
-
- # otherwise we send the Activity to the Tickets' watchlist
- else:
- log.debug('Local user has closed the local Ticket {}'.format(ticket.uri))
-
- # Retrieve the pagure "watchlist"
- watchlist = pagure.lib.query.get_watch_list(pagure_db, ticket)
- actors = []
-
- for username in watchlist:
- actor = pagure_db \
- .query(model.Person) \
- .filter(model.Person.user == username) \
- .one_or_none()
-
- actors.append(actor.uri)
-
- # Send the Activity
- person.resolve(ticket.uri, to=actors)
|