diff --git a/.gitignore b/.gitignore index 49974f9..85e884c 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,6 @@ __pycache__ volumes/ .secrets/ +static/ +!.static/150x150.png +.DS_Store diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..144cc76 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,20 @@ +#FROM mysql/mysql-server:latest +FROM python:3.9.7-slim + +WORKDIR /python + + +RUN apt-get update -y && \ + apt-get install -y \ + python \ + default-mysql-client \ + python3-dev \ + default-libmysqlclient-dev \ + build-essential +RUN pip install \ + flask \ + flask-sqlalchemy \ + mysqlclient \ + boto3 + +ADD ./ ./ diff --git a/db.py b/db.py index d1757dd..d92a5c0 100644 --- a/db.py +++ b/db.py @@ -1,12 +1,19 @@ -import mysql.connector +import os +from flask_sqlalchemy import SQLAlchemy class Database: - def __init__(self): - self.db = mysql.connector.connect( - host = 'localhost', - user = 'root', - password = '', - database = 'twitter_development' - ) + _instance = None + app = None + database = None - self.cursor = self.db.cursor() \ No newline at end of file + def __new__(klass, flask_app): + if klass._instance is None: + klass.app = flask_app + klass._instance = super(Database, klass).__new__(klass) + klass.__initialize(klass) + return klass._instance + + def __initialize(klass): + klass.app.config['SQLALCHEMY_DATABASE_URI'] = os.environ['SQLALCHEMY_DATABASE_URI'] + klass.app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False + klass.database = SQLAlchemy(klass.app) diff --git a/follower.py b/follower.py index 5f81926..f0477dd 100644 --- a/follower.py +++ b/follower.py @@ -1,27 +1,31 @@ +from flask import json +from user import Users from db import Database -class Follower: - def __init__(self): - db = Database() - self.db = db.db - self.cursor = db.cursor +db = Database.database - def follow(self, user_id, follow_id): - sql = 'SELECT COUNT(id) FROM followers WHERE user_id = %s AND follow_id = %s' % (user_id, follow_id) - self.cursor.execute(sql) - total = dict(zip(self.cursor.column_names, self.cursor.fetchone())) - if total['COUNT(id)'] > 0: - return False - else: - next_sql = 'INSERT INTO followers (user_id, follow_id) VALUES (%s, %s)' % (user_id, follow_id) +class Followers(db.Model): + id = db.Column(db.Integer, primary_key = True) + user_id = db.Column(db.Integer, db.ForeignKey(Users.id), nullable = True) + follow_id = db.Column(db.Integer, db.ForeignKey(Users.id), nullable = True) - self.cursor.execute(next_sql) - self.db.commit() - return True + def __init__(self, data): + self.user_id = data['user_id'] + self.follow_id = data['follow_id'] - def unfollow(self, user_id, follow_id): - sql = 'DELETE FROM followers WHERE user_id = %s AND follow_id = %s' % (user_id, follow_id) - self.cursor.execute(sql) - self.db.commit() + @classmethod + def search(self, data): + return Followers.query.filter_by(user_id = data['user_id'], follow_id = data['follow_id']).first() - return True \ No newline at end of file + def create(self): + db.session.add(self) + db.session.commit() + return self + + def delete(self): + db.session.delete(self) + db.session.commit() + return self + + def to_json(self): + return json.dumps(self, default = lambda o: '', sort_keys = True, indent = 4) diff --git a/heroku.yml b/heroku.yml new file mode 100644 index 0000000..c1338bf --- /dev/null +++ b/heroku.yml @@ -0,0 +1,6 @@ +build: + docker: + web: Dockerfile + +run: + web: python3 main.py diff --git a/login.py b/login.py index 3f4fb3b..b08c8e3 100644 --- a/login.py +++ b/login.py @@ -1,31 +1,23 @@ -from db import Database -import hashlib +from user_info import UserInfos +from user import Users class Login: def __init__(self): - db = Database() - self.db = db.db - self.cursor = db.cursor + pass def signup(self, email, password): - self.cursor.execute('SELECT COUNT(*) FROM users WHERE email = "%s" AND password = "%s"' % (email, self.__to_sha256(password))) - (total,) = self.cursor.fetchone() - if total <= 0: - self.cursor.execute('INSERT INTO users (email, password) VALUES ("%s", "%s")' % (email, self.__to_sha256(password))) - self.db.commit() - self.cursor.execute('SELECT * FROM users WHERE email = "%s"' % email) - (id, email, _) = self.cursor.fetchone() - return (id, email) + exists_user = Users.search({ 'email': email, 'password': password}) + if exists_user: + return exists_user else: - return (None, None) - + u = Users({ 'email': email, 'password': password }) + created_user = u.create() + UserInfos.initial_to_create(created_user.id) + return created_user + def login(self, email, password): - self.cursor.execute('SELECT * FROM users LEFT JOIN user_infos ON users.id = user_infos.user_id WHERE email = "%s" AND password = "%s"' % (email, self.__to_sha256(password))) - (id, email, _, _, _, display_name, user_name, interests, _, _) = self.cursor.fetchone() - if id: - return (id, email, display_name, user_name, interests) + exists_user = Users.search({ 'email': email, 'password': password}) + if exists_user: + return exists_user else: - return False - - def __to_sha256(self, password): - return hashlib.sha256(f'{password}'.encode()).hexdigest() \ No newline at end of file + return None diff --git a/main.py b/main.py index c830219..4a94a81 100644 --- a/main.py +++ b/main.py @@ -1,18 +1,22 @@ -from operator import itemgetter -import os -from re import U -from follower import Follower -from tweet_like import TweetLike -from flask.helpers import flash -from werkzeug.utils import secure_filename -from tweet import Tweet -from user_info import UserInfo +from flask.wrappers import Response +from werkzeug.wrappers import response +from db import Database from flask import Flask, render_template, redirect, url_for, request, jsonify + +app = Flask(__name__) +database = Database(app) + +import os, json, boto3, sqlalchemy +from werkzeug.middleware.proxy_fix import ProxyFix from flask.globals import session +from flask.helpers import flash +from werkzeug.utils import secure_filename +from tweet import Tweets +from user_info import UserInfos from login import Login -import json +from follower import Followers +from tweet_like import TweetLikes -app = Flask(__name__) UPLOAD_FOLDER = './static/' ALLOWED_EXTENSIONS = ['png', 'jpg', 'jpeg', 'gif'] @@ -22,7 +26,6 @@ @app.route('/') def home(): __remove_session() - session = None return render_template('sign_up.html') @app.route('/sign_up', methods = ['POST']) @@ -32,12 +35,17 @@ def sign_up(): if (email is None or email == '') or (password is None or password == ''): flash('email or password are not filled') return redirect(url_for('home')) + l = Login() - db_id, db_email = l.signup(email, password) - if db_id: - session['user_id'] = db_id - session['email'] = db_email - return redirect(url_for('tweets')) + try: + user = l.signup(email, password) + except sqlalchemy.exc.IntegrityError: + flash('Duplicate the email, please use another email') + return redirect(url_for('home')) + + if user: + __add_session({ 'user_id': user.id, 'email': user.email }) + return redirect(url_for('profile')) else: flash('The email is exists already') return redirect(url_for('login')) @@ -47,20 +55,25 @@ def login(): if request.method == 'POST': email = request.form['email'] password = request.form['password'] + if email is None: + print(email) + return redirect(url_for('login')) + l = Login() - (id, db_email, display_name, user_name, _) = l.login(email, password) - if email == None: - return redirect(url_for('sign_up')) - elif db_email: - session['user_id'] = id - session['email'] = db_email - if display_name is not None: - session['name'] = display_name - else: - session['name'] = user_name + user = l.login(email, password) + if user: + __add_session({ + 'user_id': user.id, + 'email': user.email, + 'display_name': user.user_info.display_name, + 'user_name': user.user_info.user_name, + 'age': user.user_info.age, + 'interests': user.user_info.interests, + 'profile_image': user.user_info.profile_image + }) return redirect(url_for('tweets')) else: - return redirect(url_for('sign_up')) + return redirect(url_for('home')) elif request.method == 'GET': return render_template('sign_up.html') @@ -69,168 +82,174 @@ def logout(): __remove_session() return redirect(url_for('login')) -@app.route('/chosing_link') -def chosing_link(): - if session['name'] is not None: - name = session['name'] - else: - name = session['email'] - return render_template('chosing_link.html', name = name) - @app.route('/profile') def profile(): if session['user_id'] is None: return redirect(url_for('home')) - u = UserInfo() - id = session['user_id'] - user = u.get_user_info(id) - __add_session(user) + + user_info = UserInfos.search({ 'user_id': session['user_id'] }) + __add_session({ + 'user_id': user_info.user_id, + 'display_name': user_info.display_name, + 'user_name': user_info.user_name, + 'age': user_info.age, + 'interests': user_info.interests, + 'profile_image': user_info.profile_image + }) return render_template('profile.html') -@app.route('/profile/new', methods = ['POST']) -def profile_new(): - u = UserInfo() - id = session['user_id'] - - display_name = request.form['display_name'] or '' - user_name = request.form['user_name'] or '' - age = request.form['age'] or 0 - interests = request.form['interests'] or '' - u.insert_user_info({ 'user_id': id, 'display_name': display_name, 'user_name': user_name, 'age': age, 'interests': interests}) - __add_session(u.get_user_info(id)) - return redirect(url_for('profile')) +# @app.route('/profile/new', methods = ['POST']) +# def profile_new(): +# u = UserInfo() +# id = session['user_id'] + +# display_name = request.form['display_name'] or '' +# user_name = request.form['user_name'] or '' +# age = request.form['age'] or 0 +# interests = request.form['interests'] or '' +# u.insert_user_info({ 'user_id': id, 'display_name': display_name, 'user_name': user_name, 'age': age, 'interests': interests}) +# __add_session(u.get_user_info(id)) +# return redirect(url_for('profile')) @app.route('/profile//edit', methods = ['POST']) def profile_edit(user_id): - u = UserInfo() - id = user_id - display_name = request.form['display_name'] user_name = request.form['user_name'] - age = request.form['age'] or 0 + age = request.form['age'] email = request.form['email'] interests = request.form['interests'] - u.update_user_info({ 'id': id, 'display_name': display_name, 'email': email, 'user_name': user_name, 'age': age, 'interests': interests}) - __add_session(u.get_user_info(id)) + u = UserInfos.search({ 'user_id': user_id }) + updated = u.update({ 'display_name': display_name, 'user_name': user_name, 'age': age, 'email': email, 'interests': interests}) + __add_session({ + 'user_id': updated.user_id, + 'display_name': updated.display_name, + 'user_name': updated.user_name, + 'age': updated.age, + 'interests': updated.interests, + 'profile_image': updated.profile_image, + 'email': updated.user.email + }) return redirect(url_for('profile')) +@app.route('/sign_s3/') +def sign3(): + BUCKET = os.environ.get('S3_BUCKET') + filename = request.args.get('file_name') + filetype = request.args.get('file_type') + + print('respooooooooooooooooooooonse', response) + s3 = boto3.client('s3') + presigned_post = s3.generate_presigned_post( + Bucket = BUCKET, + Key = filename, + Fields = { 'acl': 'public-read', 'Content-Type': filetype }, + Conditions = [ + { 'acl': 'pubilc-read' }, + { 'Content-Type': filetype } + ], + ExpiresIn = 3600 + ) + print('s33333333333333333333333333333333', s3) + print('requeeeeeeeeeeeeeeeeeeeeeeeeest', request) + + return json.dumps({ + 'data': presigned_post, + 'url': 'https://%s.s3.amazonaws.com/%s' % (BUCKET, filename) + }) + @app.route('/profile//upload_image', methods = ['POST']) def upload_image(user_id): - u = UserInfo() filename = __profile_image(request.files['profile_image']) - u.update_profile_image(user_id, filename) - __add_session_only_profile_image(filename) + u = UserInfos.search({ 'user_id': user_id }) + u.upload_image(filename) + __add_session({ 'profile_image': filename }) return redirect(url_for('profile')) @app.route('/profile//get_image') def get_image(user_id): - u = UserInfo() + u = UserInfos.search({ 'user_id': user_id }) result = { 'data': { - 'profile_image': u.get_profile_image(user_id) + 'profile_image': u.get_image() } } return json.dumps(result) @app.route('/tweets') def tweets(): - t = Tweet() - session['tweets'] = t.get_tweets({ 'user_id': session['user_id'] }) + session['tweets'] = Tweets.default_tweets(session['user_id']) return render_template('tweet.html') @app.route('/tweets/new', methods = ['POST']) def tweets_new(): - id = session['user_id'] - - message = request.form['message'] - t = Tweet() - t.add_tweet({ 'user_id': id, 'message': message }) + t = Tweets({ 'user_id': session['user_id'], 'message': request.form['message'] }) + t.create() return redirect(url_for('tweets')) @app.route('/tweets/', methods = ['POST']) def tweets_edit(message_id): - t = Tweet() - if t.invisible_tweet(message_id): - result = { - 'code': 200, - 'message': 'OK' - } - else: - result = { - 'code': 503, - 'message': 'It happened something' - } - return jsonify(values = json.dumps(result)) + t = Tweets.search(message_id) + tweet = t.invisible() + return tweet.to_json() @app.route('/tweets/', methods = ['DELETE']) def tweets_delete(message_id): - t = Tweet() - if t.delete_tweet(message_id): - result = { - 'code': 200, - 'message': 'OK' - } - else: - result = { - 'code': 503, - 'message': 'It happened something' - } - return jsonify(values = json.dumps(result)) + t = Tweets.search(message_id) + tweet = t.delete() + return tweet.to_json() @app.route('/tweets//likes', methods = ['POST']) def tweet_likes(message_id): - tl = TweetLike() - if tl.favorite(message_id, session['user_id']): - result = { - 'code': 200, - 'message': 'OK' - } + data = { 'user_id': session['user_id'], 'tweet_id': message_id } + tl = TweetLikes.search(data) + if tl: + v = tl.delete() else: - result = { - 'code': 503, - 'message': 'It happened something' - } - return json.dumps(result) + new = TweetLikes(data) + v = new.create() + return v.to_json() @app.route('/followers/', methods = ['POST']) def follow(follow_id): - user_id = session['user_id'] - f = Follower() - if f.follow(user_id, follow_id): - result = { - 'code': 200, - 'message': 'OK' - } - elif f.unfollow(user_id, follow_id): - result = { - 'code': 200, - 'message': 'OK' - } + data = { 'user_id': session['user_id'], 'follow_id': follow_id } + f = Followers.search(data) + if f: + v = f.delete() else: - result = { - 'code': 503, - 'message': 'It happened something' - } - return json.dumps(result) - -def __add_session_only_profile_image(filename): - session['profile_image'] = filename + new = Followers(data) + v = new.create() + return v.to_json() + +@app.route('/.well-known/acme-challenge/') +def acme(acme_id): + # dirname = '.well-known/acme-challenge' + r = { + 'a6cWkYIVEtIhQjSajd69Yr89EQ0CmRJess0vEhvQzUg': 'a6cWkYIVEtIhQjSajd69Yr89EQ0CmRJess0vEhvQzUg.k0g5SPH2IEAHNDbJw-rS0SbBUv09vYEAUec_pyVSgV8' + } + return Response(r[acme_id], mimetype='text/plain') + def __add_session(data): - id, email, user_info_id, display_name, user_name, age, interests, profile_image = data - session['user_id'] = id - session['email'] = email - session['user_info_id'] = user_info_id - session['display_name'] = display_name - session['user_name'] = user_name - session['interests'] = interests - session['profile_image'] = profile_image - session['age'] = age + if 'user_id' in data: + session['user_id'] = data['user_id'] + if 'email' in data: + session['email'] = data['email'] + if 'user_info_id' in data: + session['user_info_id'] = data['user_info_id'] + if 'display_name' in data: + session['display_name'] = data['display_name'] + if 'user_name' in data: + session['user_name'] = data['user_name'] + if 'interests' in data: + session['interests'] = data['interests'] + if 'profile_image' in data: + session['profile_image'] = 'https://%s.s3.amazonaws.com/%s' % (os.environ.get('S3_BUCKET'), data['profile_image']) + if 'age' in data: + session['age'] = data['age'] def __remove_session(): - for key in session: - session[key] = None + session = None def __allowed_file(filename): return '.' in filename and filename.rsplit('.', 1)[1].lower() in ALLOWED_EXTENSIONS @@ -245,4 +264,6 @@ def __profile_image(file): if __name__ == '__main__': app.secret_key = 'test' app.config['SESSION_TYPE'] = 'filesystem' - app.run(debug=True) + app.wsgi_app = ProxyFix(app.wsgi_app, x_proto = 1) + port = int(os.environ.get('PORT', 5000)) + app.run(debug = True, host='0.0.0.0', port = port) \ No newline at end of file diff --git a/static/lion.jpg b/static/lion.jpg deleted file mode 100644 index 1d5b7a7..0000000 Binary files a/static/lion.jpg and /dev/null differ diff --git a/static/lion_200x200.jpeg b/static/lion_200x200.jpeg deleted file mode 100644 index 9ac21c5..0000000 Binary files a/static/lion_200x200.jpeg and /dev/null differ diff --git a/static/panda.jpg b/static/panda.jpg deleted file mode 100644 index c5acc66..0000000 Binary files a/static/panda.jpg and /dev/null differ diff --git a/templates/chosing_link.html b/templates/chosing_link.html deleted file mode 100644 index 283f6cb..0000000 --- a/templates/chosing_link.html +++ /dev/null @@ -1,9 +0,0 @@ - diff --git a/templates/profile.html b/templates/profile.html index 945da71..4311618 100644 --- a/templates/profile.html +++ b/templates/profile.html @@ -9,7 +9,7 @@ {% set email = session['email'] %} {% set user_info_id = session['user_info_id'] %} {% set interests = session['interests'] or '' %} -{% set profile_image = url_for('static', filename = session['profile_image'] or '150x150.png') %} +{% set profile_image = session['profile_image'] %} {% if user_info_id is none: %} {% set action = '/profile/new' %} {% else %} @@ -62,10 +62,45 @@ fetch(`/profile/${userId}/get_image`) .then((res) => res.json()) .then((json) => { - const src = `/static/${json.data.profile_image[0]}` + const src = `/static/${json.data.profile_image}` $profileImage.src = src; }) } + const getSignedReqeust = (file) => { + const xhr = new XMLHttpRequest(); + xhr.open('GET', '/sign_s3?file_name=' + file.name + '&file_type=' + file.type) + xhr.onreadystatechange = function() { + if (xhr.status === 4) { + if (xhr.status === 200) { + const res = JSON.parse(xhr.responseText); + uploadImage(file, res.data, res.url) + } else { + alert('Could not get signed URL') + } + } + } + xhr.send() + } + const uploadFile = (file, s3Data, url) => { + const xhr = new XMLHttpRequest(); + xhr.open('POST', s3Data.url) + + const formData = new FormData(); + for(key in s3Data.fields) { + formData.append(key, s3Data.fields[key]) + } + formData.append('file', file) + + xhr.onreadystatechange = function() { + if (xhr.readyState === 4) { + if (xhr.status === 200 || xhr.status === 204) { + $profileImage.src = url + } + } else { + alert('Could not upload file') + } + } + } const uploadImage = (e) => { const file = e.target.files[0] const userId = e.target.dataset.userId @@ -81,9 +116,11 @@ }); } $profileImage.addEventListener('click', () => { - document.querySelector('input[type="file"]').click() - }) - document.querySelector('input[type="file"]').addEventListener('change', uploadImage) - })() + document.querySelector('input[type="file"]').click(); + }); + document.querySelector('input[type="file"]').addEventListener('change', (e) => { + getSignedReqeust(e.target.files[0]); + }); + })(); {% endblock %} \ No newline at end of file diff --git a/templates/sign_up.html b/templates/sign_up.html index 24b8dce..00aecda 100644 --- a/templates/sign_up.html +++ b/templates/sign_up.html @@ -18,7 +18,7 @@

