Commit 67647ae4 authored by Shashank Kumar's avatar Shashank Kumar

conflict resolved

parents 4f3204df 05b5d18a
# Project directories
modules/encryption/tools/all_tools/gnupg_home
/libs
gnupg_home
# Python
*.pyc
/libs/garden
# For Tests
# Tests
.pytest_cache
.coverage
......
......@@ -10,7 +10,6 @@ before_script:
- pipenv install --skip-lock
- pipenv install --skip-lock git+http://github.com/kivy/kivy.git#egg=kivy-1.10.1
pylint:
type: test
script:
......@@ -22,6 +21,5 @@ pylint:
pytest:
type: test
script:
- apt-get install -y gnupg
- pipenv install --skip-lock pytest pytest-cov
- pipenv run pytest tests --cov=modules
......@@ -55,6 +55,7 @@ confidence=
# no Warning level messages displayed, use"--disable=all --enable=classes
# --disable=W"
disable=duplicate-code,
unused-import,
pointless-string-statement,
useless-super-delegation,
parameter-unpacking,
......
......@@ -7,10 +7,12 @@ name = "pypi"
pylint = "==1.9.1"
pytest = "==3.6.0"
pytest-cov = "==2.5.1"
ipdb = "==0.11"
[packages]
cython = "==0.28"
python-gnupg = "==0.4.3"
requests = "==2.19.1"
[requires]
python_version = "3.5"
{
"_meta": {
"hash": {
"sha256": "eaa221d475af278cb4318daa3598a2c329c33d2c1fd7b220f7d4e60f4ba422c7"
"sha256": "7e795eb3ea979205c92d0da17b18b772855d81c1f510165db414636c3e46eb46"
},
"pipfile-spec": 6,
"requires": {
......@@ -16,6 +16,20 @@
]
},
"default": {
"certifi": {
"hashes": [
"sha256:13e698f54293db9f89122b0581843a782ad0934a4fe0172d2a980ba77fc61bb7",
"sha256:9fa520c1bacfb634fa7af20a76bcbd3d5fb390481724c597da32c719a7dca4b0"
],
"version": "==2018.4.16"
},
"chardet": {
"hashes": [
"sha256:84ab92ed1c4d4f16916e05906b6b75a6c0fb5db821cc65e70cbd64a3e2a5eaae",
"sha256:fc323ffcaeaed0e0a02bf4d117757b98aed530d9ed4531e3e15460124c106691"
],
"version": "==3.0.4"
},
"cython": {
"hashes": [
"sha256:02414e1cae1882d48e8fa9cdefb6e7bd3dd200a5dc5120a3905df164d23e7894",
......@@ -52,6 +66,13 @@
"index": "pypi",
"version": "==0.28"
},
"idna": {
"hashes": [
"sha256:156a6814fb5ac1fc6850fb002e0852d56c0c8d2531923a51032d1b70760e186e",
"sha256:684a38a6f903c1d71d6d5fac066b58d7768af4de2b832e426ec79c30daa94a16"
],
"version": "==2.7"
},
"python-gnupg": {
"hashes": [
"sha256:2d158dfc6b54927752b945ebe57e6a0c45da27747fa3b9ae66eccc0d2147ac0d",
......@@ -59,6 +80,21 @@
],
"index": "pypi",
"version": "==0.4.3"
},
"requests": {
"hashes": [
"sha256:63b52e3c866428a224f97cab011de738c36aec0185aa91cfacd418b5d58911d1",
"sha256:ec22d826a36ed72a7358ff3fe56cbd4ba69dd7a6718ffd450ff0e9df7a47ce6a"
],
"index": "pypi",
"version": "==2.19.1"
},
"urllib3": {
"hashes": [
"sha256:a68ac5e15e76e7e5dd2b8f94007233e01effe3e50e8daddf69acfd81cb686baf",
"sha256:b5725a0bd4ba422ab0e66e89e030c806576753ea3ee08554382c14e685d117b5"
],
"version": "==1.23"
}
},
"develop": {
......@@ -83,6 +119,13 @@
],
"version": "==18.1.0"
},
"backcall": {
"hashes": [
"sha256:38ecd85be2c1e78f77fd91700c76e14667dc21e2713b63876c0eb901196e01e4",
"sha256:bbbf4b1e5cd2bdb08f915895b51081c041bac22394fdfcfdfbe9f14b77c08bf2"
],
"version": "==0.1.0"
},
"coverage": {
"hashes": [
"sha256:03481e81d558d30d230bc12999e3edffe392d244349a90f4ef9b88425fac74ba",
......@@ -124,6 +167,34 @@
],
"version": "==4.5.1"
},
"decorator": {
"hashes": [
"sha256:2c51dff8ef3c447388fe5e4453d24a2bf128d3a4c32af3fabef1f01c6851ab82",
"sha256:c39efa13fbdeb4506c476c9b3babf6a718da943dab7811c206005a4a956c080c"
],
"version": "==4.3.0"
},
"ipdb": {
"hashes": [
"sha256:7081c65ed7bfe7737f83fa4213ca8afd9617b42ff6b3f1daf9a3419839a2a00a"
],
"index": "pypi",
"version": "==0.11"
},
"ipython": {
"hashes": [
"sha256:a0c96853549b246991046f32d19db7140f5b1a644cc31f0dc1edc86713b7676f",
"sha256:eca537aa61592aca2fef4adea12af8e42f5c335004dfa80c78caf80e8b525e5c"
],
"version": "==6.4.0"
},
"ipython-genutils": {
"hashes": [
"sha256:72dd37233799e619666c9f639a9da83c34013a73e8bbc79a7a6348d93c61fab8",
"sha256:eb2e116e75ecef9d4d228fdc66af54269afa26ab4463042e33785b887c628ba8"
],
"version": "==0.2.0"
},
"isort": {
"hashes": [
"sha256:1153601da39a25b14ddc54955dbbacbb6b2d19135386699e2ad58517953b34af",
......@@ -132,6 +203,13 @@
],
"version": "==4.3.4"
},
"jedi": {
"hashes": [
"sha256:b409ed0f6913a701ed474a614a3bb46e6953639033e31f769ca7581da5bd1ec1",
"sha256:c254b135fb39ad76e78d4d8f92765ebc9bf92cbc76f49e97ade1d5f5121e1f6f"
],
"version": "==0.12.1"
},
"lazy-object-proxy": {
"hashes": [
"sha256:0ce34342b419bd8f018e6666bfef729aec3edf62345a53b537a4dcc115746a33",
......@@ -181,6 +259,28 @@
],
"version": "==4.2.0"
},
"parso": {
"hashes": [
"sha256:8105449d86d858e53ce3e0044ede9dd3a395b1c9716c696af8aa3787158ab806",
"sha256:d250235e52e8f9fc5a80cc2a5f804c9fefd886b2e67a2b1099cf085f403f8e33"
],
"version": "==0.3.0"
},
"pexpect": {
"hashes": [
"sha256:2a8e88259839571d1251d278476f3eec5db26deb73a70be5ed5dc5435e418aba",
"sha256:3fbd41d4caf27fa4a377bfd16fef87271099463e6fa73e92a52f92dfee5d425b"
],
"markers": "sys_platform != 'win32'",
"version": "==4.6.0"
},
"pickleshare": {
"hashes": [
"sha256:84a9257227dfdd6fe1b4be1319096c20eb85ff1e82c7932f36efccfe1b09737b",
"sha256:c9a2541f25aeabc070f12f452e1f2a8eae2abd51e1cd19e8430402bdf4c1d8b5"
],
"version": "==0.7.4"
},
"pluggy": {
"hashes": [
"sha256:7f8ae7f5bdf75671a718d2daf0a64b7885f74510bcd98b1a0bb420eb9a9d0cff",
......@@ -189,6 +289,21 @@
],
"version": "==0.6.0"
},
"prompt-toolkit": {
"hashes": [
"sha256:1df952620eccb399c53ebb359cc7d9a8d3a9538cb34c5a1344bdbeb29fbcc381",
"sha256:3f473ae040ddaa52b52f97f6b4a493cfa9f5920c255a12dc56a7d34397a398a4",
"sha256:858588f1983ca497f1cf4ffde01d978a3ea02b01c8a26a8bbc5cd2e66d816917"
],
"version": "==1.0.15"
},
"ptyprocess": {
"hashes": [
"sha256:923f299cc5ad920c68f2bc0bc98b75b9f838b93b599941a6b63ddbc2476394c0",
"sha256:d7cc528d76e76342423ca640335bd3633420dc1366f258cb31d05e865ef5ca1f"
],
"version": "==0.6.0"
},
"py": {
"hashes": [
"sha256:3fd59af7435864e1a243790d322d763925431213b6b8529c6ca71081ace3bbf7",
......@@ -196,6 +311,13 @@
],
"version": "==1.5.4"
},
"pygments": {
"hashes": [
"sha256:78f3f434bcc5d6ee09020f92ba487f95ba50f1e3ef83ae96b9d5ffa1bab25c5d",
"sha256:dbae1046def0efb574852fab9e90209b23f556367b5a320c0bcb871c77c3e8cc"
],
"version": "==2.2.0"
},
"pylint": {
"hashes": [
"sha256:aa519865f8890a5905fa34924fed0f3bfc7d84fc9f9142c16dac52ffecd25a39",
......@@ -220,6 +342,12 @@
"index": "pypi",
"version": "==2.5.1"
},
"simplegeneric": {
"hashes": [
"sha256:dc972e06094b9af5b855b3df4a646395e43d1c9d0d39ed345b7393560d0b9173"
],
"version": "==0.8.1"
},
"six": {
"hashes": [
"sha256:70e8a77beed4562e7f14fe23a786b54f6296e34344c23bc42f07b15018ff98e9",
......@@ -227,6 +355,20 @@
],
"version": "==1.11.0"
},
"traitlets": {
"hashes": [
"sha256:9c4bd2d267b7153df9152698efb1050a5d84982d3384a37b2c1f7723ba3e7835",
"sha256:c6cb5e6f57c5a9bdaa40fa71ce7b4af30298fbab9ece9815b5d995ab6217c7d9"
],
"version": "==4.3.2"
},
"wcwidth": {
"hashes": [
"sha256:3df37372226d6e63e1b1e1eda15c594bca98a22d33a23832a90998faa96bc65e",
"sha256:f4ebe71925af7b40a864553f761ed559b43544f8f71746c2d756c7fe788ade7c"
],
"version": "==0.1.7"
},
"wrapt": {
"hashes": [
"sha256:d4d560d479f2c21e1b5443bbd15fe7ec4b37fe7e53d335d3b9b0a7b1226fe3c6"
......
v0.0.1
## June 19 2018
- Adding Encryption module skeleton (Shashank Kumar)
- Adding Encryption tools (create key pair, display and manage key pair, encrypt message and decrypt message) (Shashank Kumar)
## June 11 2018
- Adding Dashboard feature
- Adding blog, cli, communication, encryption, how_to_use, vcs and way_ahead modules for courseware
- Adding application, profile and theme modules for settings
- Adding Dashboard feature (Shashank Kumar)
- Adding blog, cli, communication, encryption, how_to_use, vcs and way_ahead modules for courseware (Shashank Kumar)
- Adding application, profile and theme modules for settings (Shashank Kumar)
## June 9 2018
- Added SignIn feature. (Shashank Kumar)
## June 7 2018
- Sign Up feature added.
- Added SignUp feature. (Shashank Kumar)
## June 3 2018
- Reporting coverage while running Gitlab CI.
- Reporting coverage while running Gitlab CI. (Shashank Kumar)
## June 1 2018
- Initial app setup using Kivy.
- Integrate pylint, pytest and support for Gitlab CI.
- Initial app setup using Kivy. (Shashank Kumar)
- Integrate pylint, pytest and support for Gitlab CI. (Shashank Kumar)
......@@ -52,7 +52,11 @@ Step 4: Install application dependencies (this might take a while, grab a cup of
`$ pipenv install`
Step 5: Run New Contributor Wizard
Step 5: Install Kivy
`$ pipenv install --skip-lock git+http://github.com/kivy/kivy.git#egg=kivy-1.10.1`
Step 6: Run New Contributor Wizard
`$ pipenv run python main.py`
......@@ -88,7 +92,7 @@ There are two type of testing being done for this application.
- `tests` - This directory should and only contain the Test written for the application, both for application logic and GUI.
- `ui` - This directory should and only contain the `.kv` files which uses Kivy Language in order to create the widget tree.
- `ui` - This directory should and only contain the `.kv` files which uses Kivy Language in order to create the widget tree.
### Sign Up Module
......@@ -106,7 +110,24 @@ There are two type of testing being done for this application.
- `test_services.py` - contains tests for `modules/signup/services.py`
- `test_utils.py` - contains tests for `modules/signup/utils.py`
- `test_validation.py` - contains tests for `modules/signup/validations.py`
### SignIn Module
`modules/signin/` contains the Python logic for Sign In. They can be described as below.
- `exceptions.py` contains SignIn module specific custom exception classes
- `services.py` contains service functions for SignIn module
- `signin.py` contains KIVY UI and other integrations for SignIn module
- `validations.py` contains user information validation functions
- `utils.py` contains utility functions to help out with SignIn operations
- `ui/signin.kv` file contains KIVY widget tree which in turn renders the UI for the Sign Up module.
- `tests/signin/` contains written tests for the Sign Up module. They can be described as below.
- `test_services.py` - contains tests for `modules/signin/services.py`
- `test_utils.py` - contains tests for `modules/signin/utils.py`
- `test_validation.py` - contains tests for `modules/signin/validations.py`
### The Dashboard
......
......@@ -3,11 +3,8 @@ Root Kivy Application
'''
from kivy.app import App
from kivy.config import Config
from kivy.uix.screenmanager import ScreenManager
from settings import initializing_database
from modules.signup import signup
from modules.dashboard import dashboard
from settings import get_db_connection, installing_kivy_garden_package
class NewContributorWizard(App):
......@@ -15,29 +12,36 @@ class NewContributorWizard(App):
Declaration of Root Kivy App which contains Root Widget
'''
def __init__(self, **kwargs):
super().__init__(**kwargs)
self.screen_manager_obj = ScreenManager()
self.screen_manager_obj.add_widget(signup.SignUp(name='signup'))
self.screen_manager_obj.add_widget(dashboard.Dashboard(name='dashboard'))
def build(self):
return self.screen_manager_obj
'''
Overridding build method of App class to load custom kv file
'''
self.load_kv('./ui/main.kv')
def switch_screen_to_dashboard(self):
'''
This method helps clear the widget and switch directly to the Dashboard
'''
self.root.clear_widgets()
self.root.add_widget(Dashboard())
if __name__ == '__main__':
'''
Setting up things
'''
initializing_database()
get_db_connection()
installing_kivy_garden_package('navigationdrawer')
'''
Fixing touch issue with some platforms
Setting window width to 720px and height to 480px
'''
# Importing modules
from modules.dashboard.dashboard import Dashboard
from modules.signup.signup import SignUp
from modules.signin.signin import SignIn
# Fixing touch issue with some platforms
Config.set('input', 'mouse', 'mouse')
Config.set('graphics', 'minimum_width', 720)
Config.set('graphics', 'minimum_height', 480)
'''
Running Kivy application and building root Widget
'''
# Running Kivy application and building root Widget
NewContributorWizard().run()
'''
Dashboard module includes classes to showcase Dashboard with different courseware and settings
'''
from copy import copy as cp
import logging
from kivy.uix.boxlayout import BoxLayout
from kivy.lang import Builder
from kivy.uix.screenmanager import Screen
try:
from libs.garden.navigationdrawer import NavigationDrawer
except ImportError:
logging.info('Dashboard: Install navigationdrawer from garden')
from modules.blog.blog import Blog
from modules.cli.cli import CLI
......@@ -26,42 +30,4 @@ class Dashboard(BoxLayout, Screen):
'''
Dashboard class to integrate courseware and settings
'''
def __init__(self, **kwargs):
super().__init__(**kwargs)
self.all_menu_screens = {
'application_settings': ApplicationSettings(),
'blog': Blog(),
'cli': CLI(),
'communication': Communication(),
'encryption': Encryption(),
'how_to_use': HowToUse(),
'profile_settings': ProfileSettings(),
'theme_settings': ThemeSettings(),
'vcs': VCS(),
'way_ahead': WayAhead(),
}
self.all_menu_items = list(self.all_menu_screens.keys())
self.enable_menu('encryption')
def enable_menu(self, menu_item_to_enable):
'''
enable_menu function focuses on concerned menu items or settings which is clicked and
removes focus from all other menu items and settings
'''
menu_item_to_enable_widget = self.ids[menu_item_to_enable + '_box']
menu_item_to_enable_color = menu_item_to_enable_widget.canvas.before.children[0].rgba
if menu_item_to_enable_color != [1, 1, 1, 1] or 'settings' in menu_item_to_enable:
self.ids['module_screen'].add_widget(self.all_menu_screens[menu_item_to_enable])
if 'settings' not in menu_item_to_enable:
self.ids[menu_item_to_enable + '_box'].canvas.before.children[0].rgba = [1, 1, 1, 1]
self.ids[menu_item_to_enable + '_label'].color = (0, 0, 0, 1)
all_menu_items_copy = cp(self.all_menu_items)
all_menu_items_copy.remove(menu_item_to_enable)
for menu_item in all_menu_items_copy:
if 'settings' not in menu_item:
self.ids[menu_item + '_box'].canvas.before.children[0].rgba = [0, 0, 0, 1]
self.ids[menu_item + '_label'].color = (1, 1, 1, 1)
self.ids['module_screen'].remove_widget(self.all_menu_screens[menu_item])
pass
......@@ -25,7 +25,6 @@ class Encryption(BoxLayout):
'tools': tools.Tools(),
}
self.all_options_items = list(self.all_options.keys())
self.enable_option('tools')
def enable_option(self, option_to_enable):
'''
......
......@@ -5,7 +5,7 @@ import gnupg
from modules.encryption.tools.all_tools.exceptions import GPGError
GNUPG_HOME = 'modules/encryption/tools/all_tools/gnupg_home'
GNUPG_HOME = 'gnupg_home'
def create_gnupg_object():
......
'''
This class contains signin module specific exceptions
'''
class SignInError(Exception):
'''
SignInError class can be used to raise exception related to
Sign In module
'''
def __init__(self, message):
self.message = message
super().__init__(message)
'''
This modules contain classes to query sqlite3 database
'''
from settings import get_db_connection, USER_INFOMATION_TABLE
from modules.signin.exceptions import SignInError
from modules.signin.utils import (
clean_email,
hash_password
)
def sign_in_user(email, password):
'''
sign_in_user would try to check for user's email and hashed
password in the database
Would result in a UserError if email doesn't exist
Would result in a PasswordError if password doesn't match
'''
connection = get_db_connection()
db_cursor = connection.cursor()
cleaned_email = clean_email(email)
hashed_pass = hash_password(password)
sign_in_query = 'SELECT * FROM {} WHERE email=?'.format(USER_INFOMATION_TABLE)
user_info = db_cursor.execute(sign_in_query, (cleaned_email, )).fetchone()
if not user_info:
raise SignInError('Email does not exist!')
elif user_info[2] != hashed_pass:
raise SignInError('Password is incorrect!')
return user_info
'''
Class for SignIn Screen
'''
import logging
from kivy.uix.boxlayout import BoxLayout
from kivy.lang import Builder
from kivy.clock import Clock
from kivy.uix.screenmanager import Screen
from modules.signin.services import sign_in_user
from modules.signin.exceptions import SignInError
from modules.signin.validations import validate_email, validate_password
Builder.load_file('./ui/signin.kv')
class SignIn(BoxLayout, Screen):
'''
Declaration of SignIn Screen Class
'''
def prompt_error_message(self, label, error_text):
'''
Displays error message on the UI on the respective label widget
'''
original_text = self.ids[label].text
self.ids[label].text = error_text
self.ids[label].color = [1, 0, 0, 1]
def replace_label(*args):
'''
Replacing original text in label
delay time is defined by args[0]
'''
logging.info(
'SignIn: \'%s\' changed to \'%s\' after %s seconds',
error_text,
original_text,
args[0]
)
self.ids[label].text = original_text
self.ids[label].color = [1, 1, 1, 1]
Clock.schedule_once(replace_label, 2)
def validate(self):
'''
Validating Email and Password provided by user
'''
email_validation = True
password_validation = True
user_email = self.ids['user_email'].text
try:
validate_email(user_email)
except SignInError as error:
self.prompt_error_message(
'email_label',
error.message,
)
email_validation = False
password = self.ids['password'].text
try:
validate_password(password)
except SignInError as error:
self.prompt_error_message(
'password_label',
error.message,
)
password_validation = False
return email_validation and password_validation
def sign_in(self, *args):
'''
Signin user in case of successful validation
Prompting error message to the user otherwise
'''
app_object = args[0]
if self.validate():
user_email = self.ids['user_email'].text
user_pass = self.ids['password'].text
try:
sign_in_user(
email=user_email,
password=user_pass
)
app_object.switch_screen_to_dashboard()
except SignInError as error:
self.prompt_error_message(
'email_label',
error.message
)
'''
This module contains utility functions
'''
import hashlib
def clean_email(user_email):
'''
clean_email removes unnecessary spaces from Full Name
'''
return user_email.strip('\t\n\r ')
def hash_password(password):
'''
hash_password converts plain text password into sha256 hash
'''
return hashlib.sha256(password.encode()).hexdigest()
'''
This module contains Validation functions
'''
import re
from modules.signin.utils import clean_email
from modules.signin.exceptions import SignInError
def validate_email(user_email):
'''
Validating Email provided to check for proper mail format and
only alphabets
'''
user_email = clean_email(user_email)
if not re.match(r'[^@]+@[^@]+\.[^@]+', user_email):
raise SignInError('Incorrect Format')
user_email = user_email.strip(' ').split('.')
for parts in user_email:
parts = parts.split('@')
if not all(part.isalpha() for part in parts):
raise SignInError('Incorrect Format')
return True
def validate_password(password):
'''
Validating whether or not the password is submitted by
the user
'''
if not password:
raise SignInError('Enter password')
return True
......@@ -3,7 +3,7 @@ This module contains services to be utilized by the application
'''
import sqlite3
from settings import initializing_database, USER_INFOMATION_TABLE
from settings import get_db_connection, USER_INFOMATION_TABLE
from modules.signup.exceptions import SignUpError
from modules.signup.utils import (
generate_uuid,
......@@ -13,7 +13,7 @@ from modules.signup.utils import (
)
def sign_up_user(**user_info):
def sign_up_user(email, password, full_name, language, timezone):
'''
sign_up_user creates connection with the sqlite3 database,
calls methods to clean up full_name, convert password into
......@@ -21,26 +21,30 @@ def sign_up_user(**user_info):
Would result in a False statement if the Email is already
present.
'''
connection = initializing_database()
connection = get_db_connection()
db_cursor = connection.cursor()
user_info['table_name'] = USER_INFOMATION_TABLE
user_info['user_id'] = generate_uuid()
user_info['email'] = clean_email(user_info['email'])
user_info['password'] = hash_password(user_info['password'])
user_info['full_name'] = clean_full_name(user_info['full_name'])
user_info = {
'table_name': USER_INFOMATION_TABLE,
'user_id': generate_uuid(),
'email': clean_email(email),
'password': hash_password(password),
'full_name': clean_full_name(full_name),
'language': language,
'timezone': timezone,
}
try:
sign_up_query = '''
INSERT INTO {table_name} VALUES
("{user_id}",
"{email}",
"{password}",
"{full_name}",
"{language}",
"{timezone}")
'''
db_cursor.execute(sign_up_query.format(**user_info))
('{user_id}',
'{email}',
'{password}',
'{full_name}',
'{language}',
'{timezone}')