From eb9a593fd50f8fe194f1603e8a10fcca07c3495d Mon Sep 17 00:00:00 2001
From: Dmitry <b4tm4n@mail.ru>
Date: Sat, 4 Jul 2020 15:25:31 +0300
Subject: [PATCH] structure 1

---
 .idea/codeStyles/Project.xml              |   7 +
 .idea/codeStyles/codeStyleConfig.xml      |   5 +
 .idea/dictionaries/.xml                   |   7 +
 .idea/encodings.xml                       |   6 +
 .idea/helloworld_web.iml                  |   2 +-
 .idea/misc.xml                            |   2 +-
 app/__init__.py                           |  21 +++
 forms.py => app/forms.py                  |   0
 app/models.py                             |  85 +++++++++++
 {templates => app/templates}/admin.html   |   0
 {templates => app/templates}/contact.html |   0
 {templates => app/templates}/index.html   |   0
 {templates => app/templates}/login.html   |   0
 app/views.py                              |  62 ++++++++
 config.py                                 |  23 +++
 main.py                                   | 178 ----------------------
 models.py                                 |   0
 runner.py                                 |  31 ++++
 18 files changed, 249 insertions(+), 180 deletions(-)
 create mode 100644 .idea/codeStyles/Project.xml
 create mode 100644 .idea/codeStyles/codeStyleConfig.xml
 create mode 100644 .idea/dictionaries/.xml
 create mode 100644 .idea/encodings.xml
 create mode 100644 app/__init__.py
 rename forms.py => app/forms.py (100%)
 create mode 100644 app/models.py
 rename {templates => app/templates}/admin.html (100%)
 rename {templates => app/templates}/contact.html (100%)
 rename {templates => app/templates}/index.html (100%)
 rename {templates => app/templates}/login.html (100%)
 create mode 100644 app/views.py
 create mode 100644 config.py
 delete mode 100644 main.py
 delete mode 100644 models.py
 create mode 100644 runner.py

diff --git a/.idea/codeStyles/Project.xml b/.idea/codeStyles/Project.xml
new file mode 100644
index 0000000..8550006
--- /dev/null
+++ b/.idea/codeStyles/Project.xml
@@ -0,0 +1,7 @@
+<component name="ProjectCodeStyleConfiguration">
+  <code_scheme name="Project" version="173">
+    <option name="AUTODETECT_INDENTS" value="false" />
+    <option name="LINE_SEPARATOR" value="&#10;" />
+    <option name="SOFT_MARGINS" value="80" />
+  </code_scheme>
+</component>
\ No newline at end of file
diff --git a/.idea/codeStyles/codeStyleConfig.xml b/.idea/codeStyles/codeStyleConfig.xml
new file mode 100644
index 0000000..df5f35d
--- /dev/null
+++ b/.idea/codeStyles/codeStyleConfig.xml
@@ -0,0 +1,5 @@
+<component name="ProjectCodeStyleConfiguration">
+  <state>
+    <option name="PREFERRED_PROJECT_CODE_STYLE" value="Default" />
+  </state>
+</component>
\ No newline at end of file
diff --git a/.idea/dictionaries/.xml b/.idea/dictionaries/.xml
new file mode 100644
index 0000000..291ce5b
--- /dev/null
+++ b/.idea/dictionaries/.xml
@@ -0,0 +1,7 @@
+<component name="ProjectDictionaryState">
+  <dictionary name="Дмитрий">
+    <words>
+      <w>sqlalchemy</w>
+    </words>
+  </dictionary>
+</component>
\ No newline at end of file
diff --git a/.idea/encodings.xml b/.idea/encodings.xml
new file mode 100644
index 0000000..de8d7f4
--- /dev/null
+++ b/.idea/encodings.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+  <component name="Encoding" defaultCharsetForPropertiesFiles="UTF-8">
+    <file url="PROJECT" charset="UTF-8" />
+  </component>
+</project>
\ No newline at end of file
diff --git a/.idea/helloworld_web.iml b/.idea/helloworld_web.iml
index 858c4d5..ca5e422 100644
--- a/.idea/helloworld_web.iml
+++ b/.idea/helloworld_web.iml
@@ -4,7 +4,7 @@
     <content url="file://$MODULE_DIR$">
       <excludeFolder url="file://$MODULE_DIR$/venv" />
     </content>