{{ title }}

- +
diff --git a/templates/tweet.html b/templates/tweet.html index 5485c39..e15bb83 100644 --- a/templates/tweet.html +++ b/templates/tweet.html @@ -14,6 +14,7 @@
    + {% set login_user_id = session['user_id'] %} {% for t in session['tweets'] %} {% set id = t['id'] %} {% set tweet_user_id = t['user_id'] %} @@ -24,10 +25,10 @@ {% set user_name = t['user_name'] %} {% set age = t['age'] %} {% set interests = t['interests'] %} - {% set image = url_for('static', filename = t['profile_image'] or '150x150.png') %} + {% set image = t['profile_image'] %} {% set pushed_user_id = t['pushed_user_id'] %} {% set following = t['following'] %} - {% set is_current_user = session['user_id'] == tweet_user_id %} + {% set is_current_user = login_user_id == tweet_user_id %} {% if is_visible: %}
  • @@ -36,7 +37,7 @@ {% if not is_current_user %} {% if following %}
    - +
    {% else %}
    @@ -56,11 +57,11 @@
  • - {{ display_name or user_name }} + {{ display_name or user_name }} {% if not is_current_user %} {% if following %}
    - +
    {% else %}
    @@ -116,6 +117,8 @@ document.querySelectorAll(`button[data-follow-id='${followId}']`).forEach((el) => { el.classList.toggle('btn-primary') el.classList.toggle('btn-outline-primary') + if (el.innerHTML === 'Following') el.innerHTML = 'Add Follow' + else el.innerHTML = 'Following' }) } }); diff --git a/tweet.py b/tweet.py index 157c4e2..5e5ab4f 100644 --- a/tweet.py +++ b/tweet.py @@ -1,74 +1,84 @@ +import os +from flask import json +from follower import Followers +from tweet_like import TweetLikes +from user_info import UserInfos +from user import Users from db import Database -from operator import itemgetter -class Tweet: - def __init__(self): - db = Database() - self.db = db.db - self.cursor = db.cursor +db = Database.database - def get_tweets(self, data): - current_user_id = itemgetter('user_id')(data) - sql = 'SELECT * FROM tweets LEFT JOIN user_infos ON tweets.user_id = user_infos.user_id \ - LEFT JOIN tweet_likes ON tweets.id = tweet_likes.tweet_id ORDER BY tweets.id DESC' - self.cursor.execute(sql) - tweets = self.cursor.fetchall() +class Tweets(db.Model): + id = db.Column(db.Integer, primary_key = True) + user_id = db.Column(db.Integer, db.ForeignKey(Users.id), unique = True) + message = db.Column(db.String(140), nullable = True) + is_visible = db.Column(db.Boolean, nullable = True, default = True) + following = False - second_sql = 'SELECT * FROM followers WHERE user_id = %s' % current_user_id - self.cursor.execute(second_sql) - followers = self.cursor.fetchall() + user = db.relationship('Users', backref = 'users') + tweet_likes = db.relationship('TweetLikes', back_populates = 'tweet') + tweet_like = db.relationship('TweetLikes', uselist = False, back_populates = 'tweet') + + def __repr__(self): + return '' \ + % (self.id, self.user_id, self.message, self.is_visible) + + def __init__(self, data): + self.user_id = data['user_id'] + self.message = data['message'] + + @classmethod + def default_tweets(self, user_id): + tweets = Tweets.query \ + .join(UserInfos, UserInfos.user_id == Tweets.user_id) \ + .join(TweetLikes, isouter = True) \ + .order_by(db.desc(Tweets.id)) \ + .all() + followers = Followers.query.filter_by(user_id = user_id).all() result = [] for t in tweets: dic = {} - id, user_id, message, is_visible, user_info_id, _, display_name, user_name, age, interests, profile_image, _, pushed_user_id, _ = t for f in followers: - _, user_id_on_followers, follow_id = f - if current_user_id == user_id_on_followers and follow_id == user_id: + if user_id == f.user_id and f.follow_id == t.user_id: dic['following'] = True else: dic['following'] = False - dic['id'] = id - dic['user_id'] = user_id - dic['message'] = message - dic['is_visible'] = is_visible - dic['user_info_id'] = user_info_id - dic['display_name'] = display_name - dic['user_name'] = user_name - dic['age'] = age - dic['interests'] = interests - dic['profile_image'] = profile_image - dic['pushed_user_id'] = pushed_user_id + dic['id'] = t.id + dic['user_id'] = t.user_id + dic['message'] = t.message + dic['is_visible'] = t.is_visible + user_info = t.user.user_info + dic['user_info_id'] = user_info.id + dic['display_name'] = user_info.display_name + dic['user_name'] = user_info.user_name + dic['age'] = user_info.age + dic['interests'] = user_info.interests + dic['profile_image'] = 'https://%s.s3.amazonaws.com/%s' % (os.environ.get('S3_BUCKET'), user_info.profile_image) + dic['pushed_user_id'] = t.tweet_likes[0].user_id if t.tweet_likes else 0 result.append(dic) return result - - def add_tweet(self, data): - user_id, message = itemgetter('user_id', 'message')(data) - sql = 'INSERT INTO tweets (user_id, message) VALUES (%s, "%s")' % (user_id, message) - self.cursor.execute(sql) - self.db.commit() - - return True - - def invisible_tweet(self, id): - sql = 'SELECT COUNT(id) FROM tweets WHERE is_visible = 1 AND id = %s' % id - self.cursor.execute(sql) - total = self.cursor.fetchone() - if total[0] > 0: - next_sql = 'UPDATE tweets SET is_visible = 0 WHERE id = %s' % id - else: - next_sql = 'UPDATE tweets SET is_visible = 1 WHERE id = %s' % id - self.cursor.execute(next_sql) - self.db.commit() - - return True - - def delete_tweet(self, id): - sql = 'DELETE FROM tweets WHERE id = %s' % id - self.cursor.execute(sql) - self.db.commit() - - return True \ No newline at end of file + @classmethod + def search(self, id): + return Tweets.query.filter_by(id = id).first() + + def create(self): + db.session.add(self) + db.session.commit() + return self + + def delete(self): + db.session.delete(self) + db.session.commit() + return self + + def invisible(self): + self.is_visible = not self.is_visible + db.session.commit() + return self + + def to_json(self): + return json.dumps(self, default = lambda o: '', sort_keys = True, indent = 4) diff --git a/tweet_like.py b/tweet_like.py index bb817e5..b43f4fc 100644 --- a/tweet_like.py +++ b/tweet_like.py @@ -1,22 +1,51 @@ +from flask import json +from user import Users from db import Database -class TweetLike: - def __init__(self): - db = Database() - self.db = db.db - self.cursor = db.cursor +db = Database.database +class TweetLikes(db.Model): + id = db.Column(db.Integer, primary_key = True) + user_id = db.Column(db.Integer, db.ForeignKey(Users.id), nullable = True) + tweet_id = db.Column(db.Integer, db.ForeignKey('tweets.id'), nullable = True) - def favorite(self, id, pushed_user_id): - sql = 'SELECT COUNT(id) FROM tweet_likes WHERE user_id = %s AND tweet_id = %s' % (pushed_user_id, id) - self.cursor.execute(sql) - total = self.cursor.fetchone() - if (total[0] > 0): - next_sql = 'DELETE FROM tweet_likes WHERE user_id = %s AND tweet_id = %s' % (pushed_user_id, id) - else: - next_sql = 'INSERT INTO tweet_likes (user_id, tweet_id) VALUES (%s, %s)' % (pushed_user_id, id) + user = db.relationship('Users', backref = 'user') + tweet = db.relationship('Tweets', uselist = False, back_populates = 'tweet_likes') - self.cursor.execute(next_sql) - self.db.commit() + def __repr__(self): + return '' % (self.id, self.user_id, self.tweet_id) - return True \ No newline at end of file + def __init__(self, data): + self.user_id = data['user_id'] + self.tweet_id = data['tweet_id'] + + @classmethod + def search(self, data): + return TweetLikes.query.filter_by(user_id = data['user_id'], tweet_id = data['tweet_id']).first() + + def create(self): + db.session.add(self) + db.session.commit() + return self + + def delete(self): + db.session.delete(self) + db.session.commit() + return self + + def to_json(self): + return json.dumps(self, default = lambda o: '', sort_keys = True, indent = 4) + + # def favorite(self, id, pushed_user_id): + # sql = 'SELECT COUNT(id) FROM tweet_likes WHERE user_id = %s AND tweet_id = %s' % (pushed_user_id, id) + # self.cursor.execute(sql) + # total = self.cursor.fetchone() + # if (total[0] > 0): + # next_sql = 'DELETE FROM tweet_likes WHERE user_id = %s AND tweet_id = %s' % (pushed_user_id, id) + # else: + # next_sql = 'INSERT INTO tweet_likes (user_id, tweet_id) VALUES (%s, %s)' % (pushed_user_id, id) + + # self.cursor.execute(next_sql) + # self.db.commit() + + # return True \ No newline at end of file diff --git a/user.py b/user.py index fcf175f..5871145 100644 --- a/user.py +++ b/user.py @@ -1,13 +1,48 @@ from db import Database +import hashlib -class User: - def __init__(self): - db = Database() - self.db = db.db - self.cursor = db.cursor +db = Database.database + +class Users(db.Model): + id = db.Column(db.Integer, primary_key = True) + email = db.Column(db.String(256), unique = True, nullable = True) + password = db.Column(db.String(256), unique = True, nullable = True) + + user_info = db.relationship('UserInfos', uselist = False, back_populates = 'user') + + def __repr__(self): + return '' % (self.id, self.email, self.password) + + def __init__(self, data): + self.email = data['email'] + self.password = self.__to_sha256(data['password']) + + @classmethod + def search(self, data): + return Users.query.filter_by(email = data['email'], password = self.__to_sha256(self, data['password'])).limit(1).first() + + @classmethod + def search_and_user_infos(self, data): + return Users.query.filter_by(email = data['email'], password = self.__to_sha256(self, data['password'])).limit(1).first() + + def create(self): + db.session.add(self) + db.session.commit() + return self + + def update(self, data): + if 'email' in data and data['email'] != '': + self.email = data['email'] + if 'password' in data: + self.password = self.__to_sha256(data['password']) + db.session.commit() + return self def update_user(self, id, email): self.cursor.execute('UPDATE users SET email = "%s" WHERE id = %s' % (email, id)) self.db.commit() - - return True \ No newline at end of file + + return True + + def __to_sha256(self, password): + return hashlib.sha256(f'{password}'.encode()).hexdigest() \ No newline at end of file diff --git a/user_info.py b/user_info.py index 9eec858..0302d79 100644 --- a/user_info.py +++ b/user_info.py @@ -1,67 +1,71 @@ -from operator import itemgetter -from user import User +from user import Users from db import Database -class UserInfo: - def __init__(self): - db = Database() - self.db = db.db - self.cursor = db.cursor +db = Database.database - def get_user_info(self, user_id): - self.cursor.execute('SELECT * FROM users LEFT JOIN user_infos ON users.id = user_infos.user_id WHERE users.id = %s' % user_id) - (id, email, _, user_info_id, _, display_name, user_name, interests, profile_image, age) = self.cursor.fetchone() - return (id, email, user_info_id, display_name, user_name, interests, profile_image, age) +class UserInfos(db.Model): + id = db.Column(db.Integer, primary_key = True) + user_id = db.Column(db.Integer, db.ForeignKey(Users.id), unique = True) + display_name = db.Column(db.String(80)) + user_name = db.Column(db.String(80)) + age = db.Column(db.Integer, default = 0) + interests = db.Column(db.String(256)) + profile_image = db.Column(db.String(256), nullable = False, default = '150x150.png') - def get_profile_image(self, user_id): - sql = 'SELECT profile_image FROM user_infos WHERE user_id = %s' % user_id - self.cursor.execute(sql) - profile_image = self.cursor.fetchone() - return profile_image + user = db.relationship('Users', uselist = False, foreign_keys = 'UserInfos.user_id') - def insert_user_info(self, data): - user_id, display_name, user_name, age, interests = itemgetter('user_id', 'display_name', 'user_name', 'age', 'interests')(data) - sql = 'INSERT INTO user_infos (user_id, display_name, user_name, interests, age) VALUES (%s, "%s", "%s", "%s", %s);' \ - % (user_id, self.__xstr(display_name), self.__xstr(user_name), self.__xstr(interests), age) - self.cursor.execute(sql) - self.db.commit() - return True + def __repr__(self): + return '' \ + % (self.id, self.user_id, self.display_name, self.user_name, self.age, self.interests, self.profile_image) - def update_profile_image(self, user_id, filename): - sql = 'UPDATE user_infos SET profile_image = "%s" WHERE user_id = %s' % (filename, user_id) - self.cursor.execute(sql) - self.db.commit() - return True + def __init__(self, data): + self.user_id = data['user_id'] + if 'display_name' in data: + self.display_name = data['display_name'] + if 'user_name' in data: + self.user_name = data['user_name'] + if 'age' in data: + self.age = data['age'] + if 'interests' in data: + self.interests = data['interests'] + if 'profile_image' in data: + self.profile_image = data['profile_image'] - def update_user_info(self, data): - sqls = ['UPDATE user_infos SET '] - user_id, display_name, user_name, age, email, interests = itemgetter('id', 'display_name', 'user_name', 'age', 'email', 'interests')(data) - display_name = display_name or '' - user_name = user_name or '' - interests = interests or '' - # if display_name is not None: - sqls.append('display_name = "%s"' % self.__xstr(display_name)) - # if user_name is not None: - sqls.append('user_name = "%s"' % self.__xstr(user_name)) - sqls.append('age = %s' % age) - # if interests is not None: - sqls.append('interests = "%s"' % self.__xstr(interests)) + @classmethod + def initial_to_create(self, user_id): + u = UserInfos({ 'user_id': user_id }) + return u.create() - sql = '' - for x in range(len(sqls)): - if x == 0 or x == (len(sqls) - 1): - sql += sqls[x] + ' ' - else: - sql += sqls[x] + ', ' + @classmethod + def search(self, data): + return UserInfos.query.filter_by(user_id = data['user_id']).limit(1).first() - sql += 'WHERE user_id = %s' % user_id - self.cursor.execute(sql) - self.db.commit() - if email is not None and email != '': - u = User() - u.update_user(user_id, email) - - return True + def create(self): + db.session.add(self) + db.session.commit() + return self + + def update(self, data): + if 'display_name' in data: + self.display_name = data['display_name'] + if 'user_name' in data: + self.user_name = data['user_name'] + if 'age' in data: + self.age = data['age'] + if 'interests' in data: + self.interests = data['interests'] + + if 'email' in data: + self.user.update({ 'email': data['email'] }) + + db.session.commit() + return self - def __xstr(self, s): - return '' if s is None else str(s) \ No newline at end of file + def upload_image(self, filename): + self.profile_image = filename + + db.session.commit() + return self + + def get_image(self): + return self.profile_image \ No newline at end of file