Passed
Push — develop ( 2798d2...d1b463 )
by Dean
02:48
created

UpdateAccount.from_pin()   C

Complexity

Conditions 9

Size

Total Lines 58

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 1
CRAP Score 81.9024

Importance

Changes 0
Metric Value
c 0
b 0
f 0
dl 0
loc 58
rs 5.1258
ccs 1
cts 29
cp 0.0345
cc 9
crap 81.9024

How to fix   Long Method   

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:

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 exception_wrappers.libraries import apsw
7 1
from trakt import Trakt
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, settings=None):
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
        # Fetch account settings (if not provided)
67
        if not settings:
68
            with t_account.authorization().http(retry=True):
69
                settings = Trakt['users/settings'].get()
70
71
        # Ensure account settings are available
72
        if not settings:
73
            log.warn('Unable to retrieve account details for authorization')
74
            return None
75
76
        # Update `TraktAccount` username
77
        try:
78
            self.update_username(t_account, settings)
79
        except (apsw.ConstraintError, peewee.IntegrityError) as ex:
80
            log.debug('Trakt account already exists - %s', ex, exc_info=True)
81
82
            raise TraktAccountExistsException('Trakt account already exists')
83
84
        # Refresh `TraktAccount`
85
        t_account.refresh(
86
            force=True,
87
            settings=settings
88
        )
89
90
        # Save credentials
91
        if 'basic' in authorization:
92
            t_account.basic.save()
93
94
        if 'oauth' in authorization:
95
            t_account.oauth.save()
96
97
        # Refresh `Account`
98
        t_account.account.refresh(
99
            force=True
100
        )
101
102
        log.info('Updated account authorization for %r', t_account)
103
        return True
104
105 1
    def from_pin(self, t_account, pin):
106
        if not pin:
107
            log.debug('"pin" parameter is empty, ignoring account authorization update')
108
            return t_account
109
110
        # Retrieve current account `OAuthCredential`
111
        oauth = t_account.oauth_credentials.first()
112
113
        if oauth and oauth.code == pin:
114
            log.debug("PIN hasn't changed, ignoring account authorization update")
115
            return t_account
116
117
        if not oauth:
118
            # Create new `OAuthCredential` for the account
119
            oauth = TraktOAuthCredential(
120
                account=t_account
121
            )
122
123
        # Update `OAuthCredential`
124
        if not TraktOAuthCredentialManager.update.from_pin(oauth, pin, save=False):
0 ignored issues
show
Bug introduced by
It seems like a value for argument pin is missing in the unbound method call.
Loading history...
125
            log.warn("Unable to update OAuthCredential (token exchange failed, hasn't changed, etc..)")
126
127
            # Save code into database (to avoid future re-authentication with the same pin)
128
            oauth.save()
129
            return None
130
131
        # Validate the account authorization
132
        with t_account.oauth_authorization(oauth).http(retry=True):
133
            settings = Trakt['users/settings'].get()
134
135
        if not settings:
136
            log.warn('Unable to retrieve account details for authorization')
137
            return None
138
139
        # Update `TraktAccount` username
140
        try:
141
            self.update_username(t_account, settings)
142
        except (apsw.ConstraintError, peewee.IntegrityError) as ex:
143
            log.debug('Trakt account already exists - %s', ex, exc_info=True)
144
145
            raise TraktAccountExistsException('Trakt account already exists')
146
147
        # Save oauth credential changes
148
        oauth.save()
149
150
        # Refresh `TraktAccount`
151
        t_account.refresh(
152
            force=True,
153
            settings=settings
154
        )
155
156
        # Refresh `Account`
157
        t_account.account.refresh(
158
            force=True
159
        )
160
161
        log.info('Updated account authorization for %r', t_account)
162
        return t_account
163
164 1
    def update_username(self, t_account, settings, save=True):
165
        username = settings.get('user', {}).get('username')
166
167
        if not username:
168
            log.warn('Unable to retrieve username for authorization')
169
            return
170
171
        if t_account.username == username:
172
            return
173
174
        self(t_account, {'username': username}, save=save)
175
176
177 1
class TraktAccountManager(Manager):
178 1
    update = UpdateAccount
179
180 1
    model = TraktAccount
181
182 1
    @classmethod
183
    def delete(cls, *query, **kwargs):
184
        # Retrieve account
185
        try:
186
            account = cls.get(*query, **kwargs)
187
        except Exception as ex:
0 ignored issues
show
Best Practice introduced by
Catching very general exceptions such as Exception is usually not recommended.

Generally, you would want to handle very specific errors in the exception handler. This ensure that you do not hide other types of errors which should be fixed.

So, unless you specifically plan to handle any error, consider adding a more specific exception.

Loading history...
188
            log.warn('Unable to find trakt account (query: %r, kwargs: %r): %r', query, kwargs, ex)
189
            return False
190
191
        # Clear trakt account
192
        cls.update(account, {
193
            'username': None,
194
            'thumb': None,
195
196
            'cover': None,
197
            'timezone': None,
198
199
            'refreshed_at': None
200
        })
201
202
        # Delete trakt credentials
203
        TraktBasicCredentialManager.delete(
204
            account=account.id
0 ignored issues
show
Bug introduced by
The Instance of Get does not seem to have a member named id.

This check looks for calls to members that are non-existent. These calls will fail.

The member could have been renamed or removed.

Loading history...
205
        )
206
207
        TraktOAuthCredentialManager.delete(
208
            account=account.id
0 ignored issues
show
Bug introduced by
The Instance of Get does not seem to have a member named id.

This check looks for calls to members that are non-existent. These calls will fail.

The member could have been renamed or removed.

Loading history...
209
        )
210
211
        return True
212