-    <orderEntry type="inheritedJdk" />
+    <orderEntry type="jdk" jdkName="Python 3.8 (flask_helloworld1)" jdkType="Python SDK" />
     <orderEntry type="sourceFolder" forTests="false" />
   </component>
 </module>
\ No newline at end of file
diff --git a/.idea/misc.xml b/.idea/misc.xml
index be8870e..b228a21 100644
--- a/.idea/misc.xml
+++ b/.idea/misc.xml
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <project version="4">
-  <component name="ProjectRootManager" version="2" project-jdk-name="Python 3.8 (venv)" project-jdk-type="Python SDK" />
+  <component name="ProjectRootManager" version="2" project-jdk-name="Python 3.8 (flask_helloworld1)" project-jdk-type="Python SDK" />
   <component name="PyCharmProfessionalAdvertiser">
     <option name="shown" value="true" />
   </component>
diff --git a/app/__init__.py b/app/__init__.py
new file mode 100644
index 0000000..29ce935
--- /dev/null
+++ b/app/__init__.py
@@ -0,0 +1,21 @@
+from flask import Flask
+from flask_migrate import Migrate, MigrateCommand
+from flask_sqlalchemy import SQLAlchemy
+from flask_script import Manager, Command, Shell
+from flask_login import LoginManager
+import os, config
+
+# создание экземпляра приложения
+app = Flask(__name__)
+app.config.from_object(os.environ.get('FLASK_ENV') or 'config.DevelopementConfig')
+
+# инициализирует расширения
+db = SQLAlchemy(app)
+migrate = Migrate(app, db)
+login_manager = LoginManager(app)
+login_manager.login_view = 'login'
+
+# import views
+from . import views
+# from . import forum_views
+# from . import admin_views
diff --git a/forms.py b/app/forms.py
similarity index 100%
rename from forms.py
rename to app/forms.py
diff --git a/app/models.py b/app/models.py
new file mode 100644
index 0000000..12bd3ad
--- /dev/null
+++ b/app/models.py
@@ -0,0 +1,85 @@
+from app import db, login_manager
+from datetime import datetime
+from flask_login import (LoginManager, UserMixin, login_required,
+                         login_user, current_user, logout_user)
+from werkzeug.security import generate_password_hash, check_password_hash
+
+
+class Category(db.Model):
+    __tablename__ = 'categories'
+    id = db.Column(db.Integer(), primary_key=True)
+    name = db.Column(db.String(255), nullable=False)
+    slug = db.Column(db.String(255), nullable=False)
+    created_on = db.Column(db.DateTime(), default=datetime.utcnow)
+    posts = db.relationship('Post', backref='category')
+
+    def __repr__(self):
+        return "<{}:{}>".format(id, self.name)
+
+
+class Post(db.Model):
+    __tablename__ = 'posts'
+    id = db.Column(db.Integer(), primary_key=True)
+    title = db.Column(db.String(255), nullable=False)
+    slug = db.Column(db.String(255), nullable=False)
+    content = db.Column(db.Text(), nullable=False)
+    created_on = db.Column(db.DateTime(), default=datetime.utcnow)
+    updated_on = db.Column(db.DateTime(), default=datetime.utcnow, onupdate=datetime.utcnow)
+    category_id = db.Column(db.Integer(), db.ForeignKey('categories.id'))
+
+    def __repr__(self):
+        return "<{}:{}>".format(self.id, self.title[:10])
+
+
+post_tags = db.Table('post_tags',
+                     db.Column('post_id', db.Integer, db.ForeignKey('posts.id')),
+                     db.Column('tag_id', db.Integer, db.ForeignKey('tags.id'))
+                     )
+
+
+class Tag(db.Model):
+    __tablename__ = 'tags'
+    id = db.Column(db.Integer(), primary_key=True)
+    name = db.Column(db.String(255), nullable=False)
+    slug = db.Column(db.String(255), nullable=False)
+    created_on = db.Column(db.DateTime(), default=datetime.utcnow)
+    posts = db.relationship('Post', secondary=post_tags, backref='tags')
+
+    def __repr__(self):
+        return "<{}:{}>".format(id, self.name)
+
+
+class Feedback(db.Model):
+    __tablename__ = 'feedbacks'
+    id = db.Column(db.Integer(), primary_key=True)
+    name = db.Column(db.String(1000), nullable=False)
+    email = db.Column(db.String(100), nullable=False)
+    message = db.Column(db.Text(), nullable=False)
+    created_on = db.Column(db.DateTime(), default=datetime.utcnow)
+
+    def __repr__(self):
+        return "<{}:{}>".format(self.id, self.name)
+
+
+class User(db.Model, UserMixin):
+    __tablename__ = 'users'
+    id = db.Column(db.Integer(), primary_key=True)
+    name = db.Column(db.String(100))
+    username = db.Column(db.String(50), nullable=False, unique=True)
+    email = db.Column(db.String(100), nullable=False, unique=True)
+    password_hash = db.Column(db.String(100), nullable=False)
+    created_on = db.Column(db.DateTime(), default=datetime.utcnow)
+    updated_on = db.Column(db.DateTime(), default=datetime.utcnow, onupdate=datetime.utcnow)
+
+    def __repr__(self):
+        return "<{}:{}>".format(self.id, self.username)
+
+    def set_password(self, password):
+        self.password_hash = generate_password_hash(password)
+
+    def check_password(self, password):
+        return check_password_hash(self.password_hash, password)
+
+@login_manager.user_loader
+def load_user(user_id):
+    return db.session.query(User).get(user_id)
diff --git a/templates/admin.html b/app/templates/admin.html
similarity index 100%
rename from templates/admin.html
rename to app/templates/admin.html
diff --git a/templates/contact.html b/app/templates/contact.html
similarity index 100%
rename from templates/contact.html
rename to app/templates/contact.html
diff --git a/templates/index.html b/app/templates/index.html
similarity index 100%
rename from templates/index.html
rename to app/templates/index.html
diff --git a/templates/login.html b/app/templates/login.html
similarity index 100%
rename from templates/login.html
rename to app/templates/login.html
diff --git a/app/views.py b/app/views.py
new file mode 100644
index 0000000..42a88e5
--- /dev/null
+++ b/app/views.py
@@ -0,0 +1,62 @@
+from app import app
+from flask import render_template, request, redirect, url_for, flash
+from flask_login import login_required, login_user,current_user, logout_user
+from .models import User, Post, Category, Feedback, db
+from .forms import ContactForm, LoginForm
+
+
+@app.route('/admin/')
+@login_required
+def admin():
+    return render_template('admin.html')
+
+
+@app.route('/')
+def index():
+    return render_template('index.html')
+
+
+@app.route('/login/', methods=['post', 'get'])
+def login():
+    if current_user.is_authenticated:
+        return redirect(url_for('admin'))
+    form = LoginForm()
+    if form.validate_on_submit():
+        user = db.session.query(User).filter(User.username == form.username.data).first()
+        if user and user.check_password(form.password.data):
+            login_user(user, remember=form.remember.data)
+            nextpage = request.args.get('next', url_for('admin'))
+            return redirect(nextpage)
+        else:
+            flash("Invalid username/password", 'error')
+    return render_template('login.html', form=form)
+
+
+@app.route('/logout/')
+@login_required
+def logout():
+    logout_user()
+    flash("You have been logged out.")
+    return redirect(url_for('login'))
+
+
+@app.route('/contact/', methods=['get', 'post'])
+def contact():
+    form = ContactForm()
+    if form.validate_on_submit():
+        name = form.name.data
+        email = form.email.data
+        message = form.message.data
+        print(name)
+        print(email)
+        print(message)
+        # здесь логика базы данных
+        feedback = Feedback(name=name, email=email, message=message)
+        db.session.add(feedback)
+        db.session.commit()
+
+        print("\nData received. Now redirecting ...")
+        flash("Message Received", "success")
+        return redirect(url_for('contact'))
+
+    return render_template('contact.html', form=form)
diff --git a/config.py b/config.py
new file mode 100644
index 0000000..db1c4a8
--- /dev/null
+++ b/config.py
@@ -0,0 +1,23 @@
+import os
+
+app_dir = os.path.abspath(os.path.dirname(__file__))
+
+
+class BaseConfig:
+    SECRET_KEY = os.environ.get('SECRET_KEY') or '0d6e368e-bd0c-11ea-921d-9342d47f60ca'
+    SQLALCHEMY_TRACK_MODIFICATIONS = False
+
+
+class DevelopementConfig(BaseConfig):
+    DEBUG = True
+    SQLALCHEMY_DATABASE_URI = 'sqlite:///db.sqlite'
+
+
+class TestingConfig(BaseConfig):
+    DEBUG = True
+    SQLALCHEMY_DATABASE_URI = 'sqlite:///db.sqlite'
+
+
+class ProductionConfig(BaseConfig):
+    DEBUG = False
+    SQLALCHEMY_DATABASE_URI = 'sqlite:///db.sqlite'
diff --git a/main.py b/main.py
deleted file mode 100644
index 9b1b5c1..0000000
--- a/main.py
+++ /dev/null
@@ -1,178 +0,0 @@
-import flask
-from flask import Flask, request, current_app, url_for, render_template, flash, redirect
-from werkzeug.security import generate_password_hash,  check_password_hash
-from flask_script import Manager, Shell
-from flask_migrate import Migrate, MigrateCommand
-from flask_login import LoginManager, UserMixin, login_required, login_user, current_user, logout_user
-from jinja2 import Template
-from flask_sqlalchemy import SQLAlchemy
-from datetime import datetime
-
-from forms import ContactForm, LoginForm
-
-app = Flask(__name__)
-app.debug = True
-app.config['SECRET_KEY'] = '0d6e368e-bd0c-11ea-921d-9342d47f60ca'
-app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
-app.config['SQLALCHEMY_DATABASE_URI'] = "sqlite:///db.sqlite"
-db = SQLAlchemy(app)
-login_manager = LoginManager(app)
-login_manager.login_view = 'login'
-migrate = Migrate(app,  db)
-manager = Manager(app)
-manager.add_command('db', MigrateCommand)
-
-
-class Category(db.Model):
-    __tablename__ = 'categories'
-    id = db.Column(db.Integer(), primary_key=True)
-    name = db.Column(db.String(255), nullable=False)
-    slug = db.Column(db.String(255), nullable=False)
-    created_on = db.Column(db.DateTime(), default=datetime.utcnow)
-    posts = db.relationship('Post', backref='category')
-
-    def __repr__(self):
-        return "<{}:{}>".format(id, self.name)
-
-
-class Post(db.Model):
-    __tablename__ = 'posts'
-    id = db.Column(db.Integer(), primary_key=True)
-    title = db.Column(db.String(255), nullable=False)
-    slug = db.Column(db.String(255), nullable=False)
-    content = db.Column(db.Text(), nullable=False)
-    created_on = db.Column(db.DateTime(), default=datetime.utcnow)
-    updated_on = db.Column(db.DateTime(), default=datetime.utcnow, onupdate=datetime.utcnow)
-    category_id = db.Column(db.Integer(), db.ForeignKey('categories.id'))
-
-    def __repr__(self):
-        return "<{}:{}>".format(self.id, self.title[:10])
-
-
-post_tags = db.Table('post_tags',
-                     db.Column('post_id', db.Integer, db.ForeignKey('posts.id')),
-                     db.Column('tag_id', db.Integer, db.ForeignKey('tags.id'))
-                     )
-
-
-class Tag(db.Model):
-    __tablename__ = 'tags'
-    id = db.Column(db.Integer(), primary_key=True)
-    name = db.Column(db.String(255), nullable=False)
-    slug = db.Column(db.String(255), nullable=False)
-    created_on = db.Column(db.DateTime(), default=datetime.utcnow)
-    posts = db.relationship('Post', secondary=post_tags, backref='tags')
-
-    def __repr__(self):
-        return "<{}:{}>".format(id, self.name)
-
-
-class Feedback(db.Model):
-    __tablename__ = 'feedbacks'
-    id = db.Column(db.Integer(), primary_key=True)
-    name = db.Column(db.String(1000), nullable=False)
-    email = db.Column(db.String(100), nullable=False)
-    message = db.Column(db.Text(), nullable=False)
-    created_on = db.Column(db.DateTime(), default=datetime.utcnow)
-
-    def __repr__(self):
-        return "<{}:{}>".format(self.id, self.name)
-
-
-class User(db.Model, UserMixin):
-    __tablename__ = 'users'
-    id = db.Column(db.Integer(), primary_key=True)
-    name = db.Column(db.String(100))
-    username = db.Column(db.String(50), nullable=False, unique=True)
-    email = db.Column(db.String(100), nullable=False, unique=True)
-    password_hash = db.Column(db.String(100), nullable=False)
-    created_on = db.Column(db.DateTime(), default=datetime.utcnow)
-    updated_on = db.Column(db.DateTime(), default=datetime.utcnow,  onupdate=datetime.utcnow)
-
-    def __repr__(self):
-        return "<{}:{}>".format(self.id, self.username)
-
-    def set_password(self, password):
-        self.password_hash = generate_password_hash(password)
-
-    def check_password(self, password):
-        return check_password_hash(self.password_hash, password)
-
-
-@login_manager.user_loader
-def load_user(user_id):
-    return db.session.query(User).get(user_id)
-
-
-@app.route('/admin/')
-@login_required
-def admin():
-    return render_template('admin.html')
-
-
-@manager.command
-def faker():
-    print("Команда для добавления поддельных данных в таблицы")
-
-
-@app.route('/')
-def index():
-    return render_template('index.html')
-
-
-@app.route('/login/', methods=['post', 'get'])
-def login():
-    if current_user.is_authenticated:
-        return redirect(url_for('admin'))
-    form = LoginForm()
-    if form.validate_on_submit():
-        user = db.session.query(User).filter(User.username == form.username.data).first()
-        if user and user.check_password(form.password.data):
-            login_user(user, remember=form.remember.data)
-            nextpage = request.args.get('next', url_for('admin'))
-            return redirect(nextpage)
-        else:
-            flash("Invalid username/password", 'error')
-    return render_template('login.html', form=form)
-
-
-@app.route('/logout/')
-@login_required
-def logout():
-    logout_user()
-    flash("You have been logged out.")
-    return redirect(url_for('login'))
-
-@app.route('/contact/', methods=['get', 'post'])
-def contact():
-    form = ContactForm()
-    if form.validate_on_submit():
-        name = form.name.data
-        email = form.email.data
-        message = form.message.data
-        print(name)
-        print(email)
-        print(message)
-        # здесь логика базы данных
-        feedback = Feedback(name=name, email=email, message=message)
-        db.session.add(feedback)
-        db.session.commit()
-
-        print("\nData received. Now redirecting ...")
-        flash("Message Received", "success")
-        return redirect(url_for('contact'))
-
-    return render_template('contact.html', form=form)
-
-
-def shell_context():
-    import os, sys
-    return {'app': app, 'os': os, 'sys': sys, 'flask': flask, 'request': request, 'current_app': current_app,
-            'url_for': url_for, 'Template': Template, 'db': db}
-
-
-manager.add_command("shell", Shell(make_context=shell_context))
-
-if __name__ == "__main__":
-    db.init_app(app)
-    manager.run()
diff --git a/models.py b/models.py
deleted file mode 100644
index e69de29..0000000
diff --git a/runner.py b/runner.py
new file mode 100644
index 0000000..aae9f44
--- /dev/null
+++ b/runner.py
@@ -0,0 +1,31 @@
+import os
+
+import flask
+from flask import request, current_app, url_for
+from jinja2 import Template
+
+from app import app, db
+from app.models import User, Post, Tag, Category, Feedback
+from flask_script import Manager, Shell
+from flask_migrate import MigrateCommand
+
+manager = Manager(app)
+
+
+@manager.command
+def faker():
+    print("Команда для добавления поддельных данных в таблицы")
+
+
+def shell_context():
+    import sys
+    return {'app': app, 'os': os, 'sys': sys, 'flask': flask, 'request': request, 'current_app': current_app,
+            'url_for': url_for, 'Template': Template, 'db': db, 'User': User, 'Post': Post, 'Tag': Tag,
+            'Category': Category, 'Feedback': Feedback}
+
+
+manager.add_command("shell", Shell(make_context=shell_context))
+manager.add_command('db', MigrateCommand)
+
+if __name__ == '__main__':
+    manager.run()