List of commits:
Subject Hash Author Date (UTC)
initial2 d1ca5c33ec2ee0334c44182539d2d937711ff4ac Raluca Pacurar 2019-12-05 21:40:40
initial 9acfa21f1a216106d7971d60e90f697bf2182c00 Raluca Pacurar 2019-12-05 21:38:37
Commit d1ca5c33ec2ee0334c44182539d2d937711ff4ac - initial2
Author: Raluca Pacurar
Author date (UTC): 2019-12-05 21:40
Committer name: Raluca Pacurar
Committer date (UTC): 2019-12-05 21:40
Parent(s): 9acfa21f1a216106d7971d60e90f697bf2182c00
Signing key:
Tree: bc468ffa027d6cbaa7e9bcb56de23a759fbe5473
File Lines added Lines deleted
.flaskenv 3 0
.idea/TodoList_flask.iml 11 0
.idea/inspectionProfiles/profiles_settings.xml 6 0
.idea/misc.xml 7 0
.idea/modules.xml 8 0
.idea/workspace.xml 103 0
Readme 21 0
__pycache__/config.cpython-37.pyc 0 0
__pycache__/todolist.cpython-37.pyc 0 0
app.db 0 0
migrations/README 1 0
migrations/__pycache__/env.cpython-37.pyc 0 0
migrations/alembic.ini 45 0
migrations/env.py 87 0
migrations/script.py.mako 24 0
migrations/versions/00b0da5d3ec9_.py 50 0
migrations/versions/1987486c0538_.py 34 0
migrations/versions/__pycache__/00b0da5d3ec9_.cpython-37.pyc 0 0
migrations/versions/__pycache__/1987486c0538_.cpython-37.pyc 0 0
migrations/versions/__pycache__/d58397d23b87_.cpython-37.pyc 0 0
migrations/versions/d58397d23b87_.py 50 0
File .flaskenv added (mode: 100755) (index 0000000..a9787b3)
1 FLASK_APP=todolist.py
2 DATABASE_URL=postgresql://postgres:qazwsx@localhost/todolist
3 FLASK_ENV=development
File .idea/TodoList_flask.iml added (mode: 100755) (index 0000000..6711606)
1 <?xml version="1.0" encoding="UTF-8"?>
2 <module type="PYTHON_MODULE" version="4">
3 <component name="NewModuleRootManager">
4 <content url="file://$MODULE_DIR$" />
5 <orderEntry type="inheritedJdk" />
6 <orderEntry type="sourceFolder" forTests="false" />
7 </component>
8 <component name="TestRunnerService">
9 <option name="PROJECT_TEST_RUNNER" value="Unittests" />
10 </component>
11 </module>
File .idea/inspectionProfiles/profiles_settings.xml added (mode: 100755) (index 0000000..105ce2d)
1 <component name="InspectionProjectProfileManager">
2 <settings>
3 <option name="USE_PROJECT_PROFILE" value="false" />
4 <version value="1.0" />
5 </settings>
6 </component>
File .idea/misc.xml added (mode: 100755) (index 0000000..ba24381)
1 <?xml version="1.0" encoding="UTF-8"?>
2 <project version="4">
3 <component name="ProjectRootManager" version="2" project-jdk-name="Python 3.7" project-jdk-type="Python SDK" />
4 <component name="PyCharmProfessionalAdvertiser">
5 <option name="shown" value="true" />
6 </component>
7 </project>
File .idea/modules.xml added (mode: 100755) (index 0000000..03e9860)
1 <?xml version="1.0" encoding="UTF-8"?>
2 <project version="4">
3 <component name="ProjectModuleManager">
4 <modules>
5 <module fileurl="file://$PROJECT_DIR$/.idea/TodoList_flask.iml" filepath="$PROJECT_DIR$/.idea/TodoList_flask.iml" />
6 </modules>
7 </component>
8 </project>
File .idea/workspace.xml added (mode: 100755) (index 0000000..e6feed4)
1 <?xml version="1.0" encoding="UTF-8"?>
2 <project version="4">
3 <component name="ChangeListManager">
4 <list default="true" id="768bf4ae-35c8-4f55-b532-09088a37edd1" name="Default Changelist" comment="" />
5 <option name="EXCLUDED_CONVERTED_TO_IGNORED" value="true" />
6 <option name="SHOW_DIALOG" value="false" />
7 <option name="HIGHLIGHT_CONFLICTS" value="true" />
8 <option name="HIGHLIGHT_NON_ACTIVE_CHANGELIST" value="false" />
9 <option name="LAST_RESOLUTION" value="IGNORE" />
10 </component>
11 <component name="FileTemplateManagerImpl">
12 <option name="RECENT_TEMPLATES">
13 <list>
14 <option value="Python Script" />
15 <option value="HTML File" />
16 </list>
17 </option>
18 </component>
19 <component name="ProjectId" id="1Sz8iGPOTTKy0jAH5Cm31rcCsJ8" />
20 <component name="PropertiesComponent">
21 <property name="DefaultHtmlFileTemplate" value="HTML File" />
22 <property name="last_opened_file_path" value="$PROJECT_DIR$" />
23 </component>
24 <component name="RunDashboard">
25 <option name="ruleStates">
26 <list>
27 <RuleState>
28 <option name="name" value="ConfigurationTypeDashboardGroupingRule" />
29 </RuleState>
30 <RuleState>
31 <option name="name" value="StatusDashboardGroupingRule" />
32 </RuleState>
33 </list>
34 </option>
35 </component>
36 <component name="RunManager">
37 <configuration name="TodoList_flask" type="PythonConfigurationType" factoryName="Python" nameIsGenerated="true">
38 <module name="TodoList_flask" />
39 <option name="INTERPRETER_OPTIONS" value="" />
40 <option name="PARENT_ENVS" value="true" />
41 <envs>
42 <env name="PYTHONUNBUFFERED" value="1" />
43 </envs>
44 <option name="SDK_HOME" value="/usr/bin/python3.7" />
45 <option name="WORKING_DIRECTORY" value="$PROJECT_DIR$/.." />
46 <option name="IS_MODULE_SDK" value="false" />
47 <option name="ADD_CONTENT_ROOTS" value="true" />
48 <option name="ADD_SOURCE_ROOTS" value="true" />
49 <option name="SCRIPT_NAME" value="$PROJECT_DIR$" />
50 <option name="PARAMETERS" value="" />
51 <option name="SHOW_COMMAND_LINE" value="false" />
52 <option name="EMULATE_TERMINAL" value="true" />
53 <option name="MODULE_MODE" value="false" />
54 <option name="REDIRECT_INPUT" value="false" />
55 <option name="INPUT_FILE" value="" />
56 <method v="2" />
57 </configuration>
58 <configuration default="true" type="PythonConfigurationType" factoryName="Python">
59 <module name="TodoList_flask" />
60 <option name="INTERPRETER_OPTIONS" value="" />
61 <option name="PARENT_ENVS" value="true" />
62 <envs>
63 <env name="PYTHONUNBUFFERED" value="1" />
64 </envs>
65 <option name="SDK_HOME" value="/usr/bin/python3.7" />
66 <option name="WORKING_DIRECTORY" value="$PROJECT_DIR$/.." />
67 <option name="IS_MODULE_SDK" value="false" />
68 <option name="ADD_CONTENT_ROOTS" value="true" />
69 <option name="ADD_SOURCE_ROOTS" value="true" />
70 <option name="SCRIPT_NAME" value="$PROJECT_DIR$" />
71 <option name="PARAMETERS" value="" />
72 <option name="SHOW_COMMAND_LINE" value="false" />
73 <option name="EMULATE_TERMINAL" value="true" />
74 <option name="MODULE_MODE" value="false" />
75 <option name="REDIRECT_INPUT" value="false" />
76 <option name="INPUT_FILE" value="" />
77 <method v="2" />
78 </configuration>
79 </component>
80 <component name="SvnConfiguration">
81 <configuration />
82 </component>
83 <component name="TaskManager">
84 <task active="true" id="Default" summary="Default task">
85 <changelist id="768bf4ae-35c8-4f55-b532-09088a37edd1" name="Default Changelist" comment="" />
86 <created>1572555188390</created>
87 <option name="number" value="Default" />
88 <option name="presentableId" value="Default" />
89 <updated>1572555188390</updated>
90 </task>
91 <servers />
92 </component>
93 <component name="XDebuggerManager">
94 <breakpoint-manager>
95 <breakpoints>
96 <line-breakpoint enabled="true" suspend="THREAD" type="python-line">
97 <url>file://$PROJECT_DIR$/app/models.py</url>
98 <option name="timeStamp" value="1" />
99 </line-breakpoint>
100 </breakpoints>
101 </breakpoint-manager>
102 </component>
103 </project>
File Readme added (mode: 100644) (index 0000000..9fb048b)
1 Run app: in the root directory run command
2 flask run
3
4 Generate updated db structure
5 flask db migrate
6 flask db upgrade
7
8 Psql commands
9 - list all databases: \l
10 - select db: \c todolist
11 - list of tables: \dt
12 - display table details: \d todo
13
14 alter table todo alter column body type text;
15
16 Documentation
17 Jija 2: https://jinja.palletsprojects.com/en/2.10.x/templates/
18 falsk route parameters: https://exploreflask.com/en/latest/views.html
19 fetch api upload: https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch
20 service workers: https://developers.google.com/web/ilt/pwa/introduction-to-service-worker#registration_and_scope
21 https://stackoverflow.com/questions/35780397/understanding-service-worker-scope
File __pycache__/config.cpython-37.pyc added (mode: 100644) (index 0000000..7a79f78)
File __pycache__/todolist.cpython-37.pyc added (mode: 100755) (index 0000000..796a52b)
File app.db added (mode: 100755) (index 0000000..052a067)
File migrations/README added (mode: 100644) (index 0000000..98e4f9c)
1 Generic single-database configuration.
File migrations/__pycache__/env.cpython-37.pyc added (mode: 100644) (index 0000000..366e5bf)
File migrations/alembic.ini added (mode: 100644) (index 0000000..f8ed480)
1 # A generic, single database configuration.
2
3 [alembic]
4 # template used to generate migration files
5 # file_template = %%(rev)s_%%(slug)s
6
7 # set to 'true' to run the environment during
8 # the 'revision' command, regardless of autogenerate
9 # revision_environment = false
10
11
12 # Logging configuration
13 [loggers]
14 keys = root,sqlalchemy,alembic
15
16 [handlers]
17 keys = console
18
19 [formatters]
20 keys = generic
21
22 [logger_root]
23 level = WARN
24 handlers = console
25 qualname =
26
27 [logger_sqlalchemy]
28 level = WARN
29 handlers =
30 qualname = sqlalchemy.engine
31
32 [logger_alembic]
33 level = INFO
34 handlers =
35 qualname = alembic
36
37 [handler_console]
38 class = StreamHandler
39 args = (sys.stderr,)
40 level = NOTSET
41 formatter = generic
42
43 [formatter_generic]
44 format = %(levelname)-5.5s [%(name)s] %(message)s
45 datefmt = %H:%M:%S
File migrations/env.py added (mode: 100644) (index 0000000..23663ff)
1 from __future__ import with_statement
2 from alembic import context
3 from sqlalchemy import engine_from_config, pool
4 from logging.config import fileConfig
5 import logging
6
7 # this is the Alembic Config object, which provides
8 # access to the values within the .ini file in use.
9 config = context.config
10
11 # Interpret the config file for Python logging.
12 # This line sets up loggers basically.
13 fileConfig(config.config_file_name)
14 logger = logging.getLogger('alembic.env')
15
16 # add your model's MetaData object here
17 # for 'autogenerate' support
18 # from myapp import mymodel
19 # target_metadata = mymodel.Base.metadata
20 from flask import current_app
21 config.set_main_option('sqlalchemy.url',
22 current_app.config.get('SQLALCHEMY_DATABASE_URI'))
23 target_metadata = current_app.extensions['migrate'].db.metadata
24
25 # other values from the config, defined by the needs of env.py,
26 # can be acquired:
27 # my_important_option = config.get_main_option("my_important_option")
28 # ... etc.
29
30
31 def run_migrations_offline():
32 """Run migrations in 'offline' mode.
33
34 This configures the context with just a URL
35 and not an Engine, though an Engine is acceptable
36 here as well. By skipping the Engine creation
37 we don't even need a DBAPI to be available.
38
39 Calls to context.execute() here emit the given string to the
40 script output.
41
42 """
43 url = config.get_main_option("sqlalchemy.url")
44 context.configure(url=url)
45
46 with context.begin_transaction():
47 context.run_migrations()
48
49
50 def run_migrations_online():
51 """Run migrations in 'online' mode.
52
53 In this scenario we need to create an Engine
54 and associate a connection with the context.
55
56 """
57
58 # this callback is used to prevent an auto-migration from being generated
59 # when there are no changes to the schema
60 # reference: http://alembic.zzzcomputing.com/en/latest/cookbook.html
61 def process_revision_directives(context, revision, directives):
62 if getattr(config.cmd_opts, 'autogenerate', False):
63 script = directives[0]
64 if script.upgrade_ops.is_empty():
65 directives[:] = []
66 logger.info('No changes in schema detected.')
67
68 engine = engine_from_config(config.get_section(config.config_ini_section),
69 prefix='sqlalchemy.',
70 poolclass=pool.NullPool)
71
72 connection = engine.connect()
73 context.configure(connection=connection,
74 target_metadata=target_metadata,
75 process_revision_directives=process_revision_directives,
76 **current_app.extensions['migrate'].configure_args)
77
78 try:
79 with context.begin_transaction():
80 context.run_migrations()
81 finally:
82 connection.close()
83
84 if context.is_offline_mode():
85 run_migrations_offline()
86 else:
87 run_migrations_online()
File migrations/script.py.mako added (mode: 100644) (index 0000000..2c01563)
1 """${message}
2
3 Revision ID: ${up_revision}
4 Revises: ${down_revision | comma,n}
5 Create Date: ${create_date}
6
7 """
8 from alembic import op
9 import sqlalchemy as sa
10 ${imports if imports else ""}
11
12 # revision identifiers, used by Alembic.
13 revision = ${repr(up_revision)}
14 down_revision = ${repr(down_revision)}
15 branch_labels = ${repr(branch_labels)}
16 depends_on = ${repr(depends_on)}
17
18
19 def upgrade():
20 ${upgrades if upgrades else "pass"}
21
22
23 def downgrade():
24 ${downgrades if downgrades else "pass"}
File migrations/versions/00b0da5d3ec9_.py added (mode: 100644) (index 0000000..6f920da)
1 """empty message
2
3 Revision ID: 00b0da5d3ec9
4 Revises:
5 Create Date: 2019-11-03 10:53:30.104425
6
7 """
8 from alembic import op
9 import sqlalchemy as sa
10
11
12 # revision identifiers, used by Alembic.
13 revision = '00b0da5d3ec9'
14 down_revision = None
15 branch_labels = None
16 depends_on = None
17
18
19 def upgrade():
20 # ### commands auto generated by Alembic - please adjust! ###
21 op.create_table('user',
22 sa.Column('id', sa.Integer(), nullable=False),
23 sa.Column('username', sa.String(length=64), nullable=True),
24 sa.Column('email', sa.String(length=120), nullable=True),
25 sa.Column('password_hash', sa.String(length=128), nullable=True),
26 sa.PrimaryKeyConstraint('id')
27 )
28 op.create_index(op.f('ix_user_email'), 'user', ['email'], unique=True)
29 op.create_index(op.f('ix_user_username'), 'user', ['username'], unique=True)
30 op.create_table('todo',
31 sa.Column('id', sa.Integer(), nullable=False),
32 sa.Column('title', sa.String(length=1400), nullable=True),
33 sa.Column('body', sa.String(length=1400), nullable=True),
34 sa.Column('timestamp', sa.DateTime(), nullable=True),
35 sa.Column('user_id', sa.Integer(), nullable=True),
36 sa.ForeignKeyConstraint(['user_id'], ['user.id'], ),
37 sa.PrimaryKeyConstraint('id')
38 )
39 op.create_index(op.f('ix_todo_timestamp'), 'todo', ['timestamp'], unique=False)
40 # ### end Alembic commands ###
41
42
43 def downgrade():
44 # ### commands auto generated by Alembic - please adjust! ###
45 op.drop_index(op.f('ix_todo_timestamp'), table_name='todo')
46 op.drop_table('todo')
47 op.drop_index(op.f('ix_user_username'), table_name='user')
48 op.drop_index(op.f('ix_user_email'), table_name='user')
49 op.drop_table('user')
50 # ### end Alembic commands ###
File migrations/versions/1987486c0538_.py added (mode: 100644) (index 0000000..cc8da23)
1 """empty message
2
3 Revision ID: 1987486c0538
4 Revises: 00b0da5d3ec9
5 Create Date: 2019-11-03 11:36:21.733205
6
7 """
8 from alembic import op
9 import sqlalchemy as sa
10
11
12 # revision identifiers, used by Alembic.
13 revision = '1987486c0538'
14 down_revision = '00b0da5d3ec9'
15 branch_labels = None
16 depends_on = None
17
18
19 def upgrade():
20 # ### commands auto generated by Alembic - please adjust! ###
21 op.add_column('user', sa.Column('name', sa.String(length=64), nullable=True))
22 op.add_column('user', sa.Column('password', sa.String(length=128), nullable=True))
23 op.create_index(op.f('ix_user_name'), 'user', ['name'], unique=True)
24 op.drop_column('user', 'password_hash')
25 # ### end Alembic commands ###
26
27
28 def downgrade():
29 # ### commands auto generated by Alembic - please adjust! ###
30 op.add_column('user', sa.Column('password_hash', sa.VARCHAR(length=128), autoincrement=False, nullable=True))
31 op.drop_index(op.f('ix_user_name'), table_name='user')
32 op.drop_column('user', 'password')
33 op.drop_column('user', 'name')
34 # ### end Alembic commands ###
File migrations/versions/__pycache__/00b0da5d3ec9_.cpython-37.pyc added (mode: 100644) (index 0000000..1673b74)
File migrations/versions/__pycache__/1987486c0538_.cpython-37.pyc added (mode: 100644) (index 0000000..b8845ae)
File migrations/versions/__pycache__/d58397d23b87_.cpython-37.pyc added (mode: 100644) (index 0000000..447e734)
File migrations/versions/d58397d23b87_.py added (mode: 100644) (index 0000000..f14bb88)
1 """empty message
2
3 Revision ID: d58397d23b87
4 Revises: 1987486c0538
5 Create Date: 2019-11-04 00:47:42.064999
6
7 """
8 from alembic import op
9 import sqlalchemy as sa
10 from sqlalchemy.dialects import postgresql
11
12 # revision identifiers, used by Alembic.
13 revision = 'd58397d23b87'
14 down_revision = '1987486c0538'
15 branch_labels = None
16 depends_on = None
17
18
19 def upgrade():
20 # ### commands auto generated by Alembic - please adjust! ###
21 op.add_column('todo', sa.Column('completed_date', sa.DateTime(), nullable=True))
22 op.add_column('todo', sa.Column('created_date', sa.DateTime(), nullable=True))
23 op.add_column('todo', sa.Column('modified_date', sa.DateTime(), nullable=True))
24 op.add_column('todo', sa.Column('recurring', sa.Boolean(), nullable=True))
25 op.add_column('todo', sa.Column('scheduled_date', sa.DateTime(), nullable=True))
26 op.add_column('todo', sa.Column('status', sa.String(length=1400), nullable=True))
27 op.create_index(op.f('ix_todo_completed_date'), 'todo', ['completed_date'], unique=False)
28 op.create_index(op.f('ix_todo_created_date'), 'todo', ['created_date'], unique=False)
29 op.create_index(op.f('ix_todo_modified_date'), 'todo', ['modified_date'], unique=False)
30 op.create_index(op.f('ix_todo_scheduled_date'), 'todo', ['scheduled_date'], unique=False)
31 op.drop_index('ix_todo_timestamp', table_name='todo')
32 op.drop_column('todo', 'timestamp')
33 # ### end Alembic commands ###
34
35
36 def downgrade():
37 # ### commands auto generated by Alembic - please adjust! ###
38 op.add_column('todo', sa.Column('timestamp', postgresql.TIMESTAMP(), autoincrement=False, nullable=True))
39 op.create_index('ix_todo_timestamp', 'todo', ['timestamp'], unique=False)
40 op.drop_index(op.f('ix_todo_scheduled_date'), table_name='todo')
41 op.drop_index(op.f('ix_todo_modified_date'), table_name='todo')
42 op.drop_index(op.f('ix_todo_created_date'), table_name='todo')
43 op.drop_index(op.f('ix_todo_completed_date'), table_name='todo')
44 op.drop_column('todo', 'status')
45 op.drop_column('todo', 'scheduled_date')
46 op.drop_column('todo', 'recurring')
47 op.drop_column('todo', 'modified_date')
48 op.drop_column('todo', 'created_date')
49 op.drop_column('todo', 'completed_date')
50 # ### end Alembic commands ###
Hints:
Before first commit, do not forget to setup your git environment:
git config --global user.name "your_name_here"
git config --global user.email "your@email_here"

Clone this repository using HTTP(S):
git clone https://rocketgit.com/user/raluca.pacurar/TodoList_flask

Clone this repository using ssh (do not forget to upload a key first):
git clone ssh://rocketgit@ssh.rocketgit.com/user/raluca.pacurar/TodoList_flask

Clone this repository using git:
git clone git://git.rocketgit.com/user/raluca.pacurar/TodoList_flask

You are allowed to anonymously push to this repository.
This means that your pushed commits will automatically be transformed into a merge request:
... clone the repository ...
... make some changes and some commits ...
git push origin main