Passed
Push — master ( fa3426...b7cfee )
by
unknown
02:43
created

tracim.command.user   A

Complexity

Total Complexity 23

Size/Duplication

Total Lines 232
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
wmc 23
eloc 149
dl 0
loc 232
rs 10
c 0
b 0
f 0

13 Methods

Rating   Name   Duplication   Size   Complexity  
B UserCommand._create_user() 0 23 4
A UserCommand._get_group() 0 2 1
A UserCommand.get_parser() 0 50 1
A UserCommand._proceed_groups() 0 13 3
A UserCommand._add_user_to_named_group() 0 9 2
A UserCommand._update_password_for_login() 0 5 1
A UserCommand._user_exist() 0 2 1
A UserCommand.get_description() 0 2 1
A UserCommand._check_context() 0 9 1
A UserCommand._password_required() 0 5 1
A UserCommand.take_app_action() 0 22 1
B UserCommand._proceed_user() 0 28 4
A UserCommand._remove_user_from_named_group() 0 9 2
1
# -*- coding: utf-8 -*-
0 ignored issues
show
Coding Style introduced by
This module should have a docstring.

The coding style of this project requires that you add a docstring to this code element. Below, you find an example for methods:

class SomeClass:
    def some_method(self):
        """Do x and return foo."""

If you would like to know more about docstrings, we recommend to read PEP-257: Docstring Conventions.

Loading history...
2
import argparse
3
from pyramid.scripting import AppEnvironment
4
import transaction
5
from sqlalchemy.exc import IntegrityError
6
7
from tracim import CFG
0 ignored issues
show
Unused Code introduced by
Unused CFG imported from tracim
Loading history...
8
from tracim.command import AppContextCommand
9
from tracim.command import Extender
10
#from tracim.lib.auth.ldap import LDAPAuth
11
#from tracim.lib.daemons import DaemonsManager
12
#from tracim.lib.daemons import RadicaleDaemon
13
#from tracim.lib.email import get_email_manager
14
from tracim.exceptions import AlreadyExistError
15
from tracim.exceptions import CommandAbortedError
16
from tracim.lib.core.group import GroupApi
17
from tracim.lib.core.user import UserApi
18
from tracim.models import User
19
from tracim.models import Group
20
21
22
class UserCommand(AppContextCommand):
0 ignored issues
show
Coding Style introduced by
This class should have a docstring.

The coding style of this project requires that you add a docstring to this code element. Below, you find an example for methods:

class SomeClass:
    def some_method(self):
        """Do x and return foo."""

If you would like to know more about docstrings, we recommend to read PEP-257: Docstring Conventions.

Loading history...
Unused Code introduced by
The variable __class__ seems to be unused.
Loading history...
23
24
    ACTION_CREATE = 'create'
25
    ACTION_UPDATE = 'update'
26
27
    action = NotImplemented
28
29
    def get_description(self) -> str:
30
        return '''Create or update user.'''
31
32
    def get_parser(self, prog_name: str) -> argparse.ArgumentParser:
33
        parser = super().get_parser(prog_name)
34
35
        parser.add_argument(
36
            "-l",
37
            "--login",
38
            help='User login (email)',
39
            dest='login',
40
            required=True
41
        )
42
43
        parser.add_argument(
44
            "-p",
45
            "--password",
46
            help='User password',
47
            dest='password',
48
            required=False,
49
            default=None
50
        )
51
52
        parser.add_argument(
53
            "-g",
54
            "--add-to-group",
55
            help='Add user to group',
56
            dest='add_to_group',
57
            nargs='*',
58
            action=Extender,
59
            default=[],
60
        )
61
62
        parser.add_argument(
63
            "-rmg",
64
            "--remove-from-group",
65
            help='Remove user from group',
66
            dest='remove_from_group',
67
            nargs='*',
68
            action=Extender,
69
            default=[],
70
        )
71
72
        parser.add_argument(
73
            "--send-email",
74
            help='Send mail to user',
75
            dest='send_email',
76
            required=False,
77
            action='store_true',
78
            default=False,
79
        )
80
81
        return parser
82
83
    def _user_exist(self, login: str) -> User:
84
        return self._user_api.user_with_email_exists(login)
85
86
    def _get_group(self, name: str) -> Group:
87
        return self._group_api.get_one_with_name(name)
