diff --git a/Workshop3/Procfile b/Workshop3/Procfile
new file mode 100644
index 0000000..93f040b
--- /dev/null
+++ b/Workshop3/Procfile
@@ -0,0 +1 @@
+web: gunicorn app:app --log-file -
\ No newline at end of file
diff --git a/Workshop3/Templates/404.html b/Workshop3/Templates/404.html
new file mode 100644
index 0000000..48a6214
--- /dev/null
+++ b/Workshop3/Templates/404.html
@@ -0,0 +1,10 @@
+
+
+
+
+ 404 page
+
+
+ Wrong action value: {{action_value}}
+
+
\ No newline at end of file
diff --git a/Workshop3/Templates/all.html b/Workshop3/Templates/all.html
new file mode 100644
index 0000000..2e52778
--- /dev/null
+++ b/Workshop3/Templates/all.html
@@ -0,0 +1,12 @@
+
+
+
+
+ all
+
+
+ Customer {{customer}}
+ Nutrition {{nutrition}}
+
+
+
\ No newline at end of file
diff --git a/Workshop3/Templates/customer.html b/Workshop3/Templates/customer.html
new file mode 100644
index 0000000..457a151
--- /dev/null
+++ b/Workshop3/Templates/customer.html
@@ -0,0 +1,24 @@
+
+
+
+
+ client
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Workshop3/Templates/nutrition.html b/Workshop3/Templates/nutrition.html
new file mode 100644
index 0000000..0fd7bd3
--- /dev/null
+++ b/Workshop3/Templates/nutrition.html
@@ -0,0 +1,25 @@
+
+
+
+
+ event
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Workshop3/WorkShop3 Flask.pdf b/Workshop3/WorkShop3 Flask.pdf
new file mode 100644
index 0000000..162def7
Binary files /dev/null and b/Workshop3/WorkShop3 Flask.pdf differ
diff --git a/Workshop3/app.py b/Workshop3/app.py
new file mode 100644
index 0000000..7f87ac1
--- /dev/null
+++ b/Workshop3/app.py
@@ -0,0 +1,73 @@
+from flask import Flask, request, render_template
+
+app = Flask(__name__)
+
+
+nutrition_dictionary = {
+ "nutr_title": "Big chicken nutrition pack",
+ "nutr_brand": "Purina Pro plan",
+ "nutr_ingredient": "Chicken",
+ "nutr_weight": 10,
+ "nutr_price": 400,
+ "nutr_description": "This is a food for dogs"
+}
+
+customer_dictionary = {
+ "cust_name": "Fedor",
+ "cust_surname": "Kuprianov",
+ "cust_login": "fedyakup",
+ "cust_pass": "poc123poc",
+ "cust_email": "fedya_kup@gmail.com",
+ "cust_adress": "Volgogradska str."
+}
+
+
+@app.route('/')
+def main():
+ return 'Priv che delaesh'
+
+
+
+@app.route('/api/', methods=['GET'])
+def apiget(action):
+ if action == "nutrition":
+ return render_template('nutrition.html', nutrition=nutrition_dictionary)
+ elif action == "customer":
+ return render_template('customer.html', customer=customer_dictionary)
+ elif action == "all":
+ return render_template('all.html', nutrition=nutrition_dictionary, customer=customer_dictionary)
+ else:
+ return render_template('404.html', action_value=action)
+
+
+@app.route('/api/nutrition/submit', methods=['POST'])
+def nitrition_submit():
+ if request.method == "POST":
+ nutrition_dictionary["Title"] = request.form['title']
+ nutrition_dictionary["Brand"] = request.form['brand']
+ nutrition_dictionary["Ingredient"] = request.form['ingredient']
+ nutrition_dictionary["Weight"] = request.form['weight']
+ nutrition_dictionary["Price"] = request.form['price']
+ nutrition_dictionary["Short description"] = request.form['descr']
+ return render_template("all.html", nutrition=nutrition_dictionary, customer=customer_dictionary)
+ else:
+ return render_template("nutrition.html", nutrition=nutrition_dictionary)
+
+
+@app.route('/api/customer/submit', methods=['POST'])
+def customer_submit():
+ if request.method == "POST":
+ customer_dictionary["Name"] = request.form['name']
+ customer_dictionary["Surname"] = request.form['surname']
+ customer_dictionary["Login"] = request.form['login']
+ customer_dictionary["Password"] = request.form['pass']
+ customer_dictionary["E-mail"] = request.form['email']
+ customer_dictionary["Adress"] = request.form['adress']
+ return render_template("all.html", nutrition=nutrition_dictionary, customer=customer_dictionary)
+ else:
+ return render_template("customer.html", customer=customer_dictionary)
+
+
+
+if __name__ == "__main__":
+ app.run(debug=True)
\ No newline at end of file
diff --git a/Workshop3/requirements.txt b/Workshop3/requirements.txt
new file mode 100644
index 0000000..1c4caa9
--- /dev/null
+++ b/Workshop3/requirements.txt
@@ -0,0 +1,7 @@
+click==7.1.2
+Flask==1.1.2
+itsdangerous==1.1.0
+Jinja2==2.11.2
+MarkupSafe==1.1.1
+Werkzeug==1.0.1
+gunicorn == 20.0.4
\ No newline at end of file
diff --git a/Workshop3/runtime.txt b/Workshop3/runtime.txt
new file mode 100644
index 0000000..f8624ef
--- /dev/null
+++ b/Workshop3/runtime.txt
@@ -0,0 +1 @@
+python-3.8.2
\ No newline at end of file
diff --git a/Workshop4/source/connection.py b/Workshop4/source/connection.py
new file mode 100644
index 0000000..ca6bc03
--- /dev/null
+++ b/Workshop4/source/connection.py
@@ -0,0 +1,11 @@
+from sqlalchemy.engine import create_engine
+
+username = 'user'
+password = '1234'
+sid = 'XE'
+host = 'localhost'
+port = '1521'
+
+
+oracle_connection_path = 'oracle+cx_oracle://{username}:{password}@{host}:{port}/{sid}'
+engine = create_engine(oracle_connection_path)
\ No newline at end of file
diff --git a/Workshop4/source/workshop4.py b/Workshop4/source/workshop4.py
new file mode 100644
index 0000000..8dcacf4
--- /dev/null
+++ b/Workshop4/source/workshop4.py
@@ -0,0 +1,120 @@
+from sqlalchemy import Integer, String, Column, MetaData, Float, DateTime, ForeignKey, CheckConstraint
+from sqlalchemy.ext.declarative import declarative_base
+from sqlalchemy_utils import EmailType
+from database_connection import engine
+from sqlalchemy.orm import sessionmaker
+from sqlalchemy.orm import relationship
+import re
+Base = declarative_base()
+meta = MetaData()
+
+
+class nutrition(Base):
+ __tablename__ = 'nutrition'
+ nutr_title = Column(String(100), primary_key=True, nullable=False)
+ nutr_brand = Column(String(40), primary_key=True, nullable=False)
+ nutr_price = Column(Float, primary_key=True, nullable=False)
+ nutr_weight = Column(Float, primary_key=True, nullable=False)
+ nutr_ingredient = Column(String(30), primary_key=True, nullable=False)
+ nutr_description = Column(String(500), nullable=False)
+ CheckConstraint('price > 0', name='check_price')
+ CheckConstraint('weight > 0', name='check_weight')
+
+
+
+ @classmethod
+ def add(cls, nutr_title, nutr_brand, nutr_price, nutr_weight, nutr_ingredient, nutr_description):
+ if not nutr_title.isalpha() or not nutr_brand.isalpha() or not nutr_ingredient.isalpha() or not nutr_description.isalpha() \
+ or not isinstance(nutr_price, float) or not isinstance(nutr_weight, float):
+ print("Data is not correct!")
+ return -1
+ Session = sessionmaker(bind=engine)
+ session = Session()
+ Nutrition = nutrition(nutr_title=nutr_title, nutr_brand=nutr_brand, nutr_price=nutr_price, nutr_weight=nutr_weight, nutr_ingredient=nutr_ingredient,
+ nutr_description=nutr_description)
+ session.add(Nutrition)
+ session.commit()
+
+class customer(Base):
+ __tablename__ = 'customer'
+
+ cust_name = Column(String(80), nullable=False)
+ cust_surname = Column(String(90))
+ cust_login = Column(String(40), primary_key=True, nullable=False)
+ cust_password = Column(String(50), nullable=False)
+ cust_email = Column(EmailType, nullable=False)
+ cust_adress = Column(String(300), nullable=False)
+
+ @classmethod
+ def add(cls, cust_name, cust_surname, cust_login, cust_password, cust_email, cust_adress):
+ if not cust_name.isalpha() or not cust_surname.isalpha() or not cust_login.isalpha() or not cust_password.isalpha() \
+ or not cust_adress.isalpha() or not re.match(r"[^@]+@[^@]+\.[^@]+", cust_email):
+ print("Data is not correct!")
+ return -1
+ Session = sessionmaker(bind=engine)
+ session = Session()
+ Customer1 = customer(cust_name=cust_name, cust_surname=cust_surname, cust_login=cust_login, cust_password=cust_password,
+ cust_email=cust_email, cust_adress=cust_adress)
+ session.add(Customer1)
+ session.commit()
+
+
+class review(Base):
+ __tablename__ = 'review'
+ nutr_title = Column(String(100), ForeignKey('nutrition.nutr_title'), primary_key=True, nullable=False)
+ nutr_brand = Column(String(40), ForeignKey('nutrition.nutr_brand'), primary_key=True, nullable=False)
+ nutr_price_fk = Column(Float, ForeignKey('nutrition.nutr_price'))
+ nutr_ingredient_fk = Column(String(30), ForeignKey('nutrition.nutr_ingredient'))
+ reviews = Column(String(600), nullable=False)
+ rating = Column(Integer, nullable=False)
+ CheckConstraint('nutr_price_fk >= 0', name='check_nutr_price_fk')
+ CheckConstraint('rating >= 0', name='check_rating')
+ nutritions = relationship("nutrition", foreign_keys=[nutr_title])
+ nutritions_brand = relationship("nutrition", foreign_keys=[nutr_brand])
+ nutritions_price = relationship("nutrition", foreign_keys=[nutr_price_fk])
+ nutritions_ingredient = relationship("nutrition", foreign_keys=[nutr_ingredient_fk])
+
+ @classmethod
+ def add(cls, nutr_title, nutr_brand, nutr_price_fk, nutr_ingredient_fk, reviews, rating):
+ if not nutr_title.isalpha() or not nutr_brand.isalpha() \
+ or not isinstance(nutr_price_fk, float) or not nutr_ingredient_fk.isalpha() or not reviews.isalpha() \
+ or not isinstance(rating, int):
+ print("Data is not correct!")
+ return -1
+ Session = sessionmaker(bind=engine)
+ session = Session()
+ review1 = review(nutr_title=nutr_title, nutr_brand=nutr_brand, nutr_price_fk=nutr_price_fk,
+ nutr_ingredient_fk=nutr_ingredient_fk, reviews=reviews, rating=rating)
+ session.add(review1)
+ session.commit()
+
+
+class cust_order(Base):
+ __tablename__ = 'cust_order'
+
+ nutr_title = Column(String(100), ForeignKey('nutrition.nutr_title'), primary_key=True, nullable=False)
+ nutr_brand = Column(String(40), ForeignKey('nutrition.nutr_brand'), primary_key=True, nullable=False)
+ nutr_price = Column(Float, ForeignKey('nutrition.nutr_price'))
+ nutr_ingredient_fk = Column(String(30), ForeignKey('nutrition.genre'), nullable=False)
+ status = Column(String(25), nullable=False)
+ CheckConstraint('price >= 0', name='check_price')
+ nutritions = relationship("nutrition", foreign_keys=[nutr_title])
+ nutritions_brand = relationship("nutrition", foreign_keys=[nutr_brand])
+ nutritions_price = relationship("nutrition", foreign_keys=[nutr_price])
+ nutritions_ingredient = relationship("nutrition", foreign_keys=[nutr_ingredient_fk])
+
+ @classmethod
+ def add(cls, nutr_title, nutr_brand, nutr_price, nutr_ingredient_fk, status):
+ if not nutr_title.isalpha() or not nutr_brand.isalpha() \
+ or not isinstance(nutr_price, float) or not nutr_brand.isalpha() or not status.isalpha():
+ print("Data is not correct!")
+ return -1
+ Session = sessionmaker(bind=engine)
+ session = Session()
+ cust_order1 = cust_order(nutr_title=nutr_title, nutr_brand=nutr_brand, nutr_price=nutr_price, nutr_ingredient_fk=nutr_ingredient_fk,
+ status=status)
+ session.add(cust_order1)
+ session.commit()
+
+
+Base.metadata.create_all(engine)
\ No newline at end of file
diff --git a/Workshop4/sql/add_tables.sql b/Workshop4/sql/add_tables.sql
new file mode 100644
index 0000000..7b35c3a
--- /dev/null
+++ b/Workshop4/sql/add_tables.sql
@@ -0,0 +1,46 @@
+create table nutrition(
+ nutr_title VARCHAR2(100),
+ nutr_brand VARCHAR2(40),
+ nutr_price NUMBER(8, 2),
+ nutr_weight NUMBER(6, 2),
+ nutr_ingredient VARCHAR2(30),
+ nutr_description VARCHAR2(500) NOT NULL,
+ CONSTRAINT nutr_constraint PRIMARY KEY (nutr_title, nutr_brand, nutr_price, nutr_ingredient),
+ CONSTRAINT check_nutr_price CHECK (nutr_price >= 0),
+ CONSTRAINT check_nutr_weight CHECK (nutr_weight >= 0),
+);
+
+create table customer(
+ cust_name VARCHAR2(80) NOT NULL,
+ cust_surname VARCHAR2(90),
+ cust_login VARCHAR2(40) NOT NULL PRIMARY KEY,
+ cust_password VARCHAR2(50) NOT NULL,
+ cust_email VARCHAR2(50) NOT NULL UNIQUE,
+ cust_adress VARCHAR2(300) NOT NULL
+ CONSTRAINT cust_email_check CHECK (REGEXP_LIKE (cust_email, '^(\S+)\@(\S+)\.(\S+)$'))
+);
+
+create table review(
+ nutr_title VARCHAR2(100) NOT NULL,
+ nutr_brand VARCHAR2(40) NOT NULL,
+ nutr_price_fk NUMBER(8, 2),
+ nutr_ingredient_fk VARCHAR2(30),
+ reviews VARCHAR2(600) NOT NULL,
+ rating INTEGER NOT NULL,
+ CONSTRAINT review_constraint PRIMARY KEY (nutr_title, nutr_brand),
+ CONSTRAINT check_review_nutr_price CHECK (nutr_price_fk >= 0),
+ CONSTRAINT rating CHECK (rating > 0 and rating <= 10)
+);
+
+
+create table cust_order(
+ nutr_title VARCHAR2(100) NOT NULL,
+ nutr_brand VARCHAR2(40) NOT NULL,
+ nutr_price NUMBER(8, 2) NOT NULL,
+ nutr_ingredient_fk VARCHAR2(30),
+ status VARCHAR2(25) NOT NULL,
+ CONSTRAINT order_constraint PRIMARY KEY (nutr_title, nutr_brand),
+ CONSTRAINT check_order_nutr_price CHECK (nutr_price >= 0)
+);
+
+
diff --git a/Workshop4/sql/constraints.sql b/Workshop4/sql/constraints.sql
new file mode 100644
index 0000000..923e007
--- /dev/null
+++ b/Workshop4/sql/constraints.sql
@@ -0,0 +1,88 @@
+ALTER TABLE review
+ADD CONSTRAINT review_fk_constraint
+ FOREIGN KEY (nutrition_title, nutr_brand, nutr_price_fk, nutr_ingredient_fk)
+ REFERENCES nutrition (nutr_title, nutr_brand, nutr_price, nutr_ingredient);
+
+ALTER TABLE nutrition_order
+ADD CONSTRAINT order_fk_constraint
+ FOREIGN KEY (nutrition_title, nutr_brand, nutr_price, nutr_ingredient_fk)
+ REFERENCES nutrition (nutr_title, nutr_brand, nutr_price, nutr_ingredient);
+
+CREATE OR REPLACE TRIGGER check_nutr_ingredient
+BEFORE UPDATE OF nutr_ingredient ON nutrition
+FOR EACH ROW
+DECLARE
+str VARCHAR2(20);
+BEGIN
+
+select regexp_replace(:new.nutr_ingredient, '[[:alpha:]]|_') into str from dual;
+IF str is not null then
+ raise_application_error(-20000, 'Wrong ingredient format for update!');
+END IF;
+END;
+/
+
+CREATE OR REPLACE TRIGGER check_nutr_ingredient_insert
+BEFORE INSERT ON nutrition
+FOR EACH ROW
+DECLARE
+str VARCHAR2(20);
+BEGIN
+select regexp_replace(:new.nutr_ingredient, '[[:alpha:]]|_') into str from dual;
+IF str is not null then
+ raise_application_error(-20000, 'Wrong ingredient format for insert!');
+END IF;
+END;
+/
+
+CREATE OR REPLACE TRIGGER check_cust_name_update
+BEFORE UPDATE of cust_name ON customer
+FOR EACH ROW
+DECLARE
+str VARCHAR2(20);
+BEGIN
+select regexp_replace(:new.cust_name, '[[:alpha:]]|_') into str from dual;
+IF str is not null then
+ raise_application_error(-20000, 'Wrong name format for update!');
+END IF;
+END;
+/
+
+CREATE OR REPLACE TRIGGER check_cust_name_insert
+BEFORE Insert ON customer
+FOR EACH ROW
+DECLARE
+str VARCHAR2(20);
+BEGIN
+select regexp_replace(:new.cust_name, '[[:alpha:]]|_') into str from dual;
+IF str is not null then
+ raise_application_error(-20000, 'Wrong name format for insert!');
+END IF;
+END;
+/
+
+CREATE OR REPLACE TRIGGER check_cust_surname_update
+BEFORE UPDATE of cust_surname ON customer
+FOR EACH ROW
+DECLARE
+str VARCHAR2(20);
+BEGIN
+select regexp_replace(:new.cust_surname, '[[:alpha:]]|_') into str from dual;
+IF str is not null then
+ raise_application_error(-20000, 'Wrong surname format for update!');
+END IF;
+END;
+/
+
+CREATE OR REPLACE TRIGGER check_cust_surname_insert
+BEFORE Insert ON customer
+FOR EACH ROW
+DECLARE
+str VARCHAR2(20);
+BEGIN
+select regexp_replace(:new.cust_surname, '[[:alpha:]]|_') into str from dual;
+IF str is not null then
+ raise_application_error(-20000, 'Wrong surname format for insert!');
+END IF;
+END;
+/
\ No newline at end of file
diff --git a/heroku app.txt b/heroku app.txt
new file mode 100644
index 0000000..af8baad
--- /dev/null
+++ b/heroku app.txt
@@ -0,0 +1 @@
+https://workshop3krupovych.herokuapp.com
\ No newline at end of file