Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
49 commits
Select commit Hold shift + click to select a range
c8311e0
clear boards function implemented
gergicsmilan May 27, 2019
14b00ce
implemented connection.py and (Fru: sql installéson fájl)
gergicsmilan May 27, 2019
b4c0b23
sql requests implemented for board, card and status tables
fkcreates May 27, 2019
730c2f4
test
fkcreates May 28, 2019
0311eea
test2
fkcreates May 28, 2019
dd8c177
listing board and cards dinamically from sql database is implemented
fkcreates May 29, 2019
6945d9e
my chg
gergicsmilan May 29, 2019
49a7c4a
merge
gergicsmilan May 29, 2019
e37f8c0
bootstrap initialized
fkcreates May 29, 2019
b18339a
Merge branch 'development' of https://github.com/gergicsmilan/proman-…
gergicsmilan May 29, 2019
2640d5b
created post req function, implemented add new board function..
gergicsmilan May 30, 2019
6062e05
delete board button added
kornelgatter May 30, 2019
786bea4
adding new card feature is available for the user
fkcreates May 30, 2019
9fc8f38
renamed button to add new card
fkcreates May 30, 2019
58895c9
fixed button position
gergicsmilan May 30, 2019
6dea3b9
delete button event listener function added to dom
kornelgatter May 30, 2019
ec4b934
pep 8 issues handled
fkcreates May 30, 2019
e8d95c7
Merge branch 'development' of https://github.com/gergicsmilan/proman-…
gergicsmilan May 30, 2019
25f448a
merge
kornelgatter May 30, 2019
a6c1c2c
dfgkdfh
BalintAts May 30, 2019
9f724aa
conslicthandling
BalintAts May 30, 2019
f559e1d
merge conflict handling
fkcreates May 30, 2019
dae238e
toggle button done with Dany
BalintAts May 30, 2019
1d1fd21
delete board implemented
kornelgatter May 30, 2019
0471dd0
toggle button done with Dani
BalintAts May 30, 2019
19d2a70
merge conflict resolve
kornelgatter May 30, 2019
02d093e
trying things
fkcreates May 30, 2019
acc9d78
Merge branch 'development' of https://github.com/gergicsmilan/proman-…
fkcreates May 30, 2019
af8475c
fsrfusehfih
BalintAts May 30, 2019
0b3a079
fixed add new board click bug
gergicsmilan May 30, 2019
49e5139
merge conflict handled
gergicsmilan May 30, 2019
14837fa
Merge branch 'development' of https://github.com/gergicsmilan/proman-…
fkcreates May 30, 2019
3d68801
delete card implemented, with bugs
kornelgatter Jun 12, 2019
ddba51f
some bugs fixed
kornelgatter Jun 13, 2019
339789f
Merge branch 'development' of https://github.com/gergicsmilan/proman-…
kornelgatter Jun 13, 2019
8dafd5e
delete card implemented
kornelgatter Jun 13, 2019
d584d70
Merge branch 'deletecard' into development
kornelgatter Jun 13, 2019
f572585
Merge branch 'development' of https://github.com/gergicsmilan/proman-…
fkcreates Jun 13, 2019
0019178
conflict
BalintAts Jun 13, 2019
851b1f0
megint elbaszodott
BalintAts Jun 13, 2019
37c2f61
dragndrop kesz
BalintAts Jun 13, 2019
8c9ef5b
second try on renaming, taking out original board title is ok, switch…
fkcreates Jun 13, 2019
dd2ad3e
escape and enter keydowns work well, not implementing in database yet…
fkcreates Jun 13, 2019
b04cdcb
renaming board user story works with little bug: once you rename the …
fkcreates Jun 13, 2019
ef26a0b
conflict handling
BalintAts Jun 13, 2019
a6b18f9
conflict with stupid kapcsos
BalintAts Jun 13, 2019
2daae6a
registration, navbar, reg modal, login modal
gergicsmilan Jun 14, 2019
b4aa34c
merge conflict handling well
fkcreates Jun 14, 2019
471cf56
changes with Dani, refactoring a bit of the code
fkcreates Jun 14, 2019
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
52 changes: 52 additions & 0 deletions connection.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
# Creates a decorator to handle the database connection/cursor opening/closing.
# Creates the cursor with RealDictCursor, thus it returns real dictionaries, where the column names are the keys.
import os
import psycopg2
import psycopg2.extras