88
89
    def _add_user_to_named_group(
90
            self,
91
            user: str,
92
            group_name: str
93
    ) -> None:
94
        group = self._get_group(group_name)
95
        if user not in group.users:
96
            group.users.append(user)
97
        self._session.flush()
98
99
    def _remove_user_from_named_group(
100
            self,
101
            user: User,
102
            group_name: str
103
    ) -> None:
104
        group = self._get_group(group_name)
105
        if user in group.users:
106
            group.users.remove(user)
107
        self._session.flush()
108
109
    def _create_user(self, login: str, password: str, **kwargs) -> User:
0 ignored issues
show
Unused Code introduced by
The argument kwargs seems to be unused.
Loading history...
110
        if not password:
111
            if self._password_required():
112
                raise CommandAbortedError(
113
                    "You must provide -p/--password parameter"
114
                )
115
            password = ''
116
117
        try:
118
            user = self._user_api.create_user(email=login)
119
            user.password = password
120
            self._user_api.save(user)
121
            # TODO - G.M - 04-04-2018 - [Caldav] Check this code
0 ignored issues
show
Coding Style introduced by
TODO and FIXME comments should generally be avoided.
Loading history...
122
            # # We need to enable radicale if it not already done
123
            # daemons = DaemonsManager()
124
            # daemons.run('radicale', RadicaleDaemon)
125
126
            self._user_api.execute_created_user_actions(user)
127
        except IntegrityError:
128
            self._session.rollback()
129
            raise AlreadyExistError()
130
131
        return user
132
133
    def _update_password_for_login(self, login: str, password: str) -> None:
134
        user = self._user_api.get_one_by_email(login)
135
        user.password = password
136
        self._session.flush()
137
        transaction.commit()
138
139
    def take_app_action(
0 ignored issues
show
Coding Style introduced by
This method should have a docstring.

The coding style of this project requires that you add a docstring to this code element. Below, you find an example for methods:

class SomeClass:
    def some_method(self):
        """Do x and return foo."""

If you would like to know more about docstrings, we recommend to read PEP-257: Docstring Conventions.

Loading history...
140
            self,
141
            parsed_args: argparse.Namespace,
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable argparse does not seem to be defined.
Loading history...
142
            app_context: AppEnvironment
143
    ) -> None:
144
        # TODO - G.M - 05-04-2018 -Refactor this in order
0 ignored issues
show
Coding Style introduced by
TODO and FIXME comments should generally be avoided.
Loading history...
145
        # to not setup object var outside of __init__ .
146
        self._session = app_context['request'].dbsession
0 ignored issues
show
Coding Style introduced by
The attribute _session was defined outside __init__.

It is generally a good practice to initialize all attributes to default values in the __init__ method:

class Foo:
    def __init__(self, x=None):
        self.x = x
Loading history...
147
        self._app_config = app_context['registry'].settings['CFG']
0 ignored issues
show
Coding Style introduced by
The attribute _app_config was defined outside __init__.

It is generally a good practice to initialize all attributes to default values in the __init__ method:

class Foo:
    def __init__(self, x=None):
        self.x = x
Loading history...
148
        self._user_api = UserApi(
0 ignored issues
show
Coding Style introduced by
The attribute _user_api was defined outside __init__.

It is generally a good practice to initialize all attributes to default values in the __init__ method:

class Foo:
    def __init__(self, x=None):
        self.x = x
Loading history...
149
            current_user=None,
150
            session=self._session,
151
            config=self._app_config,
152
        )
153
        self._group_api = GroupApi(
0 ignored issues
show
Coding Style introduced by
The attribute _group_api was defined outside __init__.

It is generally a good practice to initialize all attributes to default values in the __init__ method:

class Foo:
    def __init__(self, x=None):
        self.x = x
Loading history...
154
            current_user=None,
155
            session=self._session,
156
        )
157
        user = self._proceed_user(parsed_args)
158
        self._proceed_groups(user, parsed_args)
159
160
        print("User created/updated")
161
162
    def _proceed_user(self, parsed_args: argparse.Namespace) -> User:
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable argparse does not seem to be defined.
Loading history...
163
        self._check_context(parsed_args)
164
165
        if self.action == self.ACTION_CREATE:
166
            try:
167
                user = self._create_user(
168
                    login=parsed_args.login,
169
                    password=parsed_args.password
170
                )
171
            except AlreadyExistError:
172
                raise CommandAbortedError("Error: User already exist (use `user update` command instead)")
0 ignored issues
show
Coding Style introduced by
This line is too long as per the coding-style (106/100).

This check looks for lines that are too long. You can specify the maximum line length.

Loading history...
173
            # TODO - G.M - 04-04-2018 - [Email] Check this code
0 ignored issues
show
Coding Style introduced by
TODO and FIXME comments should generally be avoided.
Loading history...
174
            # if parsed_args.send_email:
175
            #     email_manager = get_email_manager()
176
            #     email_manager.notify_created_account(
177
            #         user=user,
178
            #         password=parsed_args.password,
179
            #     )
180
181
        else:
182
            if parsed_args.password:
183
                self._update_password_for_login(
184
                    login=parsed_args.login,
185
                    password=parsed_args.password
186
                )
187
            user = self._user_api.get_one_by_email(parsed_args.login)
188
189
        return user
190
191
    def _proceed_groups(
192
            self,
193
            user: User,
194
            parsed_args: argparse.Namespace
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable argparse does not seem to be defined.
Loading history...
195
    ) -> None:
196
        # User always in "users" group
197
        self._add_user_to_named_group(user, 'users')
198
199
        for group_name in parsed_args.add_to_group:
200
            self._add_user_to_named_group(user, group_name)
201
202
        for group_name in parsed_args.remove_from_group:
203
            self._remove_user_from_named_group(user, group_name)
204
205
    def _password_required(self) -> bool:
0 ignored issues
show
Coding Style introduced by
This method could be written as a function/class method.

If a method does not access any attributes of the class, it could also be implemented as a function or static method. This can help improve readability. For example

class Foo:
    def some_method(self, x, y):
        return x + y;

could be written as

class Foo:
    @classmethod
    def some_method(cls, x, y):
        return x + y;
Loading history...
206
        # TODO - G.M - 04-04-2018 - [LDAP] Check this code
0 ignored issues
show
Coding Style introduced by
TODO and FIXME comments should generally be avoided.
Loading history...
207
        # if config.get('auth_type') == LDAPAuth.name:
208
        #     return False
209
        return True
210
211
    def _check_context(self, parsed_args: argparse.Namespace) -> None:
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable argparse does not seem to be defined.
Loading history...
212
        # TODO - G.M - 04-04-2018 - [LDAP] Check this code
0 ignored issues
show
Coding Style introduced by
TODO and FIXME comments should generally be avoided.
Loading history...
213
        # if config.get('auth_type') == LDAPAuth.name:
214
        #     auth_instance = config.get('auth_instance')
215
        #     if not auth_instance.ldap_auth.user_exist(parsed_args.login):
216
        #         raise LDAPUserUnknown(
217
        #             "LDAP is enabled and user with login/email \"%s\" not found in LDAP" % parsed_args.login
0 ignored issues
show
Coding Style introduced by
This line is too long as per the coding-style (110/100).

This check looks for lines that are too long. You can specify the maximum line length.

Loading history...
218
        #         )
219
        pass
220
221
222
class CreateUserCommand(UserCommand):
0 ignored issues
show
Coding Style introduced by
This class should have a docstring.

The coding style of this project requires that you add a docstring to this code element. Below, you find an example for methods:

class SomeClass:
    def some_method(self):
        """Do x and return foo."""

If you would like to know more about docstrings, we recommend to read PEP-257: Docstring Conventions.

Loading history...
223
    action = UserCommand.ACTION_CREATE
224
225
226
class UpdateUserCommand(UserCommand):
0 ignored issues
show
Coding Style introduced by
This class should have a docstring.

The coding style of this project requires that you add a docstring to this code element. Below, you find an example for methods:

class SomeClass:
    def some_method(self):
        """Do x and return foo."""

If you would like to know more about docstrings, we recommend to read PEP-257: Docstring Conventions.

Loading history...
227
    action = UserCommand.ACTION_UPDATE
228
229
230
class LDAPUserUnknown(CommandAbortedError):
0 ignored issues
show
Coding Style introduced by
This class should have a docstring.

The coding style of this project requires that you add a docstring to this code element. Below, you find an example for methods:

class SomeClass:
    def some_method(self):
        """Do x and return foo."""

If you would like to know more about docstrings, we recommend to read PEP-257: Docstring Conventions.

Loading history...
231
    pass
232