Riki-User-Manager 1.0.1
User Manager utilities for the Riki

<a name="riki_usermanager"></a>
# riki\_usermanager

User Manager for Riki system 

Implementer: Sierra OBryan 

Python: >=3.7

Problem

There was no way to register new user and delete existing users from the riki system 

Solution

Implement a new user manager with easy to use endpoints (login, logout, register, unregister) to manage user in a SQLite database 

APIs
- Login 
- Logout 
- Register 
- Unregister 

# Usage

Command line 

**Instantiate the UserManager** 
```
user_manager = UserManager(get_db())
```
where `get_db()` returns a database connection to a database with a users table according to `schema.sql`

**Register a test user** 
Using test database  
```
1. user_manager.register(User("name", "pswd"))
2. When successful also call flask user manager login 
```
**Login a test user** 
Success
```
1. user_manager.login("name", "pswd")
2. When successful also call flask user manager login 
```
**Logout a test user** 
```
1. user_manager.logout(User("name", "pswd"))
2. When successful also call flask user manager logout
```
**Unregister test user** 
```
1. user_manager.unregister(User("name", "pswd"))
2. When successful also call flask user manager logout 
```

Command line 

**Create a test database** 
```
input: python rkusermanager.py -c "" "" ""
output: test.db 
```
**Register a test user** 

Using test database  
```
input: python rkusermanager.py -r "test.db" "name" "1234" 
output: User(username='name', password='1234', active=1, roles=[], authentication_method=0, authenticated=True, hash='', anonymous=False)
```
Using any database with correct schema (defined in `schema.sql`)
```
input: python rkusermanager.py -r "/tmp/riki.db" "name" "1234" 
output: User(username='name', password='1234', active=1, roles=[], authentication_method=0, authenticated=True, hash='', anonymous=False)
```
**Login a test user** 

Success
```
input: python rkusermanager.py -l "test.db" "name" "1234" 
output: True
```
Failure 
```
input: python rkusermanager.py -l "test.db" "name" "1234" 
output: False
```
**Logout a test user** 
```
input: python rkusermanager.py -o "test.db" "name" "1234" 
output: True
```
**Unregister test user** 
```
input: python rkusermanager.py -u "test.db" "name" "1234" 
output: True
```
**Drop table** 
```
input: python rkusermanager.py -c "" "" ""
output: True 
```
<a name="riki_usermanager.User"></a>
# riki\_usermanager.User

<a name="riki_usermanager.User.AuthMethodEnum"></a>
## AuthMethodEnum Objects

```python
class AuthMethodEnum(Enum)
```

Enum that stores supported authentication methods

<a name="riki_usermanager.User.User"></a>
## User Objects

```python
@dataclass
class User()
```

Represents User entry in the sqlite3 database

Variables: 
* username (str): The user's name.  Used as the primary key in the database.
* password (str): The user's password.  Stored as text in sqlite.
* roles (str): The roles a user has.  It's a list of string, but will be
        stored as a single text value in sqlite.
* authentication_method (int): Used to reference an authentication
        method by number.
* authenticated (bool): Flag for whether a user has been authenticated.
        Stored in sqlite as an int.
* hash (str): Stored result if password has been hashed.
* anonymous (bool): Flag for anonymous users.  Since a registered user is 
        not anonymous, this is not stored in sqlite.

<a name="riki_usermanager.User.User.is_authenticated"></a>
#### is\_authenticated

```python
 | is_authenticated()
```
Returns whether the User is authenticated.

**Arguments**:
- `self` _int_ - The current instance of User


**Returns**:

  bool:authentication state (indicates if user is logged in)

<a name="riki_usermanager.User.User.is_active"></a>
#### is\_active

```python
 | is_active()
```

Returns whether the User is active. Required by flask-login.

**Arguments**:

- `self` _int_ - The current instance of User


**Returns**:

  bool:active state

<a name="riki_usermanager.User.User.is_anonymous"></a>
#### is\_anonymous

```python
 | is_anonymous()
```

Returns whether the User is anonymous.  In this case, all users are not.

**Arguments**:

- `self` _int_ - The current instance of User


