libreqda 1.2.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- CHANGELOG.md +481 -0
- libreqda-1.2.0.dist-info/LICENSE.txt +28 -0
- libreqda-1.2.0.dist-info/METADATA +131 -0
- libreqda-1.2.0.dist-info/RECORD +255 -0
- libreqda-1.2.0.dist-info/WHEEL +4 -0
- libreqda-1.2.0.dist-info/entry_points.txt +4 -0
- scripts/babelrc +8 -0
- scripts/dist/LICENSE.txt +33 -0
- scripts/dist/RELEASE.txt +23 -0
- scripts/dist/macos/libreqda.icns +0 -0
- scripts/dist/macos/macos.spec +43 -0
- scripts/dist/macos/plist.patch +10 -0
- scripts/dist/macos/taguette.icns +0 -0
- scripts/dist/macos/taguette_console_wrapper +4 -0
- scripts/dist/macos.sh +32 -0
- scripts/dist/pyinstaller_entrypoint.py +19 -0
- scripts/dist/windows/windows-installer.iss +51 -0
- scripts/dist/windows/windows.spec +39 -0
- scripts/edugain/worker_update_edugain_idps.py +89 -0
- scripts/edugain/worker_update_edugain_idps.sh +9 -0
- scripts/make_password_reset_link.py +56 -0
- scripts/make_theme.py +99 -0
- scripts/new_db_revision.sh +8 -0
- scripts/register_user.py +76 -0
- scripts/update_pot.sh +33 -0
- scripts/update_translations.sh +17 -0
- scripts/validate.py +140 -0
- scripts/wipe_and_disable_user.py +90 -0
- taguette/__init__.py +13 -0
- taguette/access_control.py +145 -0
- taguette/convert.py +623 -0
- taguette/database/__init__.py +177 -0
- taguette/database/base.py +9 -0
- taguette/database/copy.py +433 -0
- taguette/database/models.py +920 -0
- taguette/demodata.py +688 -0
- taguette/export.py +500 -0
- taguette/extract.py +287 -0
- taguette/import_codebook.py +110 -0
- taguette/l10n/de_DE/LC_MESSAGES/taguette_javascript.mo +0 -0
- taguette/l10n/de_DE/LC_MESSAGES/taguette_main.mo +0 -0
- taguette/l10n/el_EL/LC_MESSAGES/taguette_javascript.mo +0 -0
- taguette/l10n/el_GR/LC_MESSAGES/taguette_javascript.mo +0 -0
- taguette/l10n/el_GR/LC_MESSAGES/taguette_main.mo +0 -0
- taguette/l10n/en_US/LC_MESSAGES/taguette_javascript.mo +0 -0
- taguette/l10n/en_US/LC_MESSAGES/taguette_main.mo +0 -0
- taguette/l10n/es_ES/LC_MESSAGES/taguette_javascript.mo +0 -0
- taguette/l10n/es_ES/LC_MESSAGES/taguette_main.mo +0 -0
- taguette/l10n/fr_FR/LC_MESSAGES/taguette_javascript.mo +0 -0
- taguette/l10n/fr_FR/LC_MESSAGES/taguette_main.mo +0 -0
- taguette/l10n/id_ID/LC_MESSAGES/taguette_javascript.mo +0 -0
- taguette/l10n/id_ID/LC_MESSAGES/taguette_main.mo +0 -0
- taguette/l10n/it_IT/LC_MESSAGES/taguette_javascript.mo +0 -0
- taguette/l10n/it_IT/LC_MESSAGES/taguette_main.mo +0 -0
- taguette/l10n/nl_NL/LC_MESSAGES/taguette_javascript.mo +0 -0
- taguette/l10n/nl_NL/LC_MESSAGES/taguette_main.mo +0 -0
- taguette/l10n/pt_PT/LC_MESSAGES/taguette_javascript.mo +0 -0
- taguette/l10n/pt_PT/LC_MESSAGES/taguette_main.mo +0 -0
- taguette/l10n/sv_SE/LC_MESSAGES/taguette_javascript.mo +0 -0
- taguette/l10n/sv_SE/LC_MESSAGES/taguette_main.mo +0 -0
- taguette/loki_handler.py +107 -0
- taguette/main.py +649 -0
- taguette/migrations/env.py +72 -0
- taguette/migrations/script.py.mako +24 -0
- taguette/migrations/versions/09c662cd9483_make_documents_filename_not_null.py +39 -0
- taguette/migrations/versions/1b29e68900c1_add_user_roles.py +55 -0
- taguette/migrations/versions/1b96a606551d_update_user_to_have_a_display_name.py +34 -0
- taguette/migrations/versions/2467bab602b7_add_color_column_to_tags_table.py +33 -0
- taguette/migrations/versions/382db36f20f4_add_user_disabled.py +66 -0
- taguette/migrations/versions/43d6c240309d_remove_document_groups.py +81 -0
- taguette/migrations/versions/447d636f72c5_cascades.py +40 -0
- taguette/migrations/versions/491de2dc7cd7_add_indexes.py +51 -0
- taguette/migrations/versions/4c55b3b3ff30_user_login_length.py +58 -0
- taguette/migrations/versions/61a4abcc8769_user_with_parent_for_permissions.py +40 -0
- taguette/migrations/versions/6489b5f9cfb5_increase_password_hash_size.py +34 -0
- taguette/migrations/versions/679f625e6e6a_fix_unique_tags.py +59 -0
- taguette/migrations/versions/77c4543a5b9b_add_parent_id_column_to_collection_table.py +41 -0
- taguette/migrations/versions/7c94b7a31e69_add_is_archived_column_to_projets.py +39 -0
- taguette/migrations/versions/7f56de97e3c8_change_edugain_displayname_length.py +42 -0
- taguette/migrations/versions/807c0cc0ecf6_remove_invalid_hltags.py +43 -0
- taguette/migrations/versions/80b1cc9d4c22_add_user_email.py +35 -0
- taguette/migrations/versions/91ade71ccf4d_add_user_language.py +28 -0
- taguette/migrations/versions/955db2e523d1_add_collections_tables_and_associations_.py +60 -0
- taguette/migrations/versions/a1b2c3d4e5f6_add_user_hide_code_counts.py +28 -0
- taguette/migrations/versions/b23f3b7a638e_add_user_password_change_date.py +36 -0
- taguette/migrations/versions/b7c1e2d3f4a5_add_project_compact_layout.py +28 -0
- taguette/migrations/versions/bc8e0e0677e9_rename_command_fields.py +126 -0
- taguette/migrations/versions/bce44849c2f2_lowercase_logins.py +96 -0
- taguette/migrations/versions/ca076140922f_update_user_for_external_logins.py +32 -0
- taguette/migrations/versions/d86c45d7aa8a_add_document_direction.py +127 -0
- taguette/migrations/versions/db5e31a0233d_remove_blank_highlights.py +88 -0
- taguette/migrations/versions/dd37d9027a24_unique_tags.py +68 -0
- taguette/migrations/versions/de678cef2a94_add_project_id_to_collections_and_.py +41 -0
- taguette/migrations/versions/e459991d960e_add_table_edugainidps.py +39 -0
- taguette/migrations/versions/e4cf92942271_add_index.py +29 -0
- taguette/migrations/versions/e4e090a5b511_remove_commands_document_id_fk.py +38 -0
- taguette/migrations/versions/e9a9f1c77971_add_favorite_column_to_document.py +32 -0
- taguette/migrations/versions/ecb4065de575_don_t_use_server_default_now_timezone_.py +44 -0
- taguette/migrations/versions/fbdc29566f62_edugain_fix_field_type.py +42 -0
- taguette/migrations/versions/fdc6eb54b034_add_parent_id_column_to_tags_table.py +31 -0
- taguette/static/README.md +34 -0
- taguette/static/alt_templates/.gitkeep +0 -0
- taguette/static/assets/test/logos/monsters-university-logo.png +0 -0
- taguette/static/css/custom.css +1696 -0
- taguette/static/css/fa-all.min.css +5 -0
- taguette/static/css/themed.css +3 -0
- taguette/static/css/themed.css.map +25 -0
- taguette/static/css/vendor/bootstrap-treeview.min.css +1 -0
- taguette/static/css/vendor/bootstrap.min.css +6 -0
- taguette/static/css/vendor/font/context-menu-icons.eot +0 -0
- taguette/static/css/vendor/font/context-menu-icons.ttf +0 -0
- taguette/static/css/vendor/font/context-menu-icons.woff +0 -0
- taguette/static/css/vendor/font/context-menu-icons.woff2 +0 -0
- taguette/static/css/vendor/hierarchy-select.min.css +1 -0
- taguette/static/css/vendor/introjs.min.css +2 -0
- taguette/static/css/vendor/jquery.contextMenu.min.css +16 -0
- taguette/static/favicon.ico +0 -0
- taguette/static/js/codebook-viz.js +428 -0
- taguette/static/js/collection/context-menu.js +180 -0
- taguette/static/js/collection/hierarchy-select.js +71 -0
- taguette/static/js/collection/manager.js +217 -0
- taguette/static/js/document/context-menu.js +92 -0
- taguette/static/js/document/custom-select.js +82 -0
- taguette/static/js/document/manager.js +943 -0
- taguette/static/js/document/treeview.js +593 -0
- taguette/static/js/highlight/README.md +18 -0
- taguette/static/js/highlight/crud.js +119 -0
- taguette/static/js/highlight/extracts.js +497 -0
- taguette/static/js/highlight/loader.js +109 -0
- taguette/static/js/highlight/renderer.js +405 -0
- taguette/static/js/login.js +15 -0
- taguette/static/js/permissions.js +153 -0
- taguette/static/js/polling-event.js +145 -0
- taguette/static/js/project/intro.js +524 -0
- taguette/static/js/project/manager.js +0 -0
- taguette/static/js/project/search.js +124 -0
- taguette/static/js/tag/context-menu.js +133 -0
- taguette/static/js/tag/explore-codes.js +400 -0
- taguette/static/js/tag/hierarchy-select.js +69 -0
- taguette/static/js/tag/manager.js +545 -0
- taguette/static/js/tag/treeview.js +613 -0
- taguette/static/js/taguette.js +1790 -0
- taguette/static/js/utilities.js +714 -0
- taguette/static/js/vendor/bootstrap-treeview-custum.js +421 -0
- taguette/static/js/vendor/bootstrap-treeview-custum.min.js +1 -0
- taguette/static/js/vendor/bootstrap-treeview-default.min.js +1 -0
- taguette/static/js/vendor/bootstrap.bundle.min.js +7 -0
- taguette/static/js/vendor/bootstrap.bundle.min.js.map +1 -0
- taguette/static/js/vendor/hierarchy-select.min.js +1 -0
- taguette/static/js/vendor/introjs.min.js +17 -0
- taguette/static/js/vendor/jquery-3.7.1.js +2 -0
- taguette/static/js/vendor/jquery.contextMenu.min.js +2 -0
- taguette/static/libreqda.ico +0 -0
- taguette/static/logo-h.png +0 -0
- taguette/static/logo.png +0 -0
- taguette/static/logo_blanc.png +0 -0
- taguette/static/missing.png +0 -0
- taguette/static/robots.txt +2 -0
- taguette/static/scss/components/_badge.scss +42 -0
- taguette/static/scss/components/_button.scss +169 -0
- taguette/static/scss/components/_checkbox.scss +40 -0
- taguette/static/scss/components/_context_menu.scss +28 -0
- taguette/static/scss/components/_custom_select.scss +150 -0
- taguette/static/scss/components/_dropdown.scss +43 -0
- taguette/static/scss/components/_form.scss +54 -0
- taguette/static/scss/components/_modal.scss +57 -0
- taguette/static/scss/components/_project_card.scss +163 -0
- taguette/static/scss/components/_tag.scss +308 -0
- taguette/static/scss/components/_treeview.scss +76 -0
- taguette/static/scss/custom.scss +809 -0
- taguette/static/scss/layout/_credits.scss +62 -0
- taguette/static/scss/layout/_footer.scss +6 -0
- taguette/static/scss/layout/_navigation.scss +165 -0
- taguette/static/scss/layout/_sidebar.scss +37 -0
- taguette/static/scss/themes/default/_variables.scss +103 -0
- taguette/static/scss/themes/default/theme.css +3 -0
- taguette/static/scss/themes/default/theme.css.map +26 -0
- taguette/static/scss/themes/default/theme.scss +4 -0
- taguette/static/webfonts/BadScript-OFL.txt +94 -0
- taguette/static/webfonts/BadScript.ttf +0 -0
- taguette/static/webfonts/Montserrat-Light.ttf +0 -0
- taguette/static/webfonts/Montserrat-OFL.txt +93 -0
- taguette/static/webfonts/fa-brands-400.eot +0 -0
- taguette/static/webfonts/fa-brands-400.svg +1184 -0
- taguette/static/webfonts/fa-brands-400.ttf +0 -0
- taguette/static/webfonts/fa-brands-400.woff +0 -0
- taguette/static/webfonts/fa-brands-400.woff2 +0 -0
- taguette/static/webfonts/fa-regular-400.eot +0 -0
- taguette/static/webfonts/fa-regular-400.svg +467 -0
- taguette/static/webfonts/fa-regular-400.ttf +0 -0
- taguette/static/webfonts/fa-regular-400.woff +0 -0
- taguette/static/webfonts/fa-regular-400.woff2 +0 -0
- taguette/static/webfonts/fa-solid-900.eot +0 -0
- taguette/static/webfonts/fa-solid-900.svg +2618 -0
- taguette/static/webfonts/fa-solid-900.ttf +0 -0
- taguette/static/webfonts/fa-solid-900.woff +0 -0
- taguette/static/webfonts/fa-solid-900.woff2 +0 -0
- taguette/templates/alt_templates/.gitkeep +0 -0
- taguette/templates/archived_projects.html +50 -0
- taguette/templates/auth/account.html +74 -0
- taguette/templates/auth/cilogon.login.html +89 -0
- taguette/templates/auth/email_reset_password.html +5 -0
- taguette/templates/auth/external_account.html +60 -0
- taguette/templates/auth/login.html +144 -0
- taguette/templates/auth/reset_password.html +27 -0
- taguette/templates/auth/token_needed.html +7 -0
- taguette/templates/base.html +209 -0
- taguette/templates/bug_report.html +158 -0
- taguette/templates/cookies_prompt.html +15 -0
- taguette/templates/downloads.html +127 -0
- taguette/templates/email_bug_report.txt +9 -0
- taguette/templates/email_reset_password.txt +5 -0
- taguette/templates/error.html +8 -0
- taguette/templates/export_codebook.html +20 -0
- taguette/templates/export_document.html +20 -0
- taguette/templates/export_highlights.html +47 -0
- taguette/templates/index.html +347 -0
- taguette/templates/maintenance.html +8 -0
- taguette/templates/messages.js +74 -0
- taguette/templates/modal/change_document.html +68 -0
- taguette/templates/modal/create_collection.html +100 -0
- taguette/templates/modal/create_document.html +84 -0
- taguette/templates/modal/create_highlight.html +38 -0
- taguette/templates/modal/create_tag.html +73 -0
- taguette/templates/modal/explore_codes.html +58 -0
- taguette/templates/modal/manage_collaborators.html +44 -0
- taguette/templates/modal/merge_tag.html +49 -0
- taguette/templates/new_password.html +32 -0
- taguette/templates/partials/alert.html +16 -0
- taguette/templates/partials/codebook_viz_modal.html +34 -0
- taguette/templates/partials/confirm.html +17 -0
- taguette/templates/partials/document_toolbar.html +37 -0
- taguette/templates/partials/hlinfo.html +13 -0
- taguette/templates/partials/project_card.html +44 -0
- taguette/templates/partials/project_card_archived.html +41 -0
- taguette/templates/partials/project_sidebar.html +99 -0
- taguette/templates/partials/spinner.html +11 -0
- taguette/templates/permissions.html +54 -0
- taguette/templates/project.html +288 -0
- taguette/templates/project_delete.html +17 -0
- taguette/templates/project_import.html +122 -0
- taguette/templates/project_import_codebook.html +34 -0
- taguette/templates/project_import_codebook_confirm.html +49 -0
- taguette/templates/project_new.html +31 -0
- taguette/templates/tos.html +8 -0
- taguette/templates/trans.js +7 -0
- taguette/templates/welcome.html +15 -0
- taguette/utils.py +177 -0
- taguette/validate.py +141 -0
- taguette/version_check.py +102 -0
- taguette/web/__init__.py +252 -0
- taguette/web/api.py +1835 -0
- taguette/web/base.py +864 -0
- taguette/web/export.py +338 -0
- taguette/web/views.py +1618 -0
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
from __future__ import with_statement
|
|
2
|
+
from alembic import context
|
|
3
|
+
import logging
|
|
4
|
+
from sqlalchemy import create_engine
|
|
5
|
+
import taguette.database
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
# this is the Alembic Config object, which provides
|
|
9
|
+
# access to the values within the .ini file in use.
|
|
10
|
+
config = context.config
|
|
11
|
+
|
|
12
|
+
# Interpret the config file for Python logging.
|
|
13
|
+
# This line sets up loggers basically.
|
|
14
|
+
logging.basicConfig(level=logging.INFO)
|
|
15
|
+
|
|
16
|
+
# add your model's MetaData object here
|
|
17
|
+
# for 'autogenerate' support
|
|
18
|
+
target_metadata = taguette.database.Base.metadata
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
xargs = context.get_x_argument(as_dictionary=True)
|
|
22
|
+
if 'db' in xargs:
|
|
23
|
+
config.set_main_option('sqlalchemy.url', xargs['db'])
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def run_migrations_offline():
|
|
27
|
+
"""Run migrations in 'offline' mode.
|
|
28
|
+
|
|
29
|
+
This configures the context with just a URL
|
|
30
|
+
and not an Engine, though an Engine is acceptable
|
|
31
|
+
here as well. By skipping the Engine creation
|
|
32
|
+
we don't even need a DBAPI to be available.
|
|
33
|
+
|
|
34
|
+
Calls to context.execute() here emit the given string to the
|
|
35
|
+
script output.
|
|
36
|
+
|
|
37
|
+
"""
|
|
38
|
+
url = config.get_main_option('sqlalchemy.url')
|
|
39
|
+
context.configure(
|
|
40
|
+
url=url, target_metadata=target_metadata, literal_binds=True,
|
|
41
|
+
render_as_batch=True,
|
|
42
|
+
)
|
|
43
|
+
|
|
44
|
+
with context.begin_transaction():
|
|
45
|
+
context.run_migrations()
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
def run_migrations_online():
|
|
49
|
+
"""Run migrations in 'online' mode.
|
|
50
|
+
|
|
51
|
+
In this scenario we need to create an Engine
|
|
52
|
+
and associate a connection with the context.
|
|
53
|
+
|
|
54
|
+
"""
|
|
55
|
+
url = config.get_main_option('sqlalchemy.url')
|
|
56
|
+
connectable = create_engine(url)
|
|
57
|
+
|
|
58
|
+
with connectable.connect() as connection:
|
|
59
|
+
context.configure(
|
|
60
|
+
connection=connection,
|
|
61
|
+
target_metadata=target_metadata,
|
|
62
|
+
render_as_batch=True,
|
|
63
|
+
)
|
|
64
|
+
|
|
65
|
+
with context.begin_transaction():
|
|
66
|
+
context.run_migrations()
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
if context.is_offline_mode():
|
|
70
|
+
run_migrations_offline()
|
|
71
|
+
else:
|
|
72
|
+
run_migrations_online()
|
|
@@ -0,0 +1,24 @@
|
|
|
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"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
"""make documents.filename NOT NULL
|
|
2
|
+
|
|
3
|
+
Revision ID: 09c662cd9483
|
|
4
|
+
Revises: e4cf92942271
|
|
5
|
+
Create Date: 2022-01-21 17:42:53.265226
|
|
6
|
+
|
|
7
|
+
"""
|
|
8
|
+
from alembic import op
|
|
9
|
+
import sqlalchemy as sa
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
# revision identifiers, used by Alembic.
|
|
13
|
+
revision = '09c662cd9483'
|
|
14
|
+
down_revision = 'e4cf92942271'
|
|
15
|
+
branch_labels = None
|
|
16
|
+
depends_on = None
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def upgrade():
|
|
20
|
+
op.execute(
|
|
21
|
+
'''\
|
|
22
|
+
UPDATE documents SET filename = 'unknown' WHERE filename IS NULL;
|
|
23
|
+
''',
|
|
24
|
+
)
|
|
25
|
+
with op.batch_alter_table('documents') as batch_op:
|
|
26
|
+
batch_op.alter_column(
|
|
27
|
+
'filename',
|
|
28
|
+
existing_type=sa.VARCHAR(length=200),
|
|
29
|
+
nullable=False,
|
|
30
|
+
)
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
def downgrade():
|
|
34
|
+
with op.batch_alter_table('documents') as batch_op:
|
|
35
|
+
batch_op.alter_column(
|
|
36
|
+
'filename',
|
|
37
|
+
existing_type=sa.VARCHAR(length=200),
|
|
38
|
+
nullable=True,
|
|
39
|
+
)
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
"""add user roles
|
|
2
|
+
|
|
3
|
+
Revision ID: 1b29e68900c1
|
|
4
|
+
Revises: e9a9f1c77971
|
|
5
|
+
Create Date: 2025-03-10 08:14:24.098419
|
|
6
|
+
|
|
7
|
+
"""
|
|
8
|
+
from alembic import op
|
|
9
|
+
import sqlalchemy as sa
|
|
10
|
+
from sqlalchemy.dialects import postgresql
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
# revision identifiers, used by Alembic.
|
|
14
|
+
revision = '1b29e68900c1'
|
|
15
|
+
down_revision = 'e9a9f1c77971'
|
|
16
|
+
branch_labels = None
|
|
17
|
+
depends_on = None
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def upgrade():
|
|
21
|
+
connection = op.get_bind()
|
|
22
|
+
if connection.dialect.name == 'postgresql':
|
|
23
|
+
roles_enum = postgresql.ENUM(
|
|
24
|
+
'ADMIN', 'PROJECT_ADMIN', 'TEAM_MEMBER', 'PROJECT_OWNER',
|
|
25
|
+
name='roles',
|
|
26
|
+
create_type=False,
|
|
27
|
+
)
|
|
28
|
+
roles_enum.create(connection)
|
|
29
|
+
else:
|
|
30
|
+
roles_enum = sa.Enum(
|
|
31
|
+
'ADMIN', 'PROJECT_ADMIN', 'TEAM_MEMBER',
|
|
32
|
+
name='roles',
|
|
33
|
+
)
|
|
34
|
+
|
|
35
|
+
op.add_column(
|
|
36
|
+
'users',
|
|
37
|
+
sa.Column('role', roles_enum, nullable=True)
|
|
38
|
+
)
|
|
39
|
+
op.execute(
|
|
40
|
+
'''\
|
|
41
|
+
UPDATE users SET role = 'PROJECT_ADMIN';
|
|
42
|
+
''',
|
|
43
|
+
)
|
|
44
|
+
|
|
45
|
+
with op.batch_alter_table('users', schema=None) as batch_op:
|
|
46
|
+
batch_op.alter_column('role', nullable=False)
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
def downgrade():
|
|
50
|
+
with op.batch_alter_table('users', schema=None) as batch_op:
|
|
51
|
+
batch_op.drop_column('roles')
|
|
52
|
+
|
|
53
|
+
connection = op.get_bind()
|
|
54
|
+
if connection.dialect.name == 'postgresql':
|
|
55
|
+
op.execute("DROP TYPE roles;")
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
"""update user to have a display name
|
|
2
|
+
|
|
3
|
+
Revision ID: 1b96a606551d
|
|
4
|
+
Revises: ca076140922f
|
|
5
|
+
Create Date: 2024-03-08 10:11:58.436815
|
|
6
|
+
|
|
7
|
+
"""
|
|
8
|
+
from alembic import op
|
|
9
|
+
import sqlalchemy as sa
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
# revision identifiers, used by Alembic.
|
|
13
|
+
revision = '1b96a606551d'
|
|
14
|
+
down_revision = 'ca076140922f'
|
|
15
|
+
branch_labels = None
|
|
16
|
+
depends_on = None
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def upgrade():
|
|
20
|
+
# ### commands auto generated by Alembic - please adjust! ###
|
|
21
|
+
with op.batch_alter_table('users', schema=None) as batch_op:
|
|
22
|
+
batch_op.add_column(
|
|
23
|
+
sa.Column('displayname', sa.String(length=255),
|
|
24
|
+
nullable=True))
|
|
25
|
+
|
|
26
|
+
# ### end Alembic commands ###
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def downgrade():
|
|
30
|
+
# ### commands auto generated by Alembic - please adjust! ###
|
|
31
|
+
with op.batch_alter_table('users', schema=None) as batch_op:
|
|
32
|
+
batch_op.drop_column('displayname')
|
|
33
|
+
|
|
34
|
+
# ### end Alembic commands ###
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
"""Add color column to tags table
|
|
2
|
+
|
|
3
|
+
Revision ID: 2467bab602b7
|
|
4
|
+
Revises: fdc6eb54b034
|
|
5
|
+
Create Date: 2024-02-08 23:07:22.459389
|
|
6
|
+
|
|
7
|
+
"""
|
|
8
|
+
from alembic import op
|
|
9
|
+
import sqlalchemy as sa
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
# revision identifiers, used by Alembic.
|
|
13
|
+
revision = '2467bab602b7'
|
|
14
|
+
down_revision = 'fdc6eb54b034'
|
|
15
|
+
branch_labels = None
|
|
16
|
+
depends_on = None
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def upgrade():
|
|
20
|
+
# ### commands auto generated by Alembic - please adjust! ###
|
|
21
|
+
with op.batch_alter_table('tags', schema=None) as batch_op:
|
|
22
|
+
batch_op.add_column(sa.Column('color', sa.String(length=20),
|
|
23
|
+
nullable=False, server_default=''))
|
|
24
|
+
|
|
25
|
+
# ### end Alembic commands ###
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def downgrade():
|
|
29
|
+
# ### commands auto generated by Alembic - please adjust! ###
|
|
30
|
+
with op.batch_alter_table('tags', schema=None) as batch_op:
|
|
31
|
+
batch_op.drop_column('color')
|
|
32
|
+
|
|
33
|
+
# ### end Alembic commands ###
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
"""add user disabled
|
|
2
|
+
|
|
3
|
+
Revision ID: 382db36f20f4
|
|
4
|
+
Revises: 09c662cd9483
|
|
5
|
+
Create Date: 2022-05-14 23:33:03.709256
|
|
6
|
+
|
|
7
|
+
"""
|
|
8
|
+
from alembic import op
|
|
9
|
+
from datetime import datetime
|
|
10
|
+
import sqlalchemy as sa
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
# revision identifiers, used by Alembic.
|
|
14
|
+
revision = '382db36f20f4'
|
|
15
|
+
down_revision = '6489b5f9cfb5'
|
|
16
|
+
branch_labels = None
|
|
17
|
+
depends_on = None
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
meta = sa.MetaData(naming_convention={
|
|
21
|
+
"ix": "ix_%(column_0_label)s",
|
|
22
|
+
"uq": "uq_%(table_name)s_%(column_0_name)s",
|
|
23
|
+
"ck": "ck_%(table_name)s_%(constraint_name)s",
|
|
24
|
+
"fk": "fk_%(table_name)s_%(column_0_name)s_%(referred_table_name)s",
|
|
25
|
+
"pk": "pk_%(table_name)s",
|
|
26
|
+
})
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def upgrade():
|
|
30
|
+
# Add column as NULL
|
|
31
|
+
with op.batch_alter_table('users', schema=None) as batch_op:
|
|
32
|
+
batch_op.add_column(sa.Column('disabled', sa.Boolean(), nullable=True))
|
|
33
|
+
|
|
34
|
+
users = sa.Table(
|
|
35
|
+
'users',
|
|
36
|
+
meta,
|
|
37
|
+
sa.Column('login', sa.String(30), primary_key=True),
|
|
38
|
+
sa.Column('created', sa.DateTime, nullable=False,
|
|
39
|
+
default=lambda: datetime.utcnow()),
|
|
40
|
+
sa.Column('hashed_password', sa.String(120), nullable=True),
|
|
41
|
+
sa.Column('disabled', sa.Boolean, nullable=False, default=False),
|
|
42
|
+
sa.Column('password_set_date', sa.DateTime, nullable=True),
|
|
43
|
+
sa.Column('language', sa.String(10), nullable=True),
|
|
44
|
+
sa.Column('email', sa.String(256), nullable=True,
|
|
45
|
+
index=True, unique=True),
|
|
46
|
+
sa.Column('email_sent', sa.DateTime, nullable=True),
|
|
47
|
+
)
|
|
48
|
+
|
|
49
|
+
# Set all values to False
|
|
50
|
+
connection = op.get_bind()
|
|
51
|
+
assert connection is not None
|
|
52
|
+
with connection.begin():
|
|
53
|
+
connection.execute(users.update().values(disabled=False))
|
|
54
|
+
|
|
55
|
+
# Set column to NOT NULL
|
|
56
|
+
with op.batch_alter_table('users', schema=None) as batch_op:
|
|
57
|
+
batch_op.alter_column(
|
|
58
|
+
'disabled',
|
|
59
|
+
existing_type=sa.BOOLEAN(),
|
|
60
|
+
nullable=False,
|
|
61
|
+
)
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
def downgrade():
|
|
65
|
+
with op.batch_alter_table('users', schema=None) as batch_op:
|
|
66
|
+
batch_op.drop_column('disabled')
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
"""remove document groups
|
|
2
|
+
|
|
3
|
+
Revision ID: 43d6c240309d
|
|
4
|
+
Revises: bc8e0e0677e9
|
|
5
|
+
Create Date: 2021-07-14 17:54:23.308674
|
|
6
|
+
|
|
7
|
+
"""
|
|
8
|
+
from alembic import op
|
|
9
|
+
import sqlalchemy as sa
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
# revision identifiers, used by Alembic.
|
|
13
|
+
revision = '43d6c240309d'
|
|
14
|
+
down_revision = 'bc8e0e0677e9'
|
|
15
|
+
branch_labels = None
|
|
16
|
+
depends_on = None
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def upgrade():
|
|
20
|
+
op.drop_table('document_groups')
|
|
21
|
+
|
|
22
|
+
op.drop_index('ix_groups_path')
|
|
23
|
+
op.drop_index('ix_groups_project_id')
|
|
24
|
+
op.drop_table('groups')
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def downgrade():
|
|
28
|
+
op.create_table(
|
|
29
|
+
'groups',
|
|
30
|
+
sa.Column('id', sa.INTEGER(), nullable=False),
|
|
31
|
+
sa.Column('project_id', sa.INTEGER(), nullable=False),
|
|
32
|
+
sa.Column('path', sa.VARCHAR(length=200), nullable=False),
|
|
33
|
+
sa.Column('description', sa.TEXT(), nullable=False),
|
|
34
|
+
sa.ForeignKeyConstraint(
|
|
35
|
+
['project_id'],
|
|
36
|
+
['projects.id'],
|
|
37
|
+
name='fk_groups_project_id_projects',
|
|
38
|
+
ondelete='CASCADE',
|
|
39
|
+
),
|
|
40
|
+
sa.PrimaryKeyConstraint('id'),
|
|
41
|
+
sa.UniqueConstraint(
|
|
42
|
+
'project_id',
|
|
43
|
+
'path',
|
|
44
|
+
name='uq_groups_project_id',
|
|
45
|
+
),
|
|
46
|
+
)
|
|
47
|
+
op.create_index(
|
|
48
|
+
'ix_groups_project_id',
|
|
49
|
+
'groups',
|
|
50
|
+
['project_id'],
|
|
51
|
+
unique=False,
|
|
52
|
+
)
|
|
53
|
+
op.create_index(
|
|
54
|
+
'ix_groups_path',
|
|
55
|
+
'groups',
|
|
56
|
+
['path'],
|
|
57
|
+
unique=False,
|
|
58
|
+
)
|
|
59
|
+
|
|
60
|
+
op.create_table(
|
|
61
|
+
'document_groups',
|
|
62
|
+
sa.Column('document_id', sa.INTEGER(), nullable=False),
|
|
63
|
+
sa.Column('group_id', sa.INTEGER(), nullable=False),
|
|
64
|
+
sa.ForeignKeyConstraint(
|
|
65
|
+
['document_id'],
|
|
66
|
+
['documents.id'],
|
|
67
|
+
name='fk_document_groups_document_id_documents',
|
|
68
|
+
ondelete='CASCADE',
|
|
69
|
+
),
|
|
70
|
+
sa.ForeignKeyConstraint(
|
|
71
|
+
['group_id'],
|
|
72
|
+
['groups.id'],
|
|
73
|
+
name='fk_document_groups_group_id_groups',
|
|
74
|
+
ondelete='CASCADE',
|
|
75
|
+
),
|
|
76
|
+
sa.PrimaryKeyConstraint(
|
|
77
|
+
'document_id',
|
|
78
|
+
'group_id',
|
|
79
|
+
name='pk_document_groups',
|
|
80
|
+
),
|
|
81
|
+
)
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
"""cascades
|
|
2
|
+
|
|
3
|
+
Revision ID: 447d636f72c5
|
|
4
|
+
Revises: 80b1cc9d4c22
|
|
5
|
+
Create Date: 2018-11-17 13:50:51.570871
|
|
6
|
+
|
|
7
|
+
"""
|
|
8
|
+
from alembic import op
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
# revision identifiers, used by Alembic.
|
|
12
|
+
revision = '447d636f72c5'
|
|
13
|
+
down_revision = '80b1cc9d4c22'
|
|
14
|
+
branch_labels = None
|
|
15
|
+
depends_on = None
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def upgrade():
|
|
19
|
+
with op.batch_alter_table('commands') as batch_op:
|
|
20
|
+
batch_op.drop_constraint(
|
|
21
|
+
'fk_commands_project_id_projects',
|
|
22
|
+
type_='foreignkey',
|
|
23
|
+
)
|
|
24
|
+
batch_op.create_foreign_key(
|
|
25
|
+
batch_op.f('fk_commands_project_id_projects'),
|
|
26
|
+
'projects', ['project_id'], ['id'],
|
|
27
|
+
ondelete='CASCADE',
|
|
28
|
+
)
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def downgrade():
|
|
32
|
+
with op.batch_alter_table('commands') as batch_op:
|
|
33
|
+
batch_op.drop_constraint(
|
|
34
|
+
batch_op.f('fk_commands_project_id_projects'),
|
|
35
|
+
type_='foreignkey',
|
|
36
|
+
)
|
|
37
|
+
batch_op.create_foreign_key(
|
|
38
|
+
'fk_commands_project_id_projects',
|
|
39
|
+
'projects', ['project_id'], ['id'],
|
|
40
|
+
)
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
"""add more indexes
|
|
2
|
+
|
|
3
|
+
Revision ID: 491de2dc7cd7
|
|
4
|
+
Revises: d86c45d7aa8a
|
|
5
|
+
Create Date: 2021-11-09 16:50:41.582391
|
|
6
|
+
|
|
7
|
+
"""
|
|
8
|
+
from alembic import op
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
# revision identifiers, used by Alembic.
|
|
12
|
+
revision = '491de2dc7cd7'
|
|
13
|
+
down_revision = 'd86c45d7aa8a'
|
|
14
|
+
branch_labels = None
|
|
15
|
+
depends_on = None
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def upgrade():
|
|
19
|
+
with op.batch_alter_table('commands', schema=None) as batch_op:
|
|
20
|
+
batch_op.create_index(
|
|
21
|
+
batch_op.f('ix_commands_document_id'),
|
|
22
|
+
['document_id'],
|
|
23
|
+
unique=False,
|
|
24
|
+
)
|
|
25
|
+
batch_op.create_index(
|
|
26
|
+
batch_op.f('ix_commands_user_login'),
|
|
27
|
+
['user_login'],
|
|
28
|
+
unique=False,
|
|
29
|
+
)
|
|
30
|
+
|
|
31
|
+
with op.batch_alter_table('highlight_tags', schema=None) as batch_op:
|
|
32
|
+
batch_op.create_index(
|
|
33
|
+
batch_op.f('ix_highlight_tags_highlight_id'),
|
|
34
|
+
['highlight_id'],
|
|
35
|
+
unique=False,
|
|
36
|
+
)
|
|
37
|
+
batch_op.create_index(
|
|
38
|
+
batch_op.f('ix_highlight_tags_tag_id'),
|
|
39
|
+
['tag_id'],
|
|
40
|
+
unique=False,
|
|
41
|
+
)
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
def downgrade():
|
|
45
|
+
with op.batch_alter_table('highlight_tags', schema=None) as batch_op:
|
|
46
|
+
batch_op.drop_index(batch_op.f('ix_highlight_tags_tag_id'))
|
|
47
|
+
batch_op.drop_index(batch_op.f('ix_highlight_tags_highlight_id'))
|
|
48
|
+
|
|
49
|
+
with op.batch_alter_table('commands', schema=None) as batch_op:
|
|
50
|
+
batch_op.drop_index(batch_op.f('ix_commands_user_login'))
|
|
51
|
+
batch_op.drop_index(batch_op.f('ix_commands_document_id'))
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
"""user login length
|
|
2
|
+
|
|
3
|
+
Revision ID: 4c55b3b3ff30
|
|
4
|
+
Revises: 1b96a606551d
|
|
5
|
+
Create Date: 2024-03-11 09:31:27.003711
|
|
6
|
+
|
|
7
|
+
"""
|
|
8
|
+
from alembic import op
|
|
9
|
+
import sqlalchemy as sa
|
|
10
|
+
import logging
|
|
11
|
+
|
|
12
|
+
logger = logging.getLogger(__name__)
|
|
13
|
+
|
|
14
|
+
# revision identifiers, used by Alembic.
|
|
15
|
+
revision = '4c55b3b3ff30'
|
|
16
|
+
down_revision = '1b96a606551d'
|
|
17
|
+
branch_labels = None
|
|
18
|
+
depends_on = None
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def upgrade():
|
|
22
|
+
db_url = op.get_context().config.get_section('alembic')['sqlalchemy.url']
|
|
23
|
+
if db_url.startswith('sqlite:'):
|
|
24
|
+
# SQLite doesn't mind field length
|
|
25
|
+
logger.info(f"Skipping upgrade {revision} for SQLite")
|
|
26
|
+
else:
|
|
27
|
+
op.alter_column('users', 'login',
|
|
28
|
+
existing_type=sa.VARCHAR(length=30),
|
|
29
|
+
type_=sa.String(length=255),
|
|
30
|
+
existing_nullable=True)
|
|
31
|
+
op.alter_column('project_members', 'user_login',
|
|
32
|
+
existing_type=sa.VARCHAR(length=30),
|
|
33
|
+
type_=sa.String(length=255),
|
|
34
|
+
existing_nullable=True)
|
|
35
|
+
op.alter_column('commands', 'user_login',
|
|
36
|
+
existing_type=sa.VARCHAR(length=30),
|
|
37
|
+
type_=sa.String(length=255),
|
|
38
|
+
existing_nullable=True)
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
def downgrade():
|
|
42
|
+
db_url = op.get_context().config.get_section('alembic')['sqlalchemy.url']
|
|
43
|
+
if db_url.startswith('sqlite:'):
|
|
44
|
+
# SQLite doesn't mind field length
|
|
45
|
+
logger.info(f"Skipping downgrade {down_revision} for SQLite")
|
|
46
|
+
else:
|
|
47
|
+
op.alter_column('users', 'login',
|
|
48
|
+
existing_type=sa.VARCHAR(length=255),
|
|
49
|
+
type_=sa.String(length=30),
|
|
50
|
+
existing_nullable=True)
|
|
51
|
+
op.alter_column('project_members', 'user_login',
|
|
52
|
+
existing_type=sa.VARCHAR(length=255),
|
|
53
|
+
type_=sa.String(length=30),
|
|
54
|
+
existing_nullable=True)
|
|
55
|
+
op.alter_column('commands', 'user_login',
|
|
56
|
+
existing_type=sa.VARCHAR(length=255),
|
|
57
|
+
type_=sa.String(length=30),
|
|
58
|
+
existing_nullable=True)
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
"""user with parent for permissions
|
|
2
|
+
|
|
3
|
+
Revision ID: 61a4abcc8769
|
|
4
|
+
Revises: 1b29e68900c1
|
|
5
|
+
Create Date: 2025-03-10 12:58:30.136770
|
|
6
|
+
|
|
7
|
+
"""
|
|
8
|
+
from alembic import op
|
|
9
|
+
import sqlalchemy as sa
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
# revision identifiers, used by Alembic.
|
|
13
|
+
revision = '61a4abcc8769'
|
|
14
|
+
down_revision = '1b29e68900c1'
|
|
15
|
+
branch_labels = None
|
|
16
|
+
depends_on = None
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def upgrade():
|
|
20
|
+
with op.batch_alter_table('users', schema=None) as batch_op:
|
|
21
|
+
batch_op.add_column(sa.Column('approved_by_user_login',
|
|
22
|
+
sa.String(length=255),
|
|
23
|
+
nullable=True))
|
|
24
|
+
batch_op.create_index(batch_op.f('ix_users_approved_by_user_login'),
|
|
25
|
+
['approved_by_user_login'],
|
|
26
|
+
unique=False)
|
|
27
|
+
batch_op.create_foreign_key(
|
|
28
|
+
batch_op.f('fk_users_approved_by_user_login_users'),
|
|
29
|
+
'users', ['approved_by_user_login'],
|
|
30
|
+
['login'],
|
|
31
|
+
ondelete='CASCADE')
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
def downgrade():
|
|
35
|
+
with op.batch_alter_table('users', schema=None) as batch_op:
|
|
36
|
+
batch_op.drop_constraint(
|
|
37
|
+
batch_op.f('fk_users_approved_by_user_login_users'),
|
|
38
|
+
type_='foreignkey')
|
|
39
|
+
batch_op.drop_index(batch_op.f('ix_users_approved_by_user_login'))
|
|
40
|
+
batch_op.drop_column('approved_by_user_login')
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
"""increase password hash size
|
|
2
|
+
|
|
3
|
+
Revision ID: 6489b5f9cfb5
|
|
4
|
+
Revises: 09c662cd9483
|
|
5
|
+
Create Date: 2022-10-06 17:17:36.212586
|
|
6
|
+
|
|
7
|
+
"""
|
|
8
|
+
from alembic import op
|
|
9
|
+
import sqlalchemy as sa
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
# revision identifiers, used by Alembic.
|
|
13
|
+
revision = '6489b5f9cfb5'
|
|
14
|
+
down_revision = '09c662cd9483'
|
|
15
|
+
branch_labels = None
|
|
16
|
+
depends_on = None
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def upgrade():
|
|
20
|
+
with op.batch_alter_table('users') as batch_op:
|
|
21
|
+
batch_op.alter_column(
|
|
22
|
+
'hashed_password',
|
|
23
|
+
existing_type=sa.String(120),
|
|
24
|
+
type_=sa.String(192),
|
|
25
|
+
)
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def downgrade():
|
|
29
|
+
with op.batch_alter_table('users') as batch_op:
|
|
30
|
+
batch_op.alter_column(
|
|
31
|
+
'hashed_password',
|
|
32
|
+
existing_type=sa.String(192),
|
|
33
|
+
type_=sa.String(120),
|
|
34
|
+
)
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
"""fix_unique_tags
|
|
2
|
+
|
|
3
|
+
Revision ID: 679f625e6e6a
|
|
4
|
+
Revises: dd37d9027a24
|
|
5
|
+
Create Date: 2018-11-12 17:20:50.420807
|
|
6
|
+
|
|
7
|
+
"""
|
|
8
|
+
from alembic import op
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
# revision identifiers, used by Alembic.
|
|
12
|
+
revision = '679f625e6e6a'
|
|
13
|
+
down_revision = 'dd37d9027a24'
|
|
14
|
+
branch_labels = None
|
|
15
|
+
depends_on = None
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def upgrade():
|
|
19
|
+
with op.batch_alter_table('tags') as batch_op:
|
|
20
|
+
batch_op.create_unique_constraint(
|
|
21
|
+
batch_op.f('uq_groups_project_id'),
|
|
22
|
+
['project_id', 'path'],
|
|
23
|
+
)
|
|
24
|
+
batch_op.drop_index('ix_tags_path')
|
|
25
|
+
batch_op.create_index(
|
|
26
|
+
batch_op.f('ix_tags_path'),
|
|
27
|
+
['path'],
|
|
28
|
+
unique=False,
|
|
29
|
+
)
|
|
30
|
+
|
|
31
|
+
with op.batch_alter_table('groups') as batch_op:
|
|
32
|
+
batch_op.create_unique_constraint(
|
|
33
|
+
batch_op.f('uq_groups_project_id'),
|
|
34
|
+
['project_id', 'path'],
|
|
35
|
+
)
|
|
36
|
+
batch_op.drop_index('ix_groups_path')
|
|
37
|
+
batch_op.create_index(
|
|
38
|
+
batch_op.f('ix_groups_path'),
|
|
39
|
+
['path'],
|
|
40
|
+
unique=False,
|
|
41
|
+
)
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
def downgrade():
|
|
45
|
+
with op.batch_alter_table('groups') as batch_op:
|
|
46
|
+
batch_op.drop_index(batch_op.f('ix_groups_path'))
|
|
47
|
+
batch_op.create_index('ix_groups_path', ['path'], unique=True)
|
|
48
|
+
batch_op.drop_constraint(
|
|
49
|
+
batch_op.f('uq_groups_project_id'),
|
|
50
|
+
type_='unique',
|
|
51
|
+
)
|
|
52
|
+
|
|
53
|
+
with op.batch_alter_table('tags') as batch_op:
|
|
54
|
+
batch_op.drop_index(batch_op.f('ix_tags_path'))
|
|
55
|
+
batch_op.create_index('ix_tags_path', ['path'], unique=True)
|
|
56
|
+
batch_op.drop_constraint(
|
|
57
|
+
batch_op.f('uq_groups_project_id'),
|
|
58
|
+
type_='unique',
|
|
59
|
+
)
|