def get_connection_string():
# setup connection string
# to do this, please define these environment variables first
user_name = os.environ.get('PSQL_USER_NAME')
password = os.environ.get('PSQL_PASSWORD')
host = os.environ.get('PSQL_HOST')
database_name = os.environ.get('PSQL_DB_NAME')

env_variables_defined = user_name and password and host and database_name

if env_variables_defined:

# this string describes all info for psycopg2 to connect to the database
return 'postgresql://{user_name}:{password}@{host}/{database_name}'.format(
user_name=user_name,
password=password,
host=host,
database_name=database_name
)
else:
raise KeyError('Some necessary environment variable(s) are not defined')


def open_database():
try:
connection_string = get_connection_string()
connection = psycopg2.connect(connection_string)
connection.autocommit = True
except psycopg2.DatabaseError as exception:
print('Database connection problem')
raise exception
return connection


def connection_handler(function):
def wrapper(*args, **kwargs):
connection = open_database()
# we set the cursor_factory parameter to return with a RealDictCursor cursor (cursor which provide dictionaries)
dict_cur = connection.cursor(cursor_factory=psycopg2.extras.RealDictCursor)
ret_value = function(dict_cur, *args, **kwargs)
dict_cur.close()
connection.close()
return ret_value

return wrapper
43 changes: 34 additions & 9 deletions data_handler.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,15 +16,40 @@ def get_boards():
Gather all boards
:return:
"""
return persistence.get_boards(force=True)
return persistence.get_boards()


def get_cards_for_board(board_id):
persistence.clear_cache()
all_cards = persistence.get_cards()
matching_cards = []
for card in all_cards:
if card['board_id'] == str(board_id):
card['status_id'] = get_card_status(card['status_id']) # Set textual status for the card
matching_cards.append(card)
return matching_cards
return persistence.get_cards_for_board(board_id)


def get_cards():
return persistence.get_cards()


def add_board(board_title):
return persistence.add_new_board(board_title)


def add_card(card_title, board_id, status_id):
return persistence.add_new_card(card_title, board_id, status_id)


def delete_board(id):
return persistence.delete_board(id)


def delete_card(id):
return persistence.delete_card(id)


def change_status( id, status_id):
return persistence.change_status( id, status_id)

def rename_board(board_id, title):
return persistence.rename_board(board_id, title)


def addNewUser(username, password):
return persistence.addNewUser(username, password)

75 changes: 71 additions & 4 deletions main.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
from flask import Flask, render_template, url_for
from util import json_response
from flask import Flask, render_template, url_for, request, json
from util import json_response, hash_password

import data_handler

Expand All @@ -23,16 +23,83 @@ def get_boards():
return data_handler.get_boards()


@app.route("/get-cards/<int:board_id>")
@app.route("/get-cards/<board_id>")
@json_response
def get_cards_for_board(board_id: int):
def get_cards_for_board(board_id):
"""
All cards that belongs to a board
:param board_id: id of the parent board
"""
return data_handler.get_cards_for_board(board_id)


@app.route("/get-cards")
@json_response
def get_cards():
"""
All cards that belongs to a board
:param board_id: id of the parent board
"""
return data_handler.get_cards()


@app.route("/post-new-board", methods=['POST', 'GET'])
@json_response
def post_new_board():
response_data = json.loads(request.data)
data_handler.add_board(response_data['title'])
return response_data


@app.route('/post-new-card', methods=['POST', 'GET'])
@json_response
def post_new_card():
response_data = json.loads(request.data)
data_handler.add_card(response_data['title'], response_data['board_id'], response_data['status_id'])
return response_data


@app.route('/delete-board', methods=['POST', 'GET'])
@json_response
def delete_board():
response_data = json.loads(request.data)
data_handler.delete_board(response_data['id'])
return response_data


@app.route('/delete-card', methods=['POST', 'GET'])
@json_response
def delete_card():
response_data = json.loads(request.data)
data_handler.delete_card(response_data['id'])
return response_data


@app.route('/change-status', methods=['POST', 'GET'])
@json_response
def change_status():
response_data = json.loads(request.data)
data_handler.change_status(response_data['id'], response_data['status_id'])


@app.route('/rename-board', methods=['POST', 'GET'])
@json_response
def rename_board():
response_data = json.loads(request.data)
data_handler.rename_board(response_data['id'], response_data['title'])

return response_data


@app.route('/reg', methods=["POST"])
@json_response
def reg():
reg_data = json.loads(request.data)
hashed = hash_password(reg_data['password'])
data_handler.addNewUser(reg_data['username'], hashed)
return reg_data


def main():
app.run(debug=True)

Expand Down
141 changes: 104 additions & 37 deletions persistence.py
Original file line number Diff line number Diff line change
@@ -1,51 +1,118 @@
import csv
import connection

STATUSES_FILE = './data/statuses.csv'
BOARDS_FILE = './data/boards.csv'
CARDS_FILE = './data/cards.csv'

_cache = {} # We store cached data in this dict to avoid multiple file readings
@connection.connection_handler
def get_statuses(cursor):
cursor.execute("""
SELECT id, title FROM status;
""")

statuses = cursor.fetchall()
return statuses

def _read_csv(file_name):
"""
Reads content of a .csv file
:param file_name: relative path to data file
:return: OrderedDict
"""
with open(file_name) as boards:
rows = csv.DictReader(boards, delimiter=',', quotechar='"')
formatted_data = []
for row in rows:
formatted_data.append(dict(row))
return formatted_data

@connection.connection_handler
def get_boards(cursor):
cursor.execute("""
SELECT id, title FROM board;
""")

def _get_data(data_type, file, force):
"""
Reads defined type of data from file or cache
:param data_type: key where the data is stored in cache
:param file: relative path to data file
:param force: if set to True, cache will be ignored
:return: OrderedDict
"""
if force or data_type not in _cache:
_cache[data_type] = _read_csv(file)
return _cache[data_type]
boards = cursor.fetchall()
return boards


def clear_cache():
for k in list(_cache.keys()):
_cache.pop(k)
@connection.connection_handler
def get_cards(cursor):
cursor.execute("""
SELECT id, board_id, title, status_id, card_order FROM card;
""")

cards = cursor.fetchall()
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Useless variable definition

return cards

def get_statuses(force=False):
return _get_data('statuses', STATUSES_FILE, force)

@connection.connection_handler
def get_cards_for_board(cursor, board_id):
cursor.execute("""SELECT id, board_id, title, status_id, card_order FROM card
WHERE board_id = %(board_id)s;
""",
{'board_id': board_id})

def get_boards(force=False):
return _get_data('boards', BOARDS_FILE, force)
cards = cursor.fetchall()
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Useless variable definition

return cards


def get_cards(force=False):
return _get_data('cards', CARDS_FILE, force)
@connection.connection_handler
def get_cards(cursor):
cursor.execute("""SELECT id, board_id, title, status_id, card_order FROM card;
""")

cards = cursor.fetchall()
print(cards)
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

printing in production code?

return cards


@connection.connection_handler
def add_new_board(cursor, board_title):
cursor.execute("""INSERT INTO board (title) VALUES (%(board_title)s);
""",
{'board_title': board_title})


@connection.connection_handler
def add_new_card(cursor, card_title, board_id, status_id):
cursor.execute("""
INSERT INTO card (title, board_id, status_id) VALUES (%(card_title)s, %(board_id)s, %(status_id)s);
""",
{'card_title': card_title,
'board_id': board_id,
'status_id': status_id})


@connection.connection_handler
def delete_board(cursor, board_id):
cursor.execute("""
DELETE FROM card
WHERE board_id = %(board_id)s;

DELETE FROM board
WHERE id = %(board_id)s;
""",
{'board_id': board_id})


@connection.connection_handler
def delete_card(cursor, id):
cursor.execute("""
DELETE FROM card
WHERE id = %(id)s;
""",
{'id': id})


@connection.connection_handler
def change_status(cursor, id, status_id):
cursor.execute("""
UPDATE card
SET status_id = %(status_id)s
WHERE id = %(id)s;
""", {'id': id, 'status_id': status_id})


@connection.connection_handler
def rename_board(cursor, board_id, title):
cursor.execute("""
UPDATE board
SET title = %(title)s
WHERE id = %(board_id)s;
""",
{'board_id': board_id,
'title': title})


@connection.connection_handler
def addNewUser(cursor, username, password):
cursor.execute("""
INSERT INTO users (username, password) VALUES(%(username)s, %(password)s);
""",
{'username': username, 'password': password})
Loading