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,41 @@
|
|
|
1
|
+
"""Add parent_id column to collection table
|
|
2
|
+
|
|
3
|
+
Revision ID: 77c4543a5b9b
|
|
4
|
+
Revises: de678cef2a94
|
|
5
|
+
Create Date: 2025-07-17 10:28:57.783573
|
|
6
|
+
|
|
7
|
+
"""
|
|
8
|
+
from alembic import op
|
|
9
|
+
import sqlalchemy as sa
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
# revision identifiers, used by Alembic.
|
|
13
|
+
revision = '77c4543a5b9b'
|
|
14
|
+
down_revision = 'de678cef2a94'
|
|
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('collections', schema=None) as batch_op:
|
|
22
|
+
batch_op.add_column(
|
|
23
|
+
sa.Column('parent_id', sa.Integer(), nullable=True))
|
|
24
|
+
batch_op.create_index(batch_op.f('ix_collections_parent_id'), [
|
|
25
|
+
'parent_id'], unique=False)
|
|
26
|
+
batch_op.create_foreign_key(
|
|
27
|
+
batch_op.f('fk_collections_parent_id_collections'),
|
|
28
|
+
'collections', ['parent_id'], ['id'], ondelete='CASCADE')
|
|
29
|
+
|
|
30
|
+
# ### end Alembic commands ###
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
def downgrade():
|
|
34
|
+
# ### commands auto generated by Alembic - please adjust! ###
|
|
35
|
+
with op.batch_alter_table('collections', schema=None) as batch_op:
|
|
36
|
+
batch_op.drop_constraint(batch_op.f(
|
|
37
|
+
'fk_collections_parent_id_collections'), type_='foreignkey')
|
|
38
|
+
batch_op.drop_index(batch_op.f('ix_collections_parent_id'))
|
|
39
|
+
batch_op.drop_column('parent_id')
|
|
40
|
+
|
|
41
|
+
# ### end Alembic commands ###
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
"""Add is_archived column to projets
|
|
2
|
+
|
|
3
|
+
Revision ID: 7c94b7a31e69
|
|
4
|
+
Revises: 77c4543a5b9b
|
|
5
|
+
Create Date: 2026-01-20 15:45:37.747588
|
|
6
|
+
|
|
7
|
+
"""
|
|
8
|
+
from alembic import op
|
|
9
|
+
import sqlalchemy as sa
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
# revision identifiers, used by Alembic.
|
|
13
|
+
revision = '7c94b7a31e69'
|
|
14
|
+
down_revision = '77c4543a5b9b'
|
|
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('projects', schema=None) as batch_op:
|
|
22
|
+
batch_op.add_column(sa.Column(
|
|
23
|
+
'is_archived', sa.Boolean(),
|
|
24
|
+
nullable=False, server_default='false'
|
|
25
|
+
))
|
|
26
|
+
|
|
27
|
+
op.execute(
|
|
28
|
+
'UPDATE projects SET is_archived = false'
|
|
29
|
+
' WHERE is_archived != false'
|
|
30
|
+
)
|
|
31
|
+
# ### end Alembic commands ###
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
def downgrade():
|
|
35
|
+
# ### commands auto generated by Alembic - please adjust! ###
|
|
36
|
+
with op.batch_alter_table('projects', schema=None) as batch_op:
|
|
37
|
+
batch_op.drop_column('is_archived')
|
|
38
|
+
|
|
39
|
+
# ### end Alembic commands ###
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
"""change edugain displayname length
|
|
2
|
+
|
|
3
|
+
Revision ID: 7f56de97e3c8
|
|
4
|
+
Revises: fbdc29566f62
|
|
5
|
+
Create Date: 2024-04-04 21:56:27.801558
|
|
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 = '7f56de97e3c8'
|
|
16
|
+
down_revision = 'fbdc29566f62'
|
|
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('edigainidps', 'e_displayname',
|
|
28
|
+
existing_type=sa.VARCHAR(length=255),
|
|
29
|
+
type_=sa.Text(),
|
|
30
|
+
existing_nullable=True)
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
def downgrade():
|
|
34
|
+
db_url = op.get_context().config.get_section('alembic')['sqlalchemy.url']
|
|
35
|
+
if db_url.startswith('sqlite:'):
|
|
36
|
+
# SQLite doesn't mind field length
|
|
37
|
+
logger.info(f"Skipping downgrade {down_revision} for SQLite")
|
|
38
|
+
else:
|
|
39
|
+
op.alter_column('edigainidps', 'e_displayname',
|
|
40
|
+
existing_type=sa.Text(),
|
|
41
|
+
type_=sa.VARCHAR(length=255),
|
|
42
|
+
existing_nullable=True)
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
"""remove invalid hltags
|
|
2
|
+
|
|
3
|
+
Revision ID: 807c0cc0ecf6
|
|
4
|
+
Revises: b23f3b7a638e
|
|
5
|
+
Create Date: 2021-02-17 13:04:13.809606
|
|
6
|
+
|
|
7
|
+
"""
|
|
8
|
+
from alembic import op
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
# revision identifiers, used by Alembic.
|
|
12
|
+
revision = '807c0cc0ecf6'
|
|
13
|
+
down_revision = 'b23f3b7a638e'
|
|
14
|
+
branch_labels = None
|
|
15
|
+
depends_on = None
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def upgrade():
|
|
19
|
+
op.execute(
|
|
20
|
+
'''\
|
|
21
|
+
DELETE FROM highlight_tags
|
|
22
|
+
WHERE
|
|
23
|
+
-- Project of the highlight
|
|
24
|
+
(
|
|
25
|
+
SELECT documents.project_id
|
|
26
|
+
FROM highlights
|
|
27
|
+
INNER JOIN documents
|
|
28
|
+
ON highlights.document_id = documents.id
|
|
29
|
+
WHERE highlights.id = highlight_tags.highlight_id
|
|
30
|
+
)
|
|
31
|
+
NOT IN
|
|
32
|
+
-- Project of the tag
|
|
33
|
+
(
|
|
34
|
+
SELECT tags.project_id
|
|
35
|
+
FROM tags
|
|
36
|
+
WHERE tags.id = highlight_tags.tag_id
|
|
37
|
+
);
|
|
38
|
+
''',
|
|
39
|
+
)
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
def downgrade():
|
|
43
|
+
pass
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
"""add User.email
|
|
2
|
+
|
|
3
|
+
Revision ID: 80b1cc9d4c22
|
|
4
|
+
Revises: 679f625e6e6a
|
|
5
|
+
Create Date: 2018-11-17 11:46:29.572383
|
|
6
|
+
|
|
7
|
+
"""
|
|
8
|
+
from alembic import op
|
|
9
|
+
import sqlalchemy as sa
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
# revision identifiers, used by Alembic.
|
|
13
|
+
revision = '80b1cc9d4c22'
|
|
14
|
+
down_revision = '679f625e6e6a'
|
|
15
|
+
branch_labels = None
|
|
16
|
+
depends_on = None
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def upgrade():
|
|
20
|
+
op.add_column(
|
|
21
|
+
'users',
|
|
22
|
+
sa.Column('email', sa.String(), nullable=True),
|
|
23
|
+
)
|
|
24
|
+
op.add_column(
|
|
25
|
+
'users',
|
|
26
|
+
sa.Column('email_sent', sa.DateTime(), nullable=True),
|
|
27
|
+
)
|
|
28
|
+
op.create_index(op.f('ix_users_email'), 'users', ['email'], unique=True)
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def downgrade():
|
|
32
|
+
with op.batch_alter_table('users') as batch_op:
|
|
33
|
+
batch_op.drop_index(batch_op.f('ix_users_email'))
|
|
34
|
+
batch_op.drop_column('email_sent')
|
|
35
|
+
batch_op.drop_column('email')
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
"""add User.language
|
|
2
|
+
|
|
3
|
+
Revision ID: 91ade71ccf4d
|
|
4
|
+
Revises: bce44849c2f2
|
|
5
|
+
Create Date: 2019-05-09 14:02:38.185065
|
|
6
|
+
|
|
7
|
+
"""
|
|
8
|
+
from alembic import op
|
|
9
|
+
import sqlalchemy as sa
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
# revision identifiers, used by Alembic.
|
|
13
|
+
revision = '91ade71ccf4d'
|
|
14
|
+
down_revision = 'bce44849c2f2'
|
|
15
|
+
branch_labels = None
|
|
16
|
+
depends_on = None
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def upgrade():
|
|
20
|
+
op.add_column(
|
|
21
|
+
'users',
|
|
22
|
+
sa.Column('language', sa.String(), nullable=True),
|
|
23
|
+
)
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def downgrade():
|
|
27
|
+
with op.batch_alter_table('users') as batch_op:
|
|
28
|
+
batch_op.drop_column('language')
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
"""Add collections tables and associations with documents
|
|
2
|
+
|
|
3
|
+
Revision ID: 955db2e523d1
|
|
4
|
+
Revises: 61a4abcc8769
|
|
5
|
+
Create Date: 2025-07-08 11:16:54.546173
|
|
6
|
+
|
|
7
|
+
"""
|
|
8
|
+
from alembic import op
|
|
9
|
+
import sqlalchemy as sa
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
# revision identifiers, used by Alembic.
|
|
13
|
+
revision = '955db2e523d1'
|
|
14
|
+
down_revision = '61a4abcc8769'
|
|
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('collections',
|
|
22
|
+
sa.Column('id', sa.Integer(), nullable=False),
|
|
23
|
+
sa.Column('name', sa.String(length=200), nullable=False),
|
|
24
|
+
sa.Column('description', sa.Text(), nullable=True),
|
|
25
|
+
sa.Column('created', sa.DateTime(), nullable=False),
|
|
26
|
+
sa.Column('owner_login', sa.String(length=255),
|
|
27
|
+
nullable=True),
|
|
28
|
+
sa.ForeignKeyConstraint(
|
|
29
|
+
['owner_login'], ['users.login'],
|
|
30
|
+
name=op.f('fk_collections_owner_login_users')),
|
|
31
|
+
sa.PrimaryKeyConstraint('id', name=op.f('pk_collections')),
|
|
32
|
+
sqlite_autoincrement=True
|
|
33
|
+
)
|
|
34
|
+
op.create_table('collection_documents',
|
|
35
|
+
sa.Column('collection_id', sa.Integer(), nullable=False),
|
|
36
|
+
sa.Column('document_id', sa.Integer(), nullable=False),
|
|
37
|
+
sa.ForeignKeyConstraint(
|
|
38
|
+
['collection_id'], ['collections.id'],
|
|
39
|
+
name=op.f(
|
|
40
|
+
'fk_collection_documents_collection_id_'
|
|
41
|
+
'collections'),
|
|
42
|
+
ondelete='CASCADE'),
|
|
43
|
+
sa.ForeignKeyConstraint(
|
|
44
|
+
['document_id'], ['documents.id'],
|
|
45
|
+
name=op.f(
|
|
46
|
+
'fk_collection_documents_document_id_'
|
|
47
|
+
'documents'),
|
|
48
|
+
ondelete='CASCADE'),
|
|
49
|
+
sa.PrimaryKeyConstraint(
|
|
50
|
+
'collection_id', 'document_id',
|
|
51
|
+
name=op.f('pk_collection_documents'))
|
|
52
|
+
)
|
|
53
|
+
# ### end Alembic commands ###
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
def downgrade():
|
|
57
|
+
# ### commands auto generated by Alembic - please adjust! ###
|
|
58
|
+
op.drop_table('collection_documents')
|
|
59
|
+
op.drop_table('collections')
|
|
60
|
+
# ### end Alembic commands ###
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
"""add user hide_code_counts
|
|
2
|
+
|
|
3
|
+
Revision ID: a1b2c3d4e5f6
|
|
4
|
+
Revises: 7c94b7a31e69
|
|
5
|
+
Create Date: 2026-07-10 00:00:00.000000
|
|
6
|
+
|
|
7
|
+
"""
|
|
8
|
+
from alembic import op
|
|
9
|
+
import sqlalchemy as sa
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
# revision identifiers, used by Alembic.
|
|
13
|
+
revision = 'a1b2c3d4e5f6'
|
|
14
|
+
down_revision = '7c94b7a31e69'
|
|
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(
|
|
22
|
+
sa.Column('hide_code_counts', sa.Boolean(), nullable=True),
|
|
23
|
+
)
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def downgrade():
|
|
27
|
+
with op.batch_alter_table('users', schema=None) as batch_op:
|
|
28
|
+
batch_op.drop_column('hide_code_counts')
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
"""add password change date
|
|
2
|
+
|
|
3
|
+
Revision ID: b23f3b7a638e
|
|
4
|
+
Revises: 91ade71ccf4d
|
|
5
|
+
Create Date: 2020-04-03 15:54:14.870029
|
|
6
|
+
|
|
7
|
+
"""
|
|
8
|
+
from alembic import op
|
|
9
|
+
import sqlalchemy as sa
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
# revision identifiers, used by Alembic.
|
|
13
|
+
revision = 'b23f3b7a638e'
|
|
14
|
+
down_revision = '91ade71ccf4d'
|
|
15
|
+
branch_labels = None
|
|
16
|
+
depends_on = None
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def upgrade():
|
|
20
|
+
op.add_column(
|
|
21
|
+
'users',
|
|
22
|
+
sa.Column('password_set_date', sa.DateTime(), nullable=True),
|
|
23
|
+
)
|
|
24
|
+
|
|
25
|
+
# Set the password set time to now if a password is set
|
|
26
|
+
op.execute(
|
|
27
|
+
'''\
|
|
28
|
+
UPDATE users SET password_set_date=DATETIME()
|
|
29
|
+
WHERE hashed_password IS NOT NULL;
|
|
30
|
+
''',
|
|
31
|
+
)
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
def downgrade():
|
|
35
|
+
with op.batch_alter_table('users', schema=None) as batch_op:
|
|
36
|
+
batch_op.drop_column('password_set_date')
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
"""add project compact_layout
|
|
2
|
+
|
|
3
|
+
Revision ID: b7c1e2d3f4a5
|
|
4
|
+
Revises: a1b2c3d4e5f6
|
|
5
|
+
Create Date: 2026-08-12 13:15:00.000000
|
|
6
|
+
|
|
7
|
+
"""
|
|
8
|
+
from alembic import op
|
|
9
|
+
import sqlalchemy as sa
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
# revision identifiers, used by Alembic.
|
|
13
|
+
revision = 'b7c1e2d3f4a5'
|
|
14
|
+
down_revision = 'a1b2c3d4e5f6'
|
|
15
|
+
branch_labels = None
|
|
16
|
+
depends_on = None
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def upgrade():
|
|
20
|
+
with op.batch_alter_table('projects', schema=None) as batch_op:
|
|
21
|
+
batch_op.add_column(
|
|
22
|
+
sa.Column('compact_layout', sa.Boolean(), nullable=True),
|
|
23
|
+
)
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def downgrade():
|
|
27
|
+
with op.batch_alter_table('projects', schema=None) as batch_op:
|
|
28
|
+
batch_op.drop_column('compact_layout')
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
"""rename fields in Command JSON payload
|
|
2
|
+
|
|
3
|
+
Revision ID: bc8e0e0677e9
|
|
4
|
+
Revises: ecb4065de575
|
|
5
|
+
Create Date: 2021-06-05 18:24:28.756510
|
|
6
|
+
|
|
7
|
+
"""
|
|
8
|
+
from alembic import op
|
|
9
|
+
import json
|
|
10
|
+
import sqlalchemy as sa
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
# revision identifiers, used by Alembic.
|
|
14
|
+
revision = 'bc8e0e0677e9'
|
|
15
|
+
down_revision = 'ecb4065de575'
|
|
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
|
+
commands = sa.Table(
|
|
29
|
+
'commands',
|
|
30
|
+
meta,
|
|
31
|
+
sa.Column('id', sa.Integer, primary_key=True),
|
|
32
|
+
sa.Column('date', sa.DateTime, nullable=False),
|
|
33
|
+
sa.Column('user_login', sa.String(30), nullable=False),
|
|
34
|
+
sa.Column('project_id', sa.Integer, nullable=False),
|
|
35
|
+
sa.Column('document_id', sa.Integer, nullable=True),
|
|
36
|
+
sa.Column('payload', sa.Text, nullable=False),
|
|
37
|
+
)
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
def _do_map(map_func):
|
|
41
|
+
"""Map JSON payloads through the given function.
|
|
42
|
+
"""
|
|
43
|
+
connection = op.get_bind()
|
|
44
|
+
assert connection is not None
|
|
45
|
+
|
|
46
|
+
payloads = connection.execute('''\
|
|
47
|
+
SELECT id, payload FROM commands;
|
|
48
|
+
''')
|
|
49
|
+
update = []
|
|
50
|
+
for id, payload in payloads:
|
|
51
|
+
payload = json.loads(payload)
|
|
52
|
+
payload = map_func(payload)
|
|
53
|
+
if payload is not None:
|
|
54
|
+
payload = json.dumps(payload, sort_keys=True)
|
|
55
|
+
update.append({'cmd_id': id, 'cmd_payload': payload})
|
|
56
|
+
|
|
57
|
+
if update:
|
|
58
|
+
with connection.begin():
|
|
59
|
+
connection.execute(
|
|
60
|
+
(
|
|
61
|
+
commands.update()
|
|
62
|
+
.where(commands.c.id == sa.bindparam('cmd_id'))
|
|
63
|
+
.values(payload=sa.bindparam('cmd_payload'))
|
|
64
|
+
),
|
|
65
|
+
update,
|
|
66
|
+
)
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
def upgrade():
|
|
70
|
+
def _map_forward(payload):
|
|
71
|
+
if payload['type'] == 'project_meta':
|
|
72
|
+
payload['project_name'] = payload.pop('name')
|
|
73
|
+
elif payload['type'] == 'document_add':
|
|
74
|
+
payload['document_name'] = payload.pop('name')
|
|
75
|
+
elif payload['type'] in ('highlight_add', 'highlight_delete'):
|
|
76
|
+
payload['highlight_id'] = payload.pop('id')
|
|
77
|
+
elif payload['type'] in ('tag_add', 'tag_delete'):
|
|
78
|
+
if payload['type'] == 'tag_add':
|
|
79
|
+
payload['tag_path'] = payload.pop('path')
|
|
80
|
+
payload['tag_id'] = payload.pop('id')
|
|
81
|
+
elif payload['type'] == 'tag_merge':
|
|
82
|
+
payload['src_tag_id'] = payload.pop('src')
|
|
83
|
+
payload['dest_tag_id'] = payload.pop('dest')
|
|
84
|
+
elif 'id' in payload:
|
|
85
|
+
raise ValueError(
|
|
86
|
+
"Unknown command type with 'id' field: %r" % payload['type']
|
|
87
|
+
)
|
|
88
|
+
elif 'name' in payload:
|
|
89
|
+
raise ValueError(
|
|
90
|
+
"Unknown command type with 'name' field: %r" % payload['type']
|
|
91
|
+
)
|
|
92
|
+
else:
|
|
93
|
+
return None
|
|
94
|
+
return payload
|
|
95
|
+
|
|
96
|
+
_do_map(_map_forward)
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
def downgrade():
|
|
100
|
+
def _map_back(payload):
|
|
101
|
+
if 'id' in payload:
|
|
102
|
+
raise ValueError(
|
|
103
|
+
"Command type with 'id' field: %r" % payload['type']
|
|
104
|
+
)
|
|
105
|
+
elif 'name' in payload:
|
|
106
|
+
raise ValueError(
|
|
107
|
+
"Command type with 'name' field: %r" % payload['type']
|
|
108
|
+
)
|
|
109
|
+
elif payload['type'] == 'project_meta':
|
|
110
|
+
payload['name'] = payload.pop('project_name')
|
|
111
|
+
elif payload['type'] == 'document_add':
|
|
112
|
+
payload['name'] = payload.pop('document_name')
|
|
113
|
+
elif payload['type'] in ('highlight_add', 'highlight_delete'):
|
|
114
|
+
payload['id'] = payload.pop('highlight_id')
|
|
115
|
+
elif payload['type'] in ('tag_add', 'tag_delete'):
|
|
116
|
+
if payload['type'] == 'tag_add':
|
|
117
|
+
payload['path'] = payload.pop('tag_path')
|
|
118
|
+
payload['id'] = payload.pop('tag_id')
|
|
119
|
+
elif payload['type'] == 'tag_merge':
|
|
120
|
+
payload['src'] = payload.pop('src_tag_id')
|
|
121
|
+
payload['dest'] = payload.pop('dest_tag_id')
|
|
122
|
+
else:
|
|
123
|
+
return None
|
|
124
|
+
return payload
|
|
125
|
+
|
|
126
|
+
_do_map(_map_back)
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
"""lowercase logins
|
|
2
|
+
|
|
3
|
+
Revision ID: bce44849c2f2
|
|
4
|
+
Revises: 447d636f72c5
|
|
5
|
+
Create Date: 2019-04-04 21:50:36.046753
|
|
6
|
+
|
|
7
|
+
"""
|
|
8
|
+
from alembic import op
|
|
9
|
+
from sqlalchemy.orm import Session
|
|
10
|
+
import sys
|
|
11
|
+
|
|
12
|
+
from taguette import validate
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
# revision identifiers, used by Alembic.
|
|
16
|
+
revision = 'bce44849c2f2'
|
|
17
|
+
down_revision = '447d636f72c5'
|
|
18
|
+
branch_labels = None
|
|
19
|
+
depends_on = None
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def upgrade():
|
|
23
|
+
# Add ON UPDATE CASCADE to foreign keys
|
|
24
|
+
with op.batch_alter_table('project_members') as batch_op:
|
|
25
|
+
batch_op.drop_constraint(
|
|
26
|
+
'fk_project_members_user_login_users',
|
|
27
|
+
type_='foreignkey',
|
|
28
|
+
)
|
|
29
|
+
batch_op.create_foreign_key(
|
|
30
|
+
batch_op.f('fk_project_members_user_login_users'),
|
|
31
|
+
'users', ['user_login'], ['login'],
|
|
32
|
+
onupdate='CASCADE', ondelete='CASCADE',
|
|
33
|
+
)
|
|
34
|
+
with op.batch_alter_table('commands') as batch_op:
|
|
35
|
+
batch_op.drop_constraint(
|
|
36
|
+
'fk_commands_user_login_users',
|
|
37
|
+
type_='foreignkey',
|
|
38
|
+
)
|
|
39
|
+
batch_op.create_foreign_key(
|
|
40
|
+
batch_op.f('fk_commands_user_login_users'),
|
|
41
|
+
'users', ['user_login'], ['login'],
|
|
42
|
+
onupdate='CASCADE',
|
|
43
|
+
)
|
|
44
|
+
|
|
45
|
+
# Update the login
|
|
46
|
+
op.execute('UPDATE users SET login = lower(login);')
|
|
47
|
+
# Should update via the cascade:
|
|
48
|
+
# op.execute('UPDATE project_members SET user_login = lower(user_login);')
|
|
49
|
+
# op.execute('UPDATE commands SET user_login = lower(user_login);')
|
|
50
|
+
|
|
51
|
+
# Check that logins pass new validation requirements
|
|
52
|
+
bind = op.get_bind()
|
|
53
|
+
session = Session(bind=bind)
|
|
54
|
+
logins = session.execute(
|
|
55
|
+
'''\
|
|
56
|
+
SELECT login FROM users;
|
|
57
|
+
''',
|
|
58
|
+
)
|
|
59
|
+
error = False
|
|
60
|
+
for row in logins:
|
|
61
|
+
login, = row
|
|
62
|
+
try:
|
|
63
|
+
changed = validate.fix_user_login(login)
|
|
64
|
+
except validate.InvalidFormat:
|
|
65
|
+
error = True
|
|
66
|
+
print("User login %r does not abide to new restrictions" % login,
|
|
67
|
+
file=sys.stderr)
|
|
68
|
+
else:
|
|
69
|
+
if changed != login:
|
|
70
|
+
raise ValueError("Login %r is still not canonical after "
|
|
71
|
+
"migration, please report this bug!" % login)
|
|
72
|
+
if error:
|
|
73
|
+
raise ValueError("Some user logins do not pass validation")
|
|
74
|
+
session.close()
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
def downgrade():
|
|
78
|
+
with op.batch_alter_table('project_members') as batch_op:
|
|
79
|
+
batch_op.drop_constraint(
|
|
80
|
+
batch_op.f('fk_project_members_user_login_users'),
|
|
81
|
+
type_='foreignkey',
|
|
82
|
+
)
|
|
83
|
+
batch_op.create_foreign_key(
|
|
84
|
+
'fk_project_members_user_login_users',
|
|
85
|
+
'users', ['user_login'], ['login'],
|
|
86
|
+
ondelete='CASCADE',
|
|
87
|
+
)
|
|
88
|
+
with op.batch_alter_table('commands') as batch_op:
|
|
89
|
+
batch_op.drop_constraint(
|
|
90
|
+
batch_op.f('fk_commands_user_login_users'),
|
|
91
|
+
type_='foreignkey',
|
|
92
|
+
)
|
|
93
|
+
batch_op.create_foreign_key(
|
|
94
|
+
'fk_commands_user_login_users',
|
|
95
|
+
'users', ['user_login'], ['login'],
|
|
96
|
+
)
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
"""update user for external logins
|
|
2
|
+
|
|
3
|
+
Revision ID: ca076140922f
|
|
4
|
+
Revises: 2467bab602b7
|
|
5
|
+
Create Date: 2024-03-08 08:31:48.228013
|
|
6
|
+
|
|
7
|
+
"""
|
|
8
|
+
from alembic import op
|
|
9
|
+
import sqlalchemy as sa
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
# revision identifiers, used by Alembic.
|
|
13
|
+
revision = 'ca076140922f'
|
|
14
|
+
down_revision = '2467bab602b7'
|
|
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(sa.Column('external', sa.Boolean(), nullable=True))
|
|
23
|
+
|
|
24
|
+
# ### end Alembic commands ###
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def downgrade():
|
|
28
|
+
# ### commands auto generated by Alembic - please adjust! ###
|
|
29
|
+
with op.batch_alter_table('users', schema=None) as batch_op:
|
|
30
|
+
batch_op.drop_column('external')
|
|
31
|
+
|
|
32
|
+
# ### end Alembic commands ###
|