Test Setup Failed
Push — develop ( e459d6...12ef70 )
by Dean
02:19
created

UpdateAccount.from_dict()   F

Complexity

Conditions 11

Size

Total Lines 83

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 1
CRAP Score 121.6384
Metric Value
cc 11
dl 0
loc 83
ccs 1
cts 34
cp 0.0294
crap 121.6384
rs 3.1764

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

Complexity

Complex classes like UpdateAccount.from_dict() often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

1 1
from plugin.managers.core.base import Manager, Update
2 1
from plugin.managers.core.exceptions import TraktAccountExistsException
3 1
from plugin.managers.m_trakt.credential import TraktOAuthCredentialManager, TraktBasicCredentialManager
4 1
from plugin.models import TraktAccount, TraktOAuthCredential, TraktBasicCredential
5
6 1
from trakt import Trakt
7 1
import apsw
8 1
import inspect
9 1
import logging
10 1
import peewee
11
12
13 1
log = logging.getLogger(__name__)
14
15
16 1
class UpdateAccount(Update):
17 1
    keys = ['username']
18
19 1
    def from_dict(self, t_account, changes):
20
        # Resolve `account`
21
        if inspect.isfunction(t_account):
22
            t_account = t_account()
23
24
        # Update `TraktAccount`
25
        if not super(UpdateAccount, self).from_dict(t_account, changes):
26
            return False
27
28
        # Update credentials
29
        authorization = changes.get('authorization', {})
30
31
        if 'username' in changes:
32
            # Provide username change in basic authorization update
33
            if 'basic' not in authorization:
34
                authorization['basic'] = {}
35
36
            authorization['basic']['username'] = changes['username']
37
38
        # Retrieve `TraktBasicCredential`
39
        t_account.basic = TraktBasicCredentialManager.get.or_create(
40
            TraktBasicCredential.account == t_account,
41
            account=t_account
42
        )
43
44
        # Update `TraktBasicCredential` (if there are changes)
45
        if 'basic' in authorization:
46
            TraktBasicCredentialManager.update.from_dict(
47
                t_account.basic,
48
                authorization['basic'],
49
                save=False
50
            )
51
52
        # Retrieve `TraktOAuthCredential`
53
        t_account.oauth = TraktOAuthCredentialManager.get.or_create(
54
            TraktOAuthCredential.account == t_account,
55
            account=t_account
56
        )
57
58
        # Update `TraktOAuthCredential` (if there are changes)
59
        if 'oauth' in authorization:
60
            TraktOAuthCredentialManager.update.from_dict(
61
                t_account.oauth,
62
                authorization['oauth'],
63
                save=False
64
            )
65
66
        # Validate the account authorization
67
        with t_account.authorization().http(retry=True):
68
            settings = Trakt['users/settings'].get()
69
70
        if not settings:
71
            log.warn('Unable to retrieve account details for authorization')
72
            return None
73
74
        # Update `TraktAccount` username
75
        try:
76
            self.update_username(t_account, settings)
77
        except (apsw.ConstraintError, peewee.IntegrityError), ex:
78
            log.debug('Trakt account already exists - %s', ex, exc_info=True)
79
80
            raise TraktAccountExistsException('Trakt account already exists')
81
82
        # Refresh `TraktAccount`
83
        t_account.refresh(
84
            force=True,
85
            settings=settings
86
        )
87
88
        # Save credentials
89
        if 'basic' in authorization:
90
            t_account.basic.save()
91
92
        if 'oauth' in authorization:
93
            t_account.oauth.save()
94
95
        # Refresh `Account`
96
        t_account.account.refresh(
97
            force=True
98
        )
99
100
        log.info('Updated account authorization for %r', t_account)
101
        return True
102
103 1
    def from_pin(self, t_account, pin):
104
        if not pin:
105
            log.debug('"pin" parameter is empty, ignoring account authorization update')
106
            return t_account
107
108
        # Retrieve current account `OAuthCredential`
109
        oauth = t_account.oauth_credentials.first()
110
111
        if oauth and oauth.code == pin:
112
            log.debug("PIN hasn't changed, ignoring account authorization update")
113
            return t_account
114
115
        if not oauth:
116
            # Create new `OAuthCredential` for the account
117
            oauth = TraktOAuthCredential(
118
                account=t_account
119
            )
120
121
        # Update `OAuthCredential`
122
        if not TraktOAuthCredentialManager.update.from_pin(oauth, pin, save=False):
123
            log.warn("Unable to update OAuthCredential (token exchange failed, hasn't changed, etc..)")
124
            return None
125
126
        # Validate the account authorization
127
        with t_account.oauth_authorization(oauth).http(retry=True):
128
            settings = Trakt['users/settings'].get()
129
130
        if not settings:
131
            log.warn('Unable to retrieve account details for authorization')
132
            return None
133
134
        # Update `TraktAccount` username
135
        try:
136
            self.update_username(t_account, settings)
137
        except (apsw.ConstraintError, peewee.IntegrityError), ex:
138
            log.debug('Trakt account already exists - %s', ex, exc_info=True)
139
140
            raise TraktAccountExistsException('Trakt account already exists')
141
142
        # Save oauth credential changes
143
        oauth.save()
144
145
        # Refresh `TraktAccount`
146
        t_account.refresh(
147
            force=True,
148
            settings=settings
149
        )
150
151
        # Refresh `Account`
152
        t_account.account.refresh(
153
            force=True
154
        )
155
156
        log.info('Updated account authorization for %r', t_account)
157
        return t_account
158
159 1
    def update_username(self, t_account, settings, save=True):
160
        username = settings.get('user', {}).get('username')
161
162
        if not username:
163
            log.warn('Unable to retrieve username for authorization')
164
            return
165
166
        if t_account.username == username:
167
            return
168
169
        self(t_account, {'username': username}, save=save)
170
171
172 1
class TraktAccountManager(Manager):
173 1
    update = UpdateAccount
174
175 1
    model = TraktAccount
176
177 1
    @classmethod
178
    def delete(cls, *query, **kwargs):
179
        # Retrieve account
180
        try:
181
            account = cls.get(*query, **kwargs)
182
        except Exception, ex:
183
            log.warn('Unable to find trakt account (query: %r, kwargs: %r): %r', query, kwargs, ex)
184
            return False
185
186
        # Clear trakt account
187
        cls.update(account, {
188
            'username': None,
189
            'thumb': None,
190
191
            'cover': None,
192
            'timezone': None,
193
194
            'refreshed_at': None
195
        })
196
197
        # Delete trakt credentials
198
        TraktBasicCredentialManager.delete(
199
            account=account.id
200
        )
201
202
        TraktOAuthCredentialManager.delete(
203
            account=account.id
204
        )
205
206
        return True
207