1# Copyright 2013-2016 The Distro Tracker Developers
2# See the COPYRIGHT file at the top-level directory of this distribution and
3# at https://deb.li/DTAuthors
4#
5# This file is part of Distro Tracker. It is subject to the license terms
6# in the LICENSE file found in the top-level directory of this
7# distribution and at https://deb.li/DTLicense. No part of Distro Tracker,
8# including this file, may be copied, modified, propagated, or distributed
9# except according to the terms contained in the LICENSE file.
10"""
11Implements a management command which adds a new keyword.
12"""
13from django.core.management.base import BaseCommand, CommandError
14from django.db import transaction
16from distro_tracker.core.models import (
17 EmailSettings,
18 Keyword,
19 Subscription,
20 UserEmail
21)
22from distro_tracker.core.utils import get_or_none
25class Command(BaseCommand):
26 """
27 A management command that adds a new keyword.
29 It supports simply adding a new keyword and allowing users to add it to
30 their subscriptions or to automatically add it to users' lists that
31 already contain a different keyword (given as a parameter to the command).
32 """
33 help = ("Add a new keyword.\n." # noqa
34 "The command supports simply adding a new keyword and allowing"
35 " users to add it to their subscriptions or to automatically add"
36 " it to users' lists that already contain a different keyword"
37 " (given as a parameter to the command).")
39 def add_arguments(self, parser):
40 parser.add_argument('keyword')
41 parser.add_argument('existing_keyword', nargs='?', default=None)
42 parser.add_argument(
43 '--set-default',
44 action='store_true',
45 dest='is_default_keyword',
46 default=False,
47 help='Make the new keyword a default one'
48 )
50 def warning(self, msg, *args):
51 if self.verbose > 1:
52 text = msg % args
53 self.stdout.write("Warning: {text}".format(text=text))
55 def add_keyword_to_user_defaults(self, keyword, user_set):
56 """
57 Adds the given ``keyword`` to the
58 :py:attr:`default_keywords
59 <distro_tracker.core.models.EmailSettings.default_keywords>`
60 list of each user found in the given QuerySet ``user_set``.
62 :param keyword: The keyword which should be added to all the users'
63 :py:attr:`default_keywords
64 <distro_tracker.core.models.EmailSettings.default_keywords>`
65 :type keyword: :py:class:`Keyword <distro_tracker.core.models.Keyword>`
67 :param user_set: The set of users to which the given keyword should be
68 added as a default keyword.
69 :type user_set: :py:class:`QuerySet <django.db.models.query.QuerySet>`
70 or other iterable of
71 :py:class:`UserEmail <distro_tracker.core.models.UserEmail>`
72 instances
73 """
74 for user_email in user_set:
75 email_settings, _ = \
76 EmailSettings.objects.get_or_create(user_email=user_email)
77 email_settings.default_keywords.add(keyword)
79 def add_keyword_to_subscriptions(self, new_keyword, existing_keyword):
80 """
81 Adds the given ``new_keyword`` to each
82 :py:class:`Subscription <distro_tracker.core.models.Subscription>`'s
83 keywords list which already contains the ``existing_keyword``.
85 :param new_keyword: The keyword to add to the
86 :py:class:`Subscription <distro_tracker.core.models.Subscription>`'s
87 keywords
88 :type new_keyword:
89 :py:class:`Keyword <distro_tracker.core.models.Keyword>`
91 :param existing_keyword: The keyword or name of the keyword based on
92 which all
93 :py:class:`Subscription <distro_tracker.core.models.Subscription>`
94 to which the ``new_keyword`` should be added are chosen.
95 :type existing_keyword:
96 :py:class:`Keyword <distro_tracker.core.models.Keyword>`
97 or string
98 """
99 if not isinstance(existing_keyword, Keyword): 99 ↛ 105line 99 didn't jump to line 105, because the condition on line 99 was never false
100 existing_keyword = get_or_none(Keyword, name=existing_keyword)
101 if not existing_keyword:
102 raise CommandError("Given keyword does not exist. "
103 "No actions taken.")
105 self.add_keyword_to_user_defaults(
106 new_keyword,
107 UserEmail.objects.filter(
108 emailsettings__default_keywords=existing_keyword)
109 )
110 for subscription in Subscription.objects.all():
111 if existing_keyword in subscription.keywords.all():
112 if subscription._use_user_default_keywords: 112 ↛ 115line 112 didn't jump to line 115, because the condition on line 112 was never true
113 # Skip these subscriptions since the keyword was already
114 # added to user's default lists.
115 continue
116 else:
117 subscription.keywords.add(new_keyword)
119 @transaction.atomic
120 def handle(self, *args, **kwargs):
121 self.verbose = int(kwargs.get('verbosity', 1)) > 1
122 keyword = kwargs['keyword']
123 if not keyword: 123 ↛ 124line 123 didn't jump to line 124, because the condition on line 123 was never true
124 raise CommandError("The name of the new keyword must be given")
126 default = kwargs['is_default_keyword']
127 keyword, created = Keyword.objects.get_or_create(
128 name=keyword,
129 defaults={
130 'default': default,
131 }
132 )
134 if not created: 134 ↛ 135line 134 didn't jump to line 135, because the condition on line 134 was never true
135 self.warning("The given keyword already exists")
136 return
138 if default:
139 self.add_keyword_to_user_defaults(
140 keyword,
141 UserEmail.objects.exclude(emailsettings__isnull=True)
142 )
144 if kwargs['existing_keyword'] is not None:
145 # Add the new keyword to all subscribers and subscriptions which
146 # contain the parameter keyword
147 other_keyword = kwargs['existing_keyword']
148 self.add_keyword_to_subscriptions(keyword, other_keyword)
150 if self.verbose: 150 ↛ 151line 150 didn't jump to line 151, because the condition on line 150 was never true
151 self.stdout.write('Successfully added new keyword {keyword}'.format(
152 keyword=keyword))