**Returns**:

  bool:anonymous state

<a name="riki_usermanager.User.User.get_id"></a>
#### get\_id

```python
 | get_id()
```

Returns the username of a user. Required by flask-login.

**Arguments**:

- `self` _int_ - The current instance of User


**Returns**:

  str:username

<a name="riki_usermanager.User.User.from_dict"></a>
#### from\_dict

```python
 | @staticmethod
 | from_dict(user: Dict[str, Any]) -> 'User'
```

converts array of sql data into dictionary

**Arguments**:

- `data` _List[str]_ - sql array of data


**Returns**:

  Dict[str, Any]: Dictionary of values

<a name="riki_usermanager.UserManager"></a>
# riki\_usermanager.UserManager

<a name="riki_usermanager.UserManager.UserManager"></a>
## UserManager Objects

```python
class UserManager()
```

A very simple User Manager, that manages `User` objects and writes them to database

<a name="riki_usermanager.UserManager.UserManager.__init__"></a>
#### \_\_init\_\_

```python
 | __init__(db: sqlite3.Connection)
```

Create UserManager object

**Arguments**:
- db (sqlite3.Connection): preexisting sqlite3 connection object

<a name="riki_usermanager.UserManager.UserManager.login"></a>
#### login

```python
 | login(username: str, password: str)
```

Logins in a user after username and password have been validated (username and password are not null). This function checks if a user exists (get_user), then checks password (check_password) and then authenticates the user (update). It returns the user if login was sucessful and False if login fails. 


**Arguments**:
- `username` _String_ - username
- `password` _String_ - password 


**Returns**:
- `User`- on success
- `bool`: False - on Failure 

**Depends on**:
- `get_user`
- `check_password`
- `update`

<a name="riki_usermanager.UserManager.UserManager.logout"></a>
#### logout

```python
 | logout(user: User)
```

Logouts user updates the user in database with authenticated = false and returns a `True` if this was successful, else `False`. 

**Arguments**:
- `user` _User_ - User object

**Returns**:
- `bool` - ``True`` on success, else False

**Depends on**:
- `update`

<a name="riki_usermanager.UserManager.UserManager.register"></a>
#### register

```python
 | register(user: 'User')
```

Creates a new user and authenticates a new user after username and password are validated

**Arguments**:
- `user` _User_ - User object

**Returns**:
- `User`- on success
- `bool`: False - on Failure 

**Depends on**:
- `add_user`
- `login`

<a name="riki_usermanager.UserManager.UserManager.unregister"></a>
#### unregister

```python
 | unregister(user: User)
```

Deletes a user's profile

**Arguments**:
- `user` _User_ - User object

**Returns**:
- `bool` - ``True`` on success, else False

**Depends on**:
- `update`

<a name="riki_usermanager.UserManager.UserManager.add_user"></a>
#### add\_user

```python
 | add_user(user: 'User')
```

Creates new user in the database

**Arguments**:
- `user` _User_ - User object

**Returns**:
- `User`- on success
- `bool`: False - on Failure 

<a name="riki_usermanager.UserManager.UserManager.get_user"></a>
#### get\_user

```python
 | get_user(username: str)
```

Get `User` from the database

**Args**:
- name (str): users name

**Returns**:
- User | None: User object if user with the given username is found, otherwise nothing is returned.

<a name="riki_usermanager.UserManager.UserManager.delete_user"></a>
#### delete\_user

```python
 | delete_user(username: str)
```
Deletes user from the database

**Arguments**:
- `name` _str_ - users username

**Returns**:
- `bool` - True if delete was successful, otherwise False

<a name="riki_usermanager.UserManager.UserManager.update"></a>
#### update

```python
 | update(user: 'User')
```
Update user from userdata dictionary

**Arguments**:
- `user` _User_ - User object

**Returns**:
- `bool` - True if delete was successful, otherwise False

<a name="riki_usermanager.UserManager.UserManager.check_password"></a>
#### check\_password

```python
 | @staticmethod
 | check_password(user: User, password: str) -> bool
```
Check if user password matches the password in the database

**Arguments**:
- `password` _str_ - user password

**Returns**:
- `bool` - did password match