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 

15 

16from distro_tracker.core.models import ( 

17 EmailSettings, 

18 Keyword, 

19 Subscription, 

20 UserEmail 

21) 

22from distro_tracker.core.utils import get_or_none 

23 

24 

25class Command(BaseCommand): 

26 """ 

27 A management command that adds a new keyword. 

28 

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

38 

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 ) 

49 

50 def warning(self, msg, *args): 

51 if self.verbose > 1: 

52 text = msg % args 

53 self.stdout.write("Warning: {text}".format(text=text)) 

54 

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``. 

61 

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

66 

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) 

78 

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``. 

84 

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

90 

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

104 

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) 

118 

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

125 

126 default = kwargs['is_default_keyword'] 

127 keyword, created = Keyword.objects.get_or_create( 

128 name=keyword, 

129 defaults={ 

130 'default': default, 

131 } 

132 ) 

133 

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 

137 

138 if default: 

139 self.add_keyword_to_user_defaults( 

140 keyword, 

141 UserEmail.objects.exclude(emailsettings__isnull=True) 

142 ) 

143 

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) 

149 

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