├── .env
├── .gitignore
├── .gitmodules
├── .npmignore
├── .vscode
└── settings.json
├── .yarnclean
├── CONTRIBUTING.adoc
├── LICENSE.txt
├── Makefile
├── NOTICE.txt
├── README.md
├── appsv
├── model
│ ├── .gitignore
│ ├── COPYRIGHT.txt
│ ├── LICENSE-AGPL-3.0.txt
│ ├── build.sbt
│ ├── docs
│ │ └── notes.txt
│ ├── lock.sbt
│ ├── old
│ │ ├── .build-log.txt
│ │ ├── nice.debate.xhtml
│ │ └── notes-old.txt
│ └── src
│ │ ├── main
│ │ ├── java
│ │ │ └── name
│ │ │ │ └── fraser
│ │ │ │ └── neil
│ │ │ │ └── plaintext
│ │ │ │ └── diff_match_patch.java
│ │ └── scala
│ │ │ └── com
│ │ │ └── debiki
│ │ │ └── core
│ │ │ ├── AuditLogEntry.scala
│ │ │ ├── Category.scala
│ │ │ ├── CompletedFormRenderer.scala
│ │ │ ├── DbDao2.scala
│ │ │ ├── EditedSettings.scala
│ │ │ ├── Email.scala
│ │ │ ├── Event.scala
│ │ │ ├── IdentityProvider.scala
│ │ │ ├── Notice.scala
│ │ │ ├── Page.scala
│ │ │ ├── PageParts.scala
│ │ │ ├── PagePath.scala
│ │ │ ├── PagePopularityStats.scala
│ │ │ ├── PinnedPositionCalcer.scala
│ │ │ ├── Post.scala
│ │ │ ├── PostAction.scala
│ │ │ ├── PostRelType.scala
│ │ │ ├── PostRevision.scala
│ │ │ ├── PostsReadStats.scala
│ │ │ ├── Prelude.scala
│ │ │ ├── ReviewReason.scala
│ │ │ ├── ReviewTask.scala
│ │ │ ├── ScalaBasedDatabaseMigrations.scala
│ │ │ ├── Site.scala
│ │ │ ├── SiteTransaction.scala
│ │ │ ├── SystemTransaction.scala
│ │ │ ├── Tag.scala
│ │ │ ├── TrueId.scala
│ │ │ ├── TySession.scala
│ │ │ ├── Validation.scala
│ │ │ ├── dao-db.scala
│ │ │ ├── exceptions.scala
│ │ │ ├── links.scala
│ │ │ ├── notifications.scala
│ │ │ ├── package.scala
│ │ │ ├── permissions.scala
│ │ │ ├── quota.scala
│ │ │ ├── statistics.scala
│ │ │ ├── trust-threat-level.scala
│ │ │ ├── types.scala
│ │ │ ├── uploads.scala
│ │ │ ├── user.scala
│ │ │ ├── watchbar.scala
│ │ │ └── webhooks.scala
│ │ └── test
│ │ └── scala
│ │ └── com
│ │ └── debiki
│ │ └── core
│ │ ├── PagePartsTest.scala
│ │ ├── PagePathTest.scala
│ │ ├── PageReadingProgressTest.scala
│ │ ├── PinnedPositionCalcerSpec.scala
│ │ ├── PreludeTest.scala
│ │ ├── QuotaTest.scala
│ │ ├── ReviewTaskSpec.scala
│ │ ├── StatsCalcTest.scala
│ │ ├── StringInterpolatorsTest.scala
│ │ ├── UserSpec.scala
│ │ ├── ValidationTest.scala
│ │ └── WatchbarTest.scala
├── rdb
│ ├── .gitignore
│ ├── build.sbt
│ ├── docs
│ │ └── notes.txt
│ ├── lock.sbt
│ ├── scripts
│ │ ├── create-play_evolutions-table.sql
│ │ ├── debiki-pg-views.sql
│ │ ├── debiki-postgre.sql
│ │ ├── delete-tenant.txt
│ │ ├── old
│ │ │ ├── flyway-migrations
│ │ │ │ ├── y2014
│ │ │ │ │ ├── v1__base_version.sql
│ │ │ │ │ ├── v2__posts_read_stats.sql
│ │ │ │ │ ├── v3__no_email.sql
│ │ │ │ │ ├── v4__drop_login_table_add_username.sql
│ │ │ │ │ ├── v5__multireply.sql
│ │ │ │ │ ├── v6__always_commonmark.sql
│ │ │ │ │ ├── v7__user_page_settings.sql
│ │ │ │ │ ├── v8__email_for_each_new_post.sql
│ │ │ │ │ └── v9__page_role_homepage.sql
│ │ │ │ ├── y2015
│ │ │ │ │ ├── v10__create_main_site.sql
│ │ │ │ │ ├── v11__site_creator_email.sql
│ │ │ │ │ ├── v12__simple_quotas.sql
│ │ │ │ │ ├── v13__dw2_posts.sql
│ │ │ │ │ ├── v14__migrate_posts.scala
│ │ │ │ │ ├── v15__constraints_triggers.sql
│ │ │ │ │ ├── v16__merge_guests_users.sql
│ │ │ │ │ ├── v17__invites.sql
│ │ │ │ │ ├── v18__block_bury_https_scrypt.sql
│ │ │ │ │ ├── v19__last_reply_bugfix_plans.sql
│ │ │ │ │ ├── v20__target_site_id.sql
│ │ │ │ │ ├── v21__pinned_topics_about_page_post_type.sql
│ │ │ │ │ ├── v22__q_a_site.sql
│ │ │ │ │ ├── v23__problems_ideas.sql
│ │ │ │ │ ├── v24__categories.sql
│ │ │ │ │ ├── v25__cache_html.sql
│ │ │ │ │ ├── v26__longer_site_hostname.sql
│ │ │ │ │ ├── v27__longer_emails.sql
│ │ │ │ │ ├── v28__uploads.sql
│ │ │ │ │ ├── v29__post_revisions.sql
│ │ │ │ │ ├── v30__avatars.sql
│ │ │ │ │ ├── v31__review.sql
│ │ │ │ │ ├── v32__upload_quotas.sql
│ │ │ │ │ ├── v33__messages.sql
│ │ │ │ │ └── v34__notfs_index.sql
│ │ │ │ └── y2016
│ │ │ │ │ ├── v35__html_tag_css_classes.sql
│ │ │ │ │ ├── v36__safe_settings.sql
│ │ │ │ │ ├── v37__audit_log_email.sql
│ │ │ │ │ └── v38__no_deleted_by.sql
│ │ │ └── play-evolutions
│ │ │ │ ├── 1.sql
│ │ │ │ ├── 10.sql
│ │ │ │ ├── 11.sql
│ │ │ │ ├── 12.sql
│ │ │ │ ├── 13.sql
│ │ │ │ ├── 14.sql
│ │ │ │ ├── 15.sql
│ │ │ │ ├── 16.sql
│ │ │ │ ├── 2.sql
│ │ │ │ ├── 3.sql
│ │ │ │ ├── 4.sql
│ │ │ │ ├── 5.sql
│ │ │ │ ├── 6.sql
│ │ │ │ ├── 7.sql
│ │ │ │ ├── 8.sql
│ │ │ │ └── 9.sql
│ │ ├── pending-evolutions.sql
│ │ └── useful-commands.sql
│ └── src
│ │ └── main
│ │ ├── resources
│ │ └── db
│ │ │ └── migration
│ │ │ ├── db-wip.sql
│ │ │ ├── old
│ │ │ └── skip_v426__bookmarks.sql
│ │ │ ├── r__comments.sql
│ │ │ ├── r__functions.sql
│ │ │ ├── r__triggers.sql
│ │ │ ├── tags-old-wip.sql
│ │ │ ├── wip_r__views.sql
│ │ │ ├── y2016
│ │ │ ├── v10__remove_constraint.sql
│ │ │ ├── v11__topic_list_style.sql
│ │ │ ├── v12__spam_settings.sql
│ │ │ ├── v13__page_hidden_at.sql
│ │ │ ├── v14__more_settings.sql
│ │ │ ├── v15__change_usernamed.sql
│ │ │ ├── v16__show_settings.sql
│ │ │ ├── v17__check_names_trimmed.sql
│ │ │ ├── v1__base_version.sql
│ │ │ ├── v2__rename_tables.sql
│ │ │ ├── v3__unknown_user.sql
│ │ │ ├── v4__index_queue.sql
│ │ │ ├── v5__superadmin.sql
│ │ │ ├── v6__branch_sideways.sql
│ │ │ ├── v7__tags.sql
│ │ │ ├── v8__system_user_id_1.sql
│ │ │ ├── v9__spam_check_queue.sql
│ │ │ └── wip.sql
│ │ │ ├── y2017
│ │ │ ├── v18__forum_settings_user_stats.sql
│ │ │ ├── v19__site_id_int_perms_on_pages.sql
│ │ │ ├── v20__migr_perms.sql
│ │ │ ├── v21__username_lowercase.sql
│ │ │ ├── v22__backup_test_log.sql
│ │ │ ├── v23__no_email.sql
│ │ │ ├── v24__page_pop.sql
│ │ │ ├── v25__summary_emails.sql
│ │ │ ├── v26__nulls_last.sql
│ │ │ ├── v27__plan_done_any_role.sql
│ │ │ ├── v28__allow_embedding.sql
│ │ │ ├── v29__remove_columns.sql
│ │ │ ├── v30__page_started_at_wait_until.sql
│ │ │ ├── v31__num_posts_total.sql
│ │ │ └── v32__page_constraints.sql
│ │ │ ├── y2018
│ │ │ ├── v33__many_emails.sql
│ │ │ ├── v34__longer_allow_embedding.sql
│ │ │ ├── v35__sub_communities_lang_delete_user.sql
│ │ │ ├── v367__more_settings.sql
│ │ │ ├── v368__no_browser_id_cookie.sql
│ │ │ ├── v369__cache_many_undo_review.sql
│ │ │ ├── v36__publ_site_id.sql
│ │ │ ├── v370__bump_after_close.sql
│ │ │ ├── v371__drafts.sql
│ │ │ ├── v372__sso_and_api.sql
│ │ │ ├── v373__sso_settings.sql
│ │ │ ├── v374__many_invites.sql
│ │ │ ├── v375__more_notfs.sql
│ │ │ └── v376__guest_id_constr.sql
│ │ │ ├── y2019
│ │ │ ├── v377__tour_tips_seen.sql
│ │ │ ├── v378__more_settings.sql
│ │ │ ├── v379__tos_privacy_settings.sql
│ │ │ ├── v380__review_task_notfs.sql
│ │ │ ├── v381__spam_check_results.sql
│ │ │ ├── v382__group_members.sql
│ │ │ ├── v383__ext_imp_id.sql
│ │ │ ├── v384__invites_add_to_group.sql
│ │ │ ├── v385__sso_logout_url.sql
│ │ │ ├── v386__guests_wo_browserid_use_extid.sql
│ │ │ ├── v387__email_length.sql
│ │ │ └── v388__rm_email_notf_char_check.sql
│ │ │ ├── y2020
│ │ │ ├── v389__backup_test_log.sql
│ │ │ ├── v390__sort_order.sql
│ │ │ ├── v391__root_cat_slug.sql
│ │ │ ├── v392__cors_settings.sql
│ │ │ ├── v393__nav_conf_settings.sql
│ │ │ ├── v394__settings.sql
│ │ │ ├── v395__appr_bef_settings.sql
│ │ │ ├── v396__links.sql
│ │ │ ├── v397__oidc.sql
│ │ │ ├── v398__max_html_length.sql
│ │ │ ├── v399__site_feature_flags.sql
│ │ │ ├── v400__missing_fx_ix.sql
│ │ │ ├── v401__sort_and_media_settings.sql
│ │ │ └── v402__idp_verif_email_domains.sql
│ │ │ ├── y2021
│ │ │ ├── v403__settings_purge_sites.sql
│ │ │ ├── v404__profile_pic_length.sql
│ │ │ ├── v405__email_secrets.sql
│ │ │ ├── v406__emb_coms_sso.sql
│ │ │ ├── v407__upvote_features.adoc
│ │ │ ├── v407__upvote_features.sql
│ │ │ ├── v408__email_from_name.sql
│ │ │ ├── v409__notices.sql
│ │ │ ├── v410__tags_refactored.sql
│ │ │ ├── v411__sessions_t.sql
│ │ │ └── v412__forum_search_box.sql
│ │ │ ├── y2022
│ │ │ ├── v413__webhooks.sql
│ │ │ ├── v414__webhooks_constr.sql
│ │ │ ├── v415__drop_reply_at_constr.sql
│ │ │ ├── v416__may_and_msg_id.sql
│ │ │ ├── v417__smtp_id_pat_rels.sql
│ │ │ └── v418__comment_sort_deindex.sql
│ │ │ ├── y2023
│ │ │ ├── v419__anon_posts_disc_prefs.sql
│ │ │ ├── v420__ugc_domain_sort_ideas.sql
│ │ │ ├── v421__sys_settings.sql
│ │ │ ├── v422__maint_msg.sql
│ │ │ ├── v423__type_val_type.sql
│ │ │ └── v424__job_queue.sql
│ │ │ ├── y2024
│ │ │ ├── v425__term_sess_more_conf.sql
│ │ │ ├── v426__bookmarks.sql
│ │ │ └── wip_v427__alias.sql
│ │ │ ├── y2025
│ │ │ └── v427__switch_to_sqlx.sql
│ │ │ └── y2999
│ │ │ ├── wip_sect_disc_props_views_stats.sql
│ │ │ ├── wip_v41Y__samesite_none.sql
│ │ │ └── wip_v427__sidebar_menu.sql
│ │ └── scala
│ │ ├── com
│ │ └── debiki
│ │ │ └── dao
│ │ │ └── rdb
│ │ │ ├── ApiSecretsSiteDaoMixin.scala
│ │ │ ├── AuditLogSiteDaoMixin.scala
│ │ │ ├── AuthnSiteTxMixin.scala
│ │ │ ├── BlocksSiteDaoMixin.scala
│ │ │ ├── CategoriesSiteDaoMixin.scala
│ │ │ ├── CreateSiteSystemDaoMixin.scala
│ │ │ ├── DraftsSiteDaoMixin.scala
│ │ │ ├── EmailAddressesSiteDaoMixin.scala
│ │ │ ├── LinksSiteTxMixin.scala
│ │ │ ├── LoginSiteDaoMixin.scala
│ │ │ ├── NotificationsSiteDaoMixin.scala
│ │ │ ├── PageNotfPrefsSiteTxMixin.scala
│ │ │ ├── PageUsersSiteDaoMixin.scala
│ │ │ ├── PagesSiteDaoMixin.scala
│ │ │ ├── PermsOnPagesRdbMixin.scala
│ │ │ ├── PostsReadStatsSiteDaoMixin.scala
│ │ │ ├── PostsSiteDaoMixin.scala
│ │ │ ├── Rdb.scala
│ │ │ ├── RdbDaoFactory.scala
│ │ │ ├── RdbSiteTransaction.scala
│ │ │ ├── RdbSystemTransaction.scala
│ │ │ ├── RdbUtil.scala
│ │ │ ├── ReviewTasksSiteDaoMixin.scala
│ │ │ ├── SearchSiteDaoMixin.scala
│ │ │ ├── SessionsRdbMixin.scala
│ │ │ ├── SettingsSiteDaoMixin.scala
│ │ │ ├── SpamCheckQueueDaoMixin.scala
│ │ │ ├── TagsRdbMixin.scala
│ │ │ ├── TagsSiteDaoMixin.scala
│ │ │ ├── UploadsSiteDaoMixin.scala
│ │ │ ├── UserSiteDaoMixin.scala
│ │ │ ├── UsernamesSiteDaoMixin.scala
│ │ │ └── WebhooksRdbMixin.scala
│ │ └── db
│ │ └── migration
│ │ └── MigrationHelper.scala
└── server
│ ├── controllers
│ ├── AdminController.scala
│ ├── ApiSecretsController.scala
│ ├── ApiV0Controller.scala
│ ├── Application.scala
│ ├── CloseCollapseController.scala
│ ├── CreateSiteController.scala
│ ├── CustomFormController.scala
│ ├── DebugTestController.scala
│ ├── DraftsController.scala
│ ├── EditController.scala
│ ├── EmbeddedTopicsController.scala
│ ├── FlagController.scala
│ ├── ForumController.scala
│ ├── GroupTalkController.scala
│ ├── ImpersonateController.scala
│ ├── InviteController.scala
│ ├── LegalController.scala
│ ├── LoginAsGuestController.scala
│ ├── LoginController.scala
│ ├── LoginWithOpenAuthController.scala
│ ├── LoginWithPasswordController.scala
│ ├── ModerationController.scala
│ ├── PageController.scala
│ ├── PageTitleSettingsController.scala
│ ├── ReplyController.scala
│ ├── ResetPasswordController.scala
│ ├── SearchController.scala
│ ├── SettingsController.scala
│ ├── SiteAssetBundlesController.scala
│ ├── SpecialContentController.scala
│ ├── SuperAdminController.scala
│ ├── TagsController.scala
│ ├── UnsubscriptionController.scala
│ ├── UploadsController.scala
│ ├── UserController.scala
│ ├── Utils.scala
│ ├── ViewPageController.scala
│ ├── VoteController.scala
│ └── package.scala
│ ├── debiki
│ ├── AssetBundleLoader.scala
│ ├── DatabaseUtils.scala
│ ├── DeadlockDetector.scala
│ ├── Debiki.scala
│ ├── DebikiHttp.scala
│ ├── Globals.scala
│ ├── HtmlUtils.scala
│ ├── ImageUtils.scala
│ ├── JsonUtils.scala
│ ├── MailerActor.scala
│ ├── MostMetrics.scala
│ ├── Nashorn.scala
│ ├── PageTpi.scala
│ ├── RateLimiter.scala
│ ├── RateLimits.scala
│ ├── ReactJson.scala
│ ├── SpecialContentPages.scala
│ ├── TextAndHtml.scala
│ ├── ThingsToReview.scala
│ ├── dao
│ │ ├── AssetBundleDao.scala
│ │ ├── AuditDao.scala
│ │ ├── CategoriesDao.scala
│ │ ├── CreateSiteDao.scala
│ │ ├── FeedsDao.scala
│ │ ├── ForumDao.scala
│ │ ├── MemCache.scala
│ │ ├── MessagesDao.scala
│ │ ├── PageDao.scala
│ │ ├── PageLinksDao.scala
│ │ ├── PagePathMetaDao.scala
│ │ ├── PageStuffDao.scala
│ │ ├── PagesDao.scala
│ │ ├── PostsDao.scala
│ │ ├── RedisCache.scala
│ │ ├── RenderContentService.scala
│ │ ├── RenderedPageHtmlDao.scala
│ │ ├── ReviewsDao.scala
│ │ ├── SearchDao.scala
│ │ ├── SettingsDao.scala
│ │ ├── SiteDao.scala
│ │ ├── SpecialContentDao.scala
│ │ ├── SystemDao.scala
│ │ ├── TagsDao.scala
│ │ ├── UploadsDao.scala
│ │ ├── UserDao.scala
│ │ ├── WatchbarDao.scala
│ │ └── package.scala
│ ├── feed-serializers.scala
│ ├── package.scala
│ └── settings.scala
│ ├── ed
│ ├── server
│ │ └── EdAppLoader.scala
│ └── stackdriver
│ │ └── StackdriverLayout.scala
│ ├── talkyard
│ └── server
│ │ ├── JsX.scala
│ │ ├── PostRenderer.scala
│ │ ├── TyAppLoader.scala
│ │ ├── TyController.scala
│ │ ├── TyFilters.scala
│ │ ├── api
│ │ ├── ActionDoer.scala
│ │ ├── ActionParser.scala
│ │ ├── GetController.scala
│ │ ├── GetPatsImpl.scala
│ │ ├── InclFields.scala
│ │ ├── InclFieldsParSer.scala
│ │ ├── ListController.scala
│ │ ├── PostsListFoundJson.scala
│ │ ├── QueryDoController.scala
│ │ ├── ThingsFoundJson.scala
│ │ └── package.scala
│ │ ├── authn
│ │ ├── AuthnSiteDaoMixin.scala
│ │ ├── OAuth2Provider-from-Silhouette.scala
│ │ ├── OidcClaims.scala
│ │ ├── SsoAuthnController.scala
│ │ ├── TyOidcScribeJavaApi20.scala
│ │ ├── WellKnownIdps.scala
│ │ └── package.scala
│ │ ├── authz
│ │ ├── Authz.scala
│ │ ├── AuthzSiteDaoMixin.scala
│ │ ├── ReqrAndTgt.scala
│ │ └── package.scala
│ │ ├── dao
│ │ ├── StaleStuff.scala
│ │ └── package.scala
│ │ ├── emails
│ │ ├── in
│ │ │ ├── EmailsInController.scala
│ │ │ └── package.scala
│ │ ├── out
│ │ │ ├── Emails.scala
│ │ │ └── package.scala
│ │ └── transl
│ │ ├── events
│ │ ├── EventsParSer.scala
│ │ ├── WebhooksController.scala
│ │ ├── WebhooksParSer.scala
│ │ └── WebhooksSiteDaoMixin.scala
│ │ ├── http
│ │ ├── DebikiRequest.scala
│ │ ├── JsonOrFormRequestBody.scala
│ │ ├── PageRequest.scala
│ │ ├── PlainApiActions.scala
│ │ ├── SafeActions.scala
│ │ └── package.scala
│ │ ├── jobs
│ │ └── Janitor.scala
│ │ ├── linkpreviews
│ │ ├── LinkPreviewHtml.scala
│ │ ├── LinkPreviewRenderer.scala
│ │ └── engines
│ │ │ ├── GiphyOnebox.scala
│ │ │ ├── ImageOnebox.scala
│ │ │ ├── OEmbedLinkPrevwRendrEng.scala
│ │ │ ├── VideoOnebox.scala
│ │ │ ├── YouTubeOnebox.scala
│ │ │ └── linkPreviewEngines.scala
│ │ ├── logging
│ │ ├── LastErrsActor.scala
│ │ └── package.scala
│ │ ├── migrations
│ │ ├── Migration14.scala
│ │ └── ScalaBasedMigrations.scala
│ │ ├── notf
│ │ ├── NotfHtmlRenderer.scala
│ │ ├── NotificationGenerator.scala
│ │ └── NotifierActor.scala
│ │ ├── package.scala
│ │ ├── parser
│ │ ├── MapParSer.scala
│ │ ├── PageParSer.scala
│ │ ├── PasetoParSer.scala
│ │ ├── ScalarsParSer.scala
│ │ └── package.scala
│ │ ├── plugins
│ │ └── utx
│ │ │ └── UsabilityTestingExchangeController.scala
│ │ ├── pop
│ │ ├── PagePopularityCalculator.scala
│ │ └── PagePopularityDao.scala
│ │ ├── pubsub
│ │ ├── PubSub.scala
│ │ ├── SubscriberController.scala
│ │ └── WebSocketMessageHandler.scala
│ │ ├── rendr
│ │ └── package.scala
│ │ ├── search
│ │ ├── IndexCreator.scala
│ │ ├── SearchEnginIndexer.scala
│ │ ├── SearchEngine.scala
│ │ ├── SearchQuery.scala
│ │ ├── SearchQueryParser.scala
│ │ └── package.scala
│ │ ├── security
│ │ ├── PasetoSec.scala
│ │ ├── ReservedNames.scala
│ │ ├── WhatApiSecret.scala
│ │ └── package.scala
│ │ ├── sess
│ │ ├── SessionController.scala
│ │ └── SessionSiteDaoMixin.scala
│ │ ├── sitepatch
│ │ ├── SitePatch.scala
│ │ ├── SitePatchController.scala
│ │ ├── SitePatchMaker.scala
│ │ ├── SitePatchParser.scala
│ │ └── SitePatcher.scala
│ │ ├── spam
│ │ ├── QuickSpamCheckDao.scala
│ │ ├── SpamCheckActor.scala
│ │ └── SpamChecker.scala
│ │ ├── summaryemails
│ │ ├── SummaryEmailsDao.scala
│ │ └── UnsubFromSummariesController.scala
│ │ ├── talk
│ │ └── PostsController.scala
│ │ └── util
│ │ └── package.scala
│ └── views
│ ├── adminPage.scala.html
│ ├── adminlogin
│ ├── adminLoginPage.scala.html
│ └── oneTimeLoginLinkEmail.scala.html
│ ├── authn
│ ├── authnPage.scala.html
│ ├── authnPageHtmlDoc.scala.html
│ ├── sendAuthnResultToOpenerCloseCurWin.scala.html
│ ├── showCreateUserDialogInOpenerCloseCurWin.scala.html
│ └── showCreateUserDialogInThisWin.scala.html
│ ├── confirmOneMoreEmailAddressEmail.scala.html
│ ├── createaccount
│ ├── accountAlreadyExistsEmail.scala.html
│ ├── accountApprovedEmail.scala.html
│ ├── createAccountLinkEmail.scala.html
│ ├── newMemberToApproveEmail.scala.html
│ └── welcomePage.scala.html
│ ├── createsite
│ ├── createSitePage.scala.html
│ ├── main.scala.html
│ └── welcomeEmail.scala.html
│ ├── debikiMeta.scala.html
│ ├── debikiScriptsHead.scala.html
│ ├── debikiStyles.scala.html
│ ├── editorHelp.scala.html
│ ├── emailVerified.scala.html
│ ├── embeddedEditor.scala.html
│ ├── googleAnalytics.scala.html
│ ├── invite
│ ├── inviteAcceptedEmail.scala.html
│ ├── inviteEmail.scala.html
│ └── welcomeSetPasswordEmail.scala.html
│ ├── legal
│ ├── privacyPolicy.scala.html
│ └── termsOfUse.scala.html
│ ├── login
│ ├── accountsLinkedPleaseLoginAgain.scala.html
│ ├── accountsNotLinkedPleaseLoginAgain.scala.html
│ ├── askIfLinkAccounts.scala.html
│ ├── verifyYourEmailAddr.scala.html
│ └── verifyYourEmailAddrEmail.scala.html
│ ├── resetpassword
│ ├── chooseNewPassword.scala.html
│ ├── emailSent.scala.html
│ ├── passwordHasBeenChanged.scala.html
│ ├── resetPasswordEmail.scala.html
│ └── specifyEmailAddress.scala.html
│ ├── scripts
│ └── googleAnalytics4.scala.html
│ ├── specialpages
│ └── createSomethingHerePage.scala.html
│ ├── summaryemails
│ ├── unsubFromSummariesDonePage.scala.html
│ └── unsubFromSummariesPage.scala.html
│ ├── tags
│ ├── jsonDataMustBeFirst.scala.html
│ └── talkyardScriptBundles.scala.html
│ ├── templates
│ ├── page.scala.html
│ ├── search.scala.html
│ ├── users.scala.html
│ └── wrapper.scala.html
│ ├── unsubscribe
│ └── youHaveBeenUnsubscribed.scala.html
│ └── unsubscribePage.scala.html
├── build.sbt
├── client
├── app-2d
│ ├── sidebar
│ │ └── minimap.2d.ts
│ └── utterscroll
│ │ ├── utterscroll-init-tips.js
│ │ ├── utterscroll-init-tips.styl
│ │ └── utterscroll.js
├── app-editor
│ ├── editor-bundle-already-loaded.d.ts
│ ├── editor-prelude.editor.ts
│ ├── editor
│ │ ├── commonmark.editor.ts
│ │ ├── editor.editor.ts
│ │ ├── editor.styl
│ │ ├── formatting-help.editor.ts
│ │ ├── formatting-help.styl
│ │ ├── link-previews-markdown-it-plugin.editor.ts
│ │ └── mentions-markdown-it-plugin.ts
│ └── tsconfig.json
├── app-head
│ ├── head-bundle.ts
│ └── tsconfig.json
├── app-more
│ ├── edit-history
│ │ ├── edit-history-dialog.more.ts
│ │ └── edit-history-dialog.styl
│ ├── editor
│ │ ├── PageRole.styl
│ │ ├── PageRoleDropdown.more.ts
│ │ ├── title-editor.more.ts
│ │ └── title-editor.styl
│ ├── forum
│ │ ├── create-category-dialog.more.ts
│ │ ├── create-category-dialog.styl
│ │ ├── edit-intro-dialog.more.ts
│ │ └── edit-intro-dialog.styl
│ ├── help
│ │ └── help-dialog.more.ts
│ ├── login
│ │ ├── create-user-dialog.more.ts
│ │ ├── create-user.styl
│ │ ├── login-dialog.more.ts
│ │ ├── login-dialog.styl
│ │ ├── login.styl
│ │ ├── new-password-input.more.ts
│ │ ├── new-password-input.styl
│ │ └── new-password-page.more.ts
│ ├── more-bundle-already-loaded.d.ts
│ ├── more-prelude.more.ts
│ ├── morekit
│ │ ├── proxy-diag.more.ts
│ │ └── proxy-diag.styl
│ ├── no-page
│ │ ├── no-page.styl
│ │ └── non-existing-page.more.ts
│ ├── notification
│ │ ├── Notification.more.ts
│ │ ├── email-notf-prefs.more.ts
│ │ ├── notf-prefs-dropdown.more.ts
│ │ ├── notf-prefs-dropdown.styl
│ │ └── notfs.styl
│ ├── page-dialogs
│ │ ├── ChangePageModal.more.ts
│ │ ├── ChangePageModal.styl
│ │ ├── __dialog-template__.ts
│ │ ├── about-user-dialog.more.ts
│ │ ├── about-user-dialog.styl
│ │ ├── add-remove-people-dialogs.more.ts
│ │ ├── anons-allowed-diag.more.ts
│ │ ├── choose-author-owner.more.ts
│ │ ├── delete-post-dialog.more.ts
│ │ ├── delete-post-dialog.styl
│ │ ├── disc-layout-dialog.more.ts
│ │ ├── flag-dialog.more.ts
│ │ ├── likes-dialog.more.ts
│ │ ├── move-post-dialog.styl
│ │ ├── move-posts-dialog.more.ts
│ │ ├── never-alwas-diag.more.ts
│ │ ├── progress-bar-dialog.more.ts
│ │ ├── pseudonyms-allowed-btn.more.ts
│ │ ├── see-wrench-dialog.more.ts
│ │ ├── see-wrench-dialog.styl
│ │ ├── share-dialog.more.ts
│ │ ├── share-dialogs.styl
│ │ ├── snooze-notfs-dialog.more.ts
│ │ ├── snooze-notfs-dialog.styl
│ │ ├── tags-dialog.more.ts
│ │ ├── tags-dialog.styl
│ │ ├── view-as-dialog.more.ts
│ │ ├── view-as-dialog.styl
│ │ ├── votes-dialog.styl
│ │ ├── wikify-dialog.more.ts
│ │ └── wikify-dialog.styl
│ ├── page-tools
│ │ ├── page-tools.more.ts
│ │ └── page-tools.styl
│ ├── persona
│ │ └── persona-info-diag.ts
│ ├── react-bootstrap-old
│ │ └── Input.more.ts
│ ├── search
│ │ ├── search-page.more.ts
│ │ └── search-results-page.styl
│ ├── sub-communities
│ │ └── create-join-sub-community.more.ts
│ ├── tags
│ │ ├── bookmarks-dropdown.more.ts
│ │ ├── bookmarks-dropdown.styl
│ │ ├── create-tag-dlg.more.ts
│ │ ├── tag-dropdown.more.ts
│ │ ├── tag-dropdown.styl
│ │ ├── tags-app.more.ts
│ │ └── tags.more.styl
│ ├── topbar
│ │ └── my-menu.more.ts
│ ├── tsconfig.json
│ ├── users
│ │ ├── ActivitySummaryEmailsInterval.more.ts
│ │ ├── group-members.more.ts
│ │ ├── group-members.styl
│ │ ├── groups-page.more.ts
│ │ ├── groups-page.styl
│ │ ├── pat-perms.more.ts
│ │ ├── pat-perms.styl
│ │ ├── to-dos.more.ts
│ │ ├── user-activity.more.ts
│ │ ├── user-drafts-etc.more.ts
│ │ ├── user-invites.more.ts
│ │ ├── user-invites.styl
│ │ ├── user-notifications.more.ts
│ │ ├── user-preferences.more.ts
│ │ ├── user-prefs.styl
│ │ ├── user-summary.more.ts
│ │ ├── user-tasks.more.ts
│ │ ├── users-page.more.ts
│ │ └── users-page.styl
│ ├── util
│ │ ├── EmailInput.more.ts
│ │ ├── FullNameInput.more.ts
│ │ ├── UsernameInput.more.ts
│ │ ├── resizable.more.ts
│ │ ├── stupid-dialog.more.ts
│ │ ├── stupid-dialog.styl
│ │ └── trust-level-dialog.more.ts
│ ├── utils
│ │ ├── PageUnloadAlerter.more.ts
│ │ ├── PatternInput.more.ts
│ │ ├── PatternInput.styl
│ │ ├── diff-match-patch.more.ts
│ │ └── utils.more.ts
│ ├── widgets.more.ts
│ └── widgets
│ │ └── anon-purpose-btn.more.ts
├── app-slim
│ ├── BrowserStorage.ts
│ ├── ReactActions.ts
│ ├── ReactDispatcher.ts
│ ├── ReactStore.ts
│ ├── Server.ts
│ ├── ServerApi.ts
│ ├── avatar
│ │ ├── AvatarAndName.ts
│ │ ├── avatar.styl
│ │ └── avatar.ts
│ ├── call-start-stuff.js
│ ├── constants.ts
│ ├── disconnected.styl
│ ├── editor-bundle-not-yet-loaded.ts
│ ├── editor
│ │ ├── CdnLinkifyer.ts
│ │ ├── SelectCategoryDropdown.ts
│ │ └── onebox.styl
│ ├── form
│ │ ├── form.styl
│ │ └── form.ts
│ ├── forum
│ │ ├── forum.styl
│ │ └── forum.ts
│ ├── help
│ │ ├── help.styl
│ │ ├── help.ts
│ │ └── serverAnnouncements.ts
│ ├── if-in-iframe.styl
│ ├── if-in-iframe.ts
│ ├── init-all-react-roots.ts
│ ├── keyboard-shortcuts.styl
│ ├── keyboard-shortcuts.ts
│ ├── link-previews.ts
│ ├── links.ts
│ ├── login
│ │ ├── login-if-needed.ts
│ │ └── login-popup.js
│ ├── magic-time.ts
│ ├── me-getters.ts
│ ├── mixins.styl
│ ├── model.ts
│ ├── more-bundle-not-yet-loaded.ts
│ ├── notification
│ │ └── notf-prefs-button.ts
│ ├── old
│ │ ├── actions
│ │ │ └── popup-menu-unused.js
│ │ ├── arrows
│ │ │ └── arrows-svg-unused.js
│ │ ├── inline-threads
│ │ │ ├── inline-threads-unused.js
│ │ │ └── inline-threads-unused.styl
│ │ ├── unused-pin.ls
│ │ ├── unused-tagdog.js
│ │ ├── unused-unread-posts.ls
│ │ └── unused.styl
│ ├── oop-methods.ts
│ ├── page-dialogs
│ │ ├── open-share-popup.ts
│ │ ├── server-error-dialog.styl
│ │ └── server-error-dialog.ts
│ ├── page-methods.ts
│ ├── page
│ │ ├── arrows.styl
│ │ ├── arrows.ts
│ │ ├── cats-or-home-link.ts
│ │ ├── chat.styl
│ │ ├── chat.ts
│ │ ├── discussion.ts
│ │ ├── hacks.ts
│ │ ├── layout-threads.2d.js
│ │ ├── metabar.styl
│ │ ├── metabar.ts
│ │ ├── mind-maps.styl
│ │ ├── page.styl
│ │ ├── page.ts
│ │ ├── post-actions.styl
│ │ ├── post-actions.ts
│ │ ├── posts-read-tracker.ts
│ │ ├── posts.styl
│ │ ├── resize-threads.2d.js
│ │ ├── scroll-buttons.styl
│ │ ├── scroll-buttons.ts
│ │ ├── social-buttons.styl
│ │ ├── social-buttons.ts
│ │ └── threads.styl
│ ├── personas
│ │ ├── PersonaIndicator.ts
│ │ └── personas.ts
│ ├── plugins.styl
│ ├── plugins
│ │ └── usability-testing-exchange.styl
│ ├── prelude.ts
│ ├── print.styl
│ ├── privacy.styl
│ ├── pubsub
│ │ └── subscriptions.ts
│ ├── react-elements
│ │ └── name-login-btns.ts
│ ├── react-flux
│ │ ├── dispatcher.ts
│ │ └── invariant.ts
│ ├── rules.ts
│ ├── server-vars.ts
│ ├── sidebar
│ │ ├── sidebar.styl
│ │ └── sidebar.ts
│ ├── slim-bundle.d.ts
│ ├── staff-bundle-not-yet-loaded.ts
│ ├── start-page.ts
│ ├── start-stuff.ts
│ ├── store-getters.ts
│ ├── tags
│ │ ├── tags.styl
│ │ └── tags.ts
│ ├── theme.styl
│ ├── third-party.styl
│ ├── topbar
│ │ ├── topbar.styl
│ │ └── topbar.ts
│ ├── translations.d.ts
│ ├── tsconfig.json
│ ├── util
│ │ ├── ExplainingDropdown.styl
│ │ ├── ExplainingDropdown.ts
│ │ ├── FadingBackdrop.styl
│ │ ├── FadingBackdrop.ts
│ │ ├── resizable.styl
│ │ ├── scrollbox.styl
│ │ └── stupid-lightbox.js
│ ├── utils
│ │ ├── DropdownModal.styl
│ │ ├── DropdownModal.ts
│ │ ├── calcScrollRectIntoViewCoords.js
│ │ ├── close-cross.styl
│ │ ├── css-popup.styl
│ │ ├── detect-mouse.ts
│ │ ├── fade-in-on-click.styl
│ │ ├── fade-in-on-click.ts
│ │ ├── highlight-active-link-in-header.ts
│ │ ├── page-scroll-mixin.ts
│ │ ├── post-json.styl
│ │ ├── react-utils.ts
│ │ ├── scroll-into-view.ts
│ │ ├── show-and-highlight.ts
│ │ ├── site-utils.styl
│ │ ├── talkyard-tour.styl
│ │ ├── talkyard-tour.ts
│ │ ├── util-browser.js
│ │ ├── util.js
│ │ ├── utils.ts
│ │ └── window-zoom-resize-mixin.ts
│ ├── variables.styl
│ ├── watchbar
│ │ ├── watchbar.styl
│ │ └── watchbar.ts
│ ├── widgets.styl
│ ├── widgets.ts
│ └── widgets
│ │ └── widget-open-buttons.ts
├── app-staff
│ ├── admin
│ │ ├── AdminGuide.staff.ts
│ │ ├── admin-app.staff.ts
│ │ ├── admin-page.styl
│ │ ├── api-panel.staff.ts
│ │ ├── api-panel.styl
│ │ ├── backup-panel.staff.ts
│ │ ├── contents-panel.staff.ts
│ │ ├── hostname-editor.staff.ts
│ │ ├── hostname-editor.styl
│ │ ├── inspect-panel.styl
│ │ ├── inspect.staff.ts
│ │ ├── oop-method.staff.ts
│ │ ├── review-all.staff.ts
│ │ ├── review.styl
│ │ ├── special-contents.staff.ts
│ │ ├── staff-tours.staff.ts
│ │ ├── users-one.staff.ts
│ │ └── users.staff.ts
│ ├── create-site
│ │ ├── create-site.staff.ts
│ │ └── create-site.styl
│ ├── misc-staff.styl
│ ├── staff-bundle-already-loaded.d.ts
│ ├── staff-prelude.staff.ts
│ ├── superadmin
│ │ ├── superadmin-app.staff.ts
│ │ └── superadmin-app.styl
│ └── tsconfig.json
├── embedded-comments
│ ├── blog-comments.ts
│ ├── comments-count.ts
│ ├── debiki-utterscroll-iframe-parent.js
│ ├── embedding-page.d.ts
│ ├── fetch.ts
│ ├── parent-footer.js
│ ├── parent-header.js
│ ├── readme.txt
│ └── tsconfig.json
├── ext-iframe.js
├── macros
│ ├── macros-dev.h
│ ├── macros-none.h
│ ├── macros-prod.h
│ ├── macros.d.ts
│ └── macros.ts
├── reactjs-types.ts
├── rtl
│ ├── bootstrap.styl
│ ├── react-select.styl
│ ├── react-textarea-autocomplete.styl
│ ├── right-to-left-mixins.styl
│ └── right-to-left-props.styl
├── server
│ ├── ReactActions.ts
│ ├── ReactStore.ts
│ ├── Server.ts
│ ├── ServerApi.ts
│ ├── avatar
│ │ ├── AvatarAndName.ts
│ │ └── avatar.ts
│ ├── constants.ts
│ ├── edit-history
│ │ └── edit-history-dialog.ts
│ ├── editor-bundle-not-yet-loaded.ts
│ ├── editor
│ │ ├── CdnLinkifyer.ts
│ │ ├── link-previews-markdown-it-plugin.editor.ts
│ │ ├── mentions-markdown-it-plugin.ts
│ │ └── title-editor.ts
│ ├── forum
│ │ ├── edit-intro-dialog.ts
│ │ └── forum.ts
│ ├── help
│ │ ├── help.ts
│ │ └── serverAnnouncements.ts
│ ├── links.ts
│ ├── login
│ │ ├── login-dialog.ts
│ │ ├── login-if-needed.ts
│ │ └── login.ts
│ ├── magic-time.ts
│ ├── me-getters.ts
│ ├── model.ts
│ ├── more-bundle-not-yet-loaded.ts
│ ├── notification
│ │ ├── Notification.ts
│ │ └── notf-prefs-button.ts
│ ├── oop-methods.ts
│ ├── page-dialogs
│ │ ├── delete-post-dialog.ts
│ │ ├── flag-dialog.ts
│ │ ├── move-posts-dialog.ts
│ │ ├── open-share-popup.ts
│ │ ├── see-wrench-dialog.ts
│ │ ├── share-dialog.ts
│ │ ├── tags-dialog.ts
│ │ └── wikify-dialog.ts
│ ├── page-methods.ts
│ ├── page-tools
│ │ └── page-tools.ts
│ ├── page
│ │ ├── arrows.ts
│ │ ├── cats-or-home-link.ts
│ │ ├── chat.ts
│ │ ├── discussion.ts
│ │ ├── hacks.ts
│ │ ├── metabar.ts
│ │ ├── page.ts
│ │ ├── post-actions.ts
│ │ ├── scroll-buttons.ts
│ │ └── social-buttons.ts
│ ├── personas
│ │ └── PersonaIndicator.ts
│ ├── prelude.ts
│ ├── react-bootstrap-old
│ │ └── Input.more.ts
│ ├── react-elements
│ │ └── name-login-btns.ts
│ ├── readme.txt
│ ├── rules.ts
│ ├── server-side-type-stubs.ts
│ ├── server-vars.ts
│ ├── staff-bundle-not-yet-loaded.ts
│ ├── store-getters.ts
│ ├── tags
│ │ └── tags.ts
│ ├── topbar
│ │ └── topbar.ts
│ ├── translations.d.ts
│ ├── tsconfig.json
│ ├── util
│ │ └── ExplainingDropdown.ts
│ ├── utils
│ │ ├── DropdownModal.ts
│ │ ├── page-scroll-mixin.ts
│ │ ├── react-utils.ts
│ │ ├── scroll-into-view.ts
│ │ ├── show-and-highlight.ts
│ │ ├── utils.ts
│ │ └── window-zoom-resize-mixin.ts
│ ├── widgets.ts
│ └── widgets
│ │ └── widget-open-buttons.ts
├── serviceworker
│ ├── constants.ts
│ ├── magic-time.ts
│ ├── model.ts
│ ├── service-worker.ts
│ └── tsconfig.json
├── third-party
│ ├── abbreviate-jquery.js
│ ├── bliss.shy.js
│ ├── codemirror-show-markdown-line-breaks.css
│ ├── codemirror-show-markdown-line-breaks.js
│ ├── diff_match_patch.js
│ ├── get-set-cookie.js
│ ├── gifffer
│ │ ├── LICENSE
│ │ ├── README.md
│ │ └── gifffer.js
│ ├── html-css-sanitizer-bundle.js
│ ├── jquery-scrollable.js
│ ├── jquery.browser.js
│ ├── lodash-custom.js
│ ├── non-angular-slugify.js
│ ├── popuplib.js
│ ├── popuplib.js.debiki-readme.txt
│ ├── rename-key-to-keymaster.js
│ ├── smoothscroll-tiny.js
│ ├── stupid-lightbox.css
│ ├── third-party-types.d.ts
│ └── tiny-querystring.umd.js
└── types-and-const-enums.ts
├── conf
├── app-dev.conf
├── app-prod.conf
├── logback-prod.xml
├── logback.xml
├── rdb
│ └── postgresql.conf
└── routes
├── d
├── c
├── kill-down-prod-test
├── n
├── node
├── selenium
└── tykc
├── decisions.adoc
├── docker-compose-no-limits.yml
├── docker-compose.it.yml
├── docker-compose.yml
├── docs
├── CLA-history.md
├── CLA-v1.txt
├── CLA-v2.txt
├── abbreviations.txt
├── about-the-talkyard-images.md
├── anti-bugs.txt
├── api
│ └── openapi-TySeV0Search-test.json
├── building-images.md
├── coding-style.adoc
├── db-queries.txt
├── db-schema
│ ├── README.txt
│ ├── alt_page_ids3.txt
│ ├── api_secrets3.txt
│ ├── audit_log3.txt
│ ├── backup_test_log3.txt
│ ├── blocks3.txt
│ ├── categories3.txt
│ ├── domains-no-comments.txt
│ ├── domains.txt
│ ├── drafts3.txt
│ ├── emails_out3.txt
│ ├── flyway_schema_history.txt
│ ├── group_participants3.txt
│ ├── guest_prefs3.txt
│ ├── hosts3.txt
│ ├── identities3.txt
│ ├── idps_t.txt
│ ├── invites3.txt
│ ├── job_queue_t.txt
│ ├── link_previews_t.txt
│ ├── links_t.txt
│ ├── notices_t.txt
│ ├── notifications3.txt
│ ├── page_html_cache_t.txt
│ ├── page_notf_prefs_t.txt
│ ├── page_paths3.txt
│ ├── page_popularity_scores3.txt
│ ├── page_users3.txt
│ ├── pages3.txt
│ ├── perms_on_pages3.txt
│ ├── post_actions3.txt
│ ├── post_read_stats3.txt
│ ├── post_revisions3.txt
│ ├── post_tags3.txt
│ ├── posts3.txt
│ ├── review_tasks3.txt
│ ├── sessions_t.txt
│ ├── settings3.txt
│ ├── sites3.txt
│ ├── spam_check_queue3.txt
│ ├── system_settings_t.txt
│ ├── tag_notf_levels3.txt
│ ├── tags_t.txt
│ ├── tagtypes_t.txt
│ ├── upload_refs3.txt
│ ├── uploads3.txt
│ ├── user_emails3.txt
│ ├── user_stats3.txt
│ ├── user_visit_stats3.txt
│ ├── usernames3.txt
│ ├── users3.txt
│ ├── webhook_reqs_out_t.txt
│ └── webhooks_t.txt
├── debugging-ios-safari-without-iphone.md
├── design-docs
│ ├── bookmarks.dd.adoc
│ └── tags.dd.adoc
├── developing-talkyard.md
├── docs-to-write.txt
├── e2e-tests-readme.md
├── everything-is-a-node.txt
├── intro-to-docker-compose.md
├── maybe-do-later.txt
├── maybe-refactor.txt
├── naming-notes.md
├── old
│ └── css-docs.txt
├── safari-itp-firefox-etp.md
├── security-tests-readme.md
├── starting-talkyard.md
├── talkyard-api.md
├── testing-images-in-vagrant.md
├── tests-map.txt
├── things-in-talkyard.md
├── tips.md
├── ty-security.adoc
├── tyworld.adoc
├── ux-design.adoc
└── wildcard-dot-localhost.md
├── gulpfile.js
├── images
├── app
│ ├── Dockerfile.dev
│ ├── Dockerfile.prod
│ ├── assets
│ │ └── .gitkeep
│ ├── entrypoint.dev.sh
│ └── fakemail-publ-test-self-signed.crt
├── backup
│ └── entrypoint.sh
├── cache
│ └── Dockerfile
├── certgen
│ └── Dockerfile
├── fakemail
│ ├── README.md
│ ├── fakemail-publ-test-self-signed.crt
│ ├── fakemail-publ-test-self-signed.key
│ └── mailslurper-config.json
├── fakeweb
│ ├── Dockerfile
│ ├── app
│ │ ├── deps.ts
│ │ └── main.ts
│ └── docker
│ │ ├── LICENSE
│ │ └── docker-entrypoint.sh
├── gulp
│ ├── Dockerfile
│ └── entrypoint.sh
├── keycloak
│ ├── Dockerfile
│ └── docker-compose-keycloak.yml
├── rdb
│ ├── Dockerfile
│ ├── chown-logs-then-exec-entrypoint.sh
│ └── docker-entrypoint-initdb.d
│ │ └── init.sh
├── search
│ ├── Dockerfile
│ ├── elasticsearch.yml
│ ├── entrypoint.sh
│ ├── jvm.options
│ └── log4j2.properties
└── web
│ ├── README.adoc
│ ├── assets
│ └── .gitkeep
│ ├── fonts
│ └── .gitkeep
│ ├── gen-def-cert-letsencrypt-key.sh
│ ├── html
│ ├── 403-upload-not-found.html
│ ├── 404.html
│ ├── 413.html
│ ├── 502.html
│ ├── 503.html
│ ├── 504.html
│ ├── robots.txt
│ ├── security.txt
│ └── session-iframe.html
│ ├── http-limits.conf
│ ├── http-redirect-to-https.conf
│ ├── nginx.conf
│ ├── old
│ ├── Dockerfile-openresty-1.19.3.1-0-alpine-official
│ ├── Dockerfile-openresty-1.19.9.1-alpine-3.14-official
│ ├── Dockerfile.buster-apt-get-old
│ ├── Dockerfile.nginx-old
│ └── old-nginx-config-snippets.conf
│ ├── openresty.Dockerfile
│ ├── package.json
│ ├── run-envsubst-gen-keys.sh
│ ├── server-limits.conf
│ ├── server-listen.conf
│ ├── server-location-cdn.conf
│ ├── server-locations.conf
│ ├── server-ssl.conf
│ ├── sites-enabled-manual
│ └── default-server.conf
│ ├── ssl-cert-snakeoil.key
│ ├── ssl-cert-snakeoil.pem
│ ├── ty-lua
│ ├── access-by-lua-file.lua
│ ├── init-by-lua-file.lua
│ ├── init-worker-by-lua-file.lua
│ ├── log-by-lua-file.lua
│ ├── lua-limit-bandwidth
│ │ ├── access-phase.lua
│ │ ├── log-phase.lua
│ │ ├── readme.md
│ │ └── util.lua
│ └── lua-limit-uploads
│ │ └── limit-uploads.lua
│ └── yarn.lock
├── lock.sbt
├── modules
├── ed-prod-one-test-override.yml
└── paseto-cmd
│ ├── .gitignore
│ ├── Cargo.lock
│ ├── Cargo.toml
│ ├── README.txt
│ └── src
│ └── main.rs
├── nix
├── sources.json
└── sources.nix
├── old
├── PinController.scala
├── db-skip.sql
├── done.txt
└── perhaps.txt
├── package.json
├── project
├── Dependencies.scala
├── build.properties
└── plugins.sbt
├── s
├── _tyd-completion-bash.sh
├── build-prod-images.sh
├── bump-versions.sh
├── d
├── d-cli
├── d-debug-security-tests
├── d-down
├── d-gulp
├── d-killcli
├── d-killdown
├── d-logs
├── d-logsf0
├── d-psql
├── d-restart
├── d-restart-web-app
├── d-run-security-tests
├── d-start-ed-prod-one-test
├── d-stats
├── d-up-d-logsf0
├── delete-container-logs.sh
├── diff-ty-dirs.sh
├── drop-database-create-empty.sh
├── drop-database-import-latest.sh
├── gen-big-file-if-not-exists.sh
├── git-delete-branch-here-and-origin.sh
├── git-delete-tag-here-and-origin.sh
├── git-diff-patches.sh
├── git-merge-into-release-branch.sh
├── git-range-stats.sh
├── git-show-changed-files.sh
├── git-show-tags-by-date.sh
├── impl
│ ├── build-prod-app-image.sh
│ ├── build-prod-images.sh
│ ├── tyd-e2e-tests.ts
│ ├── tyd-util.ts
│ └── unjson.sh
├── kill-wdio
├── old
│ ├── run-all-tests.sh
│ ├── run-embedded-comments-tests.sh
│ ├── run-test-suite.sh
│ └── timeout.sh
├── promote-version.sh
├── rerun-failed-e2e.sh
├── run-e2e-tests.sh
├── selenium-config.js
├── selenium-install
├── selenium-start
├── selenium-start-invisible
├── start-prod-images.sh
├── tsconfig.json
├── tyd
├── tyd.js
├── tyd.ts
├── wdio
├── wdio-7
├── wdio-debug-9101
└── yarn
├── shell.nix
├── tests
├── api
│ ├── jest-concise-console.ts
│ ├── jest.config.ts
│ ├── server.ts
│ └── tests
│ │ └── some.test.ts
├── app
│ ├── controllers
│ │ ├── EmbeddedTopicsControllerSpec.scala
│ │ ├── LoginWithSecretControllerSpec.scala
│ │ └── UtilsSpec.scala
│ ├── debiki
│ │ ├── RateLimiterSpec.scala
│ │ ├── SettingsSpec.scala
│ │ ├── SiteCreatorSpec.scala
│ │ ├── TextAndHtmlTest.scala
│ │ └── dao
│ │ │ ├── AnonymAppSpec.scala
│ │ │ ├── CategoriesDaoAppSpec.scala
│ │ │ ├── CreateSiteDaoAppSpec.scala
│ │ │ ├── DaoAppSuite.scala
│ │ │ ├── DeletePageAppSpec.scala
│ │ │ ├── DraftsDaoAppSpec.scala
│ │ │ ├── FirstPostsAppSpec.scala
│ │ │ ├── MaxLimitsDaoAppSpec.scala
│ │ │ ├── MessagesDaoAppSpec.scala
│ │ │ ├── MovePostsAppSpec.scala
│ │ │ ├── PageNotfPrefTxSpec.scala
│ │ │ ├── PromotionToFullMemberAppSpec.scala
│ │ │ ├── ReviewStuffAppSuite.scala
│ │ │ ├── ReviewTasksAppSpec.scala
│ │ │ ├── TagsAppSpec.scala
│ │ │ ├── TestSiteAndDao.scala
│ │ │ ├── ThreatLevelsAppSpec.scala
│ │ │ ├── UploadsDaoSpec.scala
│ │ │ ├── UserStatsAppSpec.scala
│ │ │ └── __DaoAppSpecTemplate__.scala
│ ├── resources
│ │ └── embedding-pages
│ │ │ ├── .gitignore
│ │ │ ├── embeds-localhost-topic-id-1001-jquery-1.7-and-modernizr-2.5-pre-loaded.html
│ │ │ ├── embeds-localhost-topic-id-1001-jquery-2.1-and-modernizr-2.7-pre-loaded.html
│ │ │ ├── embeds-localhost-topic-id-1001-jquery-2.1-pre-loaded.html
│ │ │ ├── embeds-localhost-topic-id-1001-modernizr-2.7-pre-loaded.html
│ │ │ ├── embeds-localhost-topic-id-1001.html
│ │ │ ├── embeds-localhost-topic-id-1002.html
│ │ │ ├── embeds-site-1-topic-id-empty.html
│ │ │ ├── embeds-site-11-topic-id-empty.html
│ │ │ ├── embeds-site-12-topic-id-empty.html
│ │ │ ├── embeds-site-13-topic-id-empty.html
│ │ │ ├── embeds-site-14-topic-id-empty.html
│ │ │ ├── embeds-site-15-topic-id-empty.html
│ │ │ ├── readme.txt
│ │ │ ├── static-page-at-10.0.2.2.html
│ │ │ ├── static-page-no-id-2.html
│ │ │ ├── static-page-no-id-3.html
│ │ │ ├── static-page-no-id-4.html
│ │ │ ├── static-page-no-id-5.html
│ │ │ ├── static-page-no-id-6.html
│ │ │ ├── static-page-no-id-7.html
│ │ │ ├── static-page-no-id-8.html
│ │ │ ├── static-page-no-id-9.html
│ │ │ ├── static-page-no-id.html
│ │ │ ├── static-page-with-jquery-and-modernizr.html
│ │ │ └── static-page.html
│ ├── server
│ │ └── talkyard
│ │ │ └── server
│ │ │ ├── events
│ │ │ └── WebhooksSiteDaoMixinSpec.scala
│ │ │ └── search
│ │ │ └── SearchQueryParserSpec.scala
│ ├── talkyard
│ │ └── server
│ │ │ ├── GlobalConfigSpec.scala
│ │ │ ├── authn
│ │ │ ├── AuthOidcAppSpec.scala
│ │ │ ├── LoginAppSpec.scala
│ │ │ └── SignupAppSpec.scala
│ │ │ ├── dao
│ │ │ ├── LoadWhomToSendSummariesToAppSpec.scala
│ │ │ ├── SiteTransactionAppSpec.scala
│ │ │ ├── SiteTxLoadParticipantsAppSpec.scala
│ │ │ ├── SiteTxNoticesAppSpec.scala
│ │ │ └── SiteTxPermissionsAppSpec.scala
│ │ │ ├── events
│ │ │ └── WebhooksAppSpec.scala
│ │ │ ├── linkpreviews
│ │ │ ├── LinkPreviewMatchersSpec.scala
│ │ │ └── LinkPreviewRendererSpec.scala
│ │ │ ├── links
│ │ │ └── LinksAppSpec.scala
│ │ │ ├── notf
│ │ │ ├── NotfsAppMentionsSpec.scala
│ │ │ └── NotfsAppPageNotfsSpec.scala
│ │ │ ├── security
│ │ │ └── ReservedNamesTest.scala
│ │ │ ├── sitepatch
│ │ │ ├── DumpMaker.scala
│ │ │ ├── SitePatcherAppSpec.scala
│ │ │ └── TwoPeopleChatSpecTrait.scala
│ │ │ └── summaryemails
│ │ │ └── SummaryEmailsAppSpec.scala
│ └── test
│ │ └── tags
│ │ └── SlowTest.java
├── e2e-wdio7
│ ├── modules
│ ├── package.json
│ ├── pageobjects
│ │ ├── login.page.ts
│ │ ├── page.ts
│ │ └── secure.page.ts
│ ├── pub-api.ts
│ ├── specs
│ │ ├── __e2e-test-template.2br.ec.e2e__.ts
│ │ ├── __e2e-test-template.2br.f.e2e__.ts
│ │ ├── alias-anons-approve-review.2br.f.e2e.ts
│ │ ├── alias-anons-basic-perm.2br.f.e2e.ts
│ │ ├── alias-anons-basic-temp.2br.f.e2e.ts
│ │ ├── alias-anons-edit-alter.2br.f.e2e.ts
│ │ ├── alias-anons-true-mixed.2br.f.e2e.ts
│ │ ├── api-get-query-for-pats.2br.e2e.ts
│ │ ├── api-list-query-for-topics-popular-first.1br.f.e2e.ts
│ │ ├── api-search-ext-site-and-server.2br.cors.e2e.ts
│ │ ├── api-search-full-text.1br.f.e2e.ts
│ │ ├── api-upsert-posts.2br.d.e2e.ts
│ │ ├── assign-can-see.2br.d.e2e.ts
│ │ ├── assign-to-basic.2br.d.e2e.ts
│ │ ├── assign-to-notfs.2br.d.e2e.ts
│ │ ├── backlinks-basic.2br.d.e2e.ts
│ │ ├── badges-basic.2br.e2e.ts
│ │ ├── block-dir-msgs.2br.d.e2e.ts
│ │ ├── block-mentions.2br.d.e2e.ts
│ │ ├── cannot-reply-via-email.2br.e2e.ts
│ │ ├── categories-basic.3br.d.e2e.ts
│ │ ├── category-perms.2br.d.e2e.ts
│ │ ├── cats-perf-many.2br.d.e2e.ts
│ │ ├── chat-basic.2br.f.mtime.e2e.ts
│ │ ├── chat-scroll.2br.f.e2e.ts
│ │ ├── comment-sort-order-inherited.d.2br.e2e.ts
│ │ ├── comment-sort-order.d.2br.e2e.ts
│ │ ├── comment-sort-order.util.ts
│ │ ├── create-private-site-gmail-invite-only.2br.f.e2e.ts
│ │ ├── create-private-site-password.2br.f.e2e.ts
│ │ ├── create-site-admin-guide.2br.d.e2e.ts
│ │ ├── create-site-facebook.1br.d.extidp.e2e.ts
│ │ ├── create-site-github-uppercase-email.1br.d.extidp.e2e.ts
│ │ ├── create-site-gmail-and-email-notf.1br.d.extidp.e2e.ts
│ │ ├── create-site-linkedin.1br.d.extidp.e2e.ts
│ │ ├── create-site-password-run-admin-intro-tours.1br.d.e2e.ts
│ │ ├── custom-forms.3br.d.e2e.ts
│ │ ├── d.oidc-azure-impl.ts
│ │ ├── d.oidc-azure-login-required.2br.extidp.e2e.ts
│ │ ├── d.oidc-azure-pub-site.2br.extidp.e2e.ts
│ │ ├── d.sessions-logout-elsewhere.4br.e2e.ts
│ │ ├── d.sessions-staff-logout-others.4br.e2e.ts
│ │ ├── dir.create-site-imp-json.2br.e2e.ts
│ │ ├── dir.create-site-via-api.2br.e2e.ts
│ │ ├── dir.manual.2br.e2e.ts
│ │ ├── dir.summarize-squash-siblings.2br.e2e.ts
│ │ ├── direct-messages-notfs.3br.d.e2e.ts
│ │ ├── do-api-create-pages-comts-check-webhooks-search.2br.e2e.ts
│ │ ├── do-api-like-and-subscribe.2br.e2e.ts
│ │ ├── do-api-upvote-ideas-sort-by-votes.2br.d.e2e.ts
│ │ ├── editor-toolbar-preview.1br.e2e.ts
│ │ ├── embcom.comment-counts.2br.ec.cors.e2e.ts
│ │ ├── embcom.create-site-req-verif-email-exit-tours.2br.e2e.ts
│ │ ├── embcom.create-site-via-api.2br.e2e.ts
│ │ ├── embcom.dont-load-script-twice.1br.ec.e2e.ts
│ │ ├── embcom.drafts-previews-not-logged-in.2br.e2e.ts
│ │ ├── embcom.expimpjson.create-site-exp-json.2br.e2e.ts
│ │ ├── embcom.expimpjson.imp-to-existing-site.2br.e2e-UNIMPL.ts
│ │ ├── embcom.expimpjson.imp-to-new-site.2br.e2e.ts
│ │ ├── embcom.expimpjson.import-tests-impl.ts
│ │ ├── embcom.expimpjson.restore-overwrite-site-new-domain.2br.e2e.ts
│ │ ├── embcom.expimpjson.restore-overwrite-site-same-domain.2br.e2e.ts
│ │ ├── embcom.expimpjson.test-data.ts
│ │ ├── embcom.ignore-query-params.2br.e2e.ts
│ │ ├── embcom.log-levels-on-loaded.1br.ec.e2e.ts
│ │ ├── embcom.manual.2br.e2e.ts
│ │ ├── embcom.manyframes.basic.2br.e2e.ts
│ │ ├── embcom.manyframes.comment-counts.2br.cors.e2e.ts
│ │ ├── embcom.manyframes.drafts-repl-to.2br.e2e.ts
│ │ ├── embcom.manyframes.js-api.2br.ec.e2e.ts
│ │ ├── embcom.manyframes.js-api.impl.ts
│ │ ├── embcom.manyframes.js-api.sso.2br.ec.e2e.ts
│ │ ├── embcom.manyframes.manual.2br.e2e.ts
│ │ ├── embcom.reply-vote-report-bef-login.2br.e2e.ts
│ │ ├── embcom.scroll-and-load-more.2br.ec.e2e.ts
│ │ ├── embcom.sessions-emb-sess-cannot-moderate.3br.e2e.ts
│ │ ├── embcom.sort-order-op-likes-btn-txt.2br.ec.e2e.ts
│ │ ├── embcom.sso.redir-page.2br.ec.e2e.ts
│ │ ├── embcom.sso.token-direct-w-logout-url.2br.ec.e2e.ts
│ │ ├── embcom.sso.token-in-cookie.2br.ec.e2e.ts
│ │ ├── embcom.sso.token-in-cookie.2br.test.ts--e2e-crypto-probl.txt
│ │ ├── embcom.vote-bef-page-exists.1br.e2e.ts
│ │ ├── embforum.b3c.login.2br.ef.e2e.ts
│ │ ├── embforum.b3c.sso-login.2br.ef.e2e.ts
│ │ ├── forum-sort-and-scroll.d.2br.e2e.ts
│ │ ├── frag-action-compose-topic.2br.f.wip.ts
│ │ ├── ghost.embcom.comments-basic.2br.e2e.ts
│ │ ├── hide-unhide-tips.2br.f.e2e.ts
│ │ ├── link-previews-all-others.1br.d.extln.e2e.ts
│ │ ├── link-previews-http-to-https.1br.d.e2e.ts
│ │ ├── link-previews-images-mp4-youtube.1br.d.extln.e2e.ts
│ │ ├── link-previews-internal-may-see.2br.d.e2e.ts
│ │ ├── link-previews-internal-not-see-cat.2br.d.e2e.ts
│ │ ├── link-previews-internal-to-cats-not-see.2br.f.e2e.ts
│ │ ├── link-previews-twitter-max-editor.1br.d.extln.e2e.ts
│ │ ├── load-test-100-pages-60-users.2br.e2e.ts
│ │ ├── load-test-site-builder.ts
│ │ ├── may-see-email-adrs.2br.d.e2e.ts
│ │ ├── modn-ban-from-disc-page.2br.f.e2e.ts
│ │ ├── modn-ban-spammer.2br.f.e2e.ts
│ │ ├── modn-from-disc-page-appr-befr.2br.f.e2e.ts
│ │ ├── move-posts-newer-page-reply.2br.d.e2e.ts
│ │ ├── move-posts-other-page.2br.d.e2e.ts
│ │ ├── move-posts-pin-delete.2br.d.e2e.ts
│ │ ├── move-posts-same-page.2br.d.e2e.ts
│ │ ├── notfs-mark-seen-as-seen.d.2br.e2e.ts
│ │ ├── notfs-prefs-inherit-group.d.2br.e2e.ts
│ │ ├── notfs-prefs-inherit-own.d.2br.e2e.ts
│ │ ├── page-type-discussion-progress.1br.d.e2e.ts
│ │ ├── page-type-idea-statuses-comments.2br.d.e2e.ts
│ │ ├── page-type-info-page.1br.d.e2e.ts
│ │ ├── page-type-problem-statuses.2br.d.e2e.ts
│ │ ├── page-type-question-closed.2br.d.e2e.ts
│ │ ├── password-login-reset.2br.f.e2e.ts
│ │ ├── perms-see-own.2br.f.e2e.ts
│ │ ├── plan-maintenance.2br.d.e2e.ts
│ │ ├── privacy-list-activity.2br.f.e2e.ts
│ │ ├── privacy-may-see.3br.f.e2e.ts
│ │ ├── private-chat.3br.d.e2e.ts
│ │ ├── reindex-sites.2br.f.e2e.ts
│ │ ├── search-tag-vals-priv-cats.2br.f.e2e.ts
│ │ ├── settings-toggle-login-required.3br.d.e2e.ts
│ │ ├── show-admin-notices.2br.e2e.ts
│ │ ├── site-api-secrets-not-global.2br.f.e2e.ts
│ │ ├── tags-badges-not-missing.2br.e2e.ts
│ │ ├── tags-basic.2br.e2e.ts
│ │ ├── topic-prominent-pats-basic.2br.d.e2e.ts
│ │ ├── topic-prominent-pats-reply-approve.2br.d.e2e.ts
│ │ ├── user-self-delete-upd-groups.2br.f.e2e.ts
│ │ ├── votes-and-best-first.d.2br.e2e.ts
│ │ ├── webhooks-basic.2br.e2e.ts
│ │ ├── webhooks-enable-disable.2br.e2e.ts
│ │ ├── webhooks-for-api-upserts.2br.e2e.ts
│ │ ├── webhooks-retry-impl.ts
│ │ └── webhooks-retry.2br.e2e.ts
│ ├── target
│ ├── test-constants.ts
│ ├── test-types.ts
│ ├── test-types2.ts
│ ├── tsconfig.json
│ ├── utils
│ │ ├── do-api-actions.ts
│ │ ├── emails-e2e.ts
│ │ ├── ext-cors-site.html
│ │ ├── fakeweb.ts
│ │ ├── log-and-die.ts
│ │ ├── make.ts
│ │ ├── server.ts
│ │ ├── settings-exp-def.ts
│ │ ├── settings.ts
│ │ ├── site-builder.ts
│ │ ├── ty-assert.ts
│ │ ├── ty-e2e-post.ts
│ │ ├── ty-e2e-test-browser.ts
│ │ └── utils.ts
│ ├── wdio-progress-reporter.ts
│ ├── wdio.conf.autogen-webdriver-7.ts
│ ├── wdio.conf.ts
│ └── yarn.lock
├── e2e
│ ├── find-and-run-wdio.sh
│ ├── package.json
│ ├── pub-api.ts
│ ├── readme.md
│ ├── specs
│ │ ├── __e2e-test-template__.2br.test.ts
│ │ ├── admin-move-hostname.2browsers.test.ts
│ │ ├── admin-review-cascade-approval.2br.mtime.test.ts
│ │ ├── admin-review-invalidate-for-reply.2br.mtime.test.ts
│ │ ├── admin-review-invalidate-page-deld.2br.mtime.test.ts
│ │ ├── admin-user-approve-reject.2browsers.test.ts
│ │ ├── admin-user-staff.2browsers.test.ts
│ │ ├── admin-user-suspend.2browsers.test.ts
│ │ ├── admin-user-threat-mild.2br.mtime.test.ts
│ │ ├── admin-user-threat-moderate.2br.mtime.test.ts
│ │ ├── all-links.test.ts
│ │ ├── api-list-query-for-posts.test.ts
│ │ ├── api-list-query-for-topics-recent-etc-first.test.ts
│ │ ├── api-private-chat-two-pps-impl.test.ts
│ │ ├── api-private-chat-two-pps-list-use-usernames.2browsers.test.ts
│ │ ├── api-private-chat-two-pps-sso-extid.2browsers.test.ts
│ │ ├── api-update-user-and-sso-user.2br.test.ts
│ │ ├── api-upsert-categories.2browsers.test.ts
│ │ ├── api-upsert-page-notfs.2browsers.test.ts
│ │ ├── api-upsert-pages.2browsers.test.ts
│ │ ├── api-w-sso-upsert-pages.2browsers.test.ts
│ │ ├── authz-basic-see-reply-create.test.ts
│ │ ├── authz-view-as-stranger.test.ts
│ │ ├── categories-delete.2br.test.ts
│ │ ├── chat-create-from-direct-message.2browsers.test.ts
│ │ ├── chat-create-from-profile-pages.2browsers.test.ts
│ │ ├── delete-pages.2br.test.ts
│ │ ├── direct-messages-delete.2browsers.test.ts
│ │ ├── drafts-chat-adv-ed.2browsers.test.ts
│ │ ├── drafts-delete.test.ts
│ │ ├── drafts-new-topic-from-cats-page.test.ts
│ │ ├── drafts-new-topic.2br.mtime.test.ts
│ │ ├── drafts-reply-edit-dir-msg.2br.mtime.test.ts
│ │ ├── embcom.all-idp-logins-old-name.1br.extidp.test.ts
│ │ ├── embcom.all-idp-logins.1br.extidp.test.ts
│ │ ├── embcom.b3c.guest.1br.test.ts
│ │ ├── embcom.b3c.unverif-gmail.1br.extidp.test.ts
│ │ ├── embcom.b3c.verif-email.1br.test.ts
│ │ ├── embcom.b3c.verif-gmail.1br.extidp.test.ts
│ │ ├── embcom.manua.2br.test.ts
│ │ ├── embedded-comments-cat-refs-and-disc-ids.2browsers.test.ts
│ │ ├── embedded-comments-category-refs.2browsers.test.ts
│ │ ├── embedded-comments-conf-notf-pref-first.test.ts
│ │ ├── embedded-comments-create-site-forum-intro-tour.test.ts
│ │ ├── embedded-comments-create-site-import-disqus.2br.test.ts
│ │ ├── embedded-comments-create-site-no-verif-email-admin-area-tour.2browsers.test.ts
│ │ ├── embedded-comments-different-disc-ids-same-page.test.ts
│ │ ├── embedded-comments-discussion-id-old-name.test.ts
│ │ ├── embedded-comments-discussion-id.test.ts
│ │ ├── embedded-comments-edit-and-vote-old-name.test.ts
│ │ ├── embedded-comments-edit-and-vote.test.ts
│ │ ├── embedded-comments-gatsby.test.ts
│ │ ├── embedded-comments-guest-login-email-notf-unsbscribe.test.ts
│ │ ├── embedded-comments-navigation-as-guest.test.ts
│ │ ├── embedded-comments-scroll-embedding-page.test.ts
│ │ ├── embedded-comments-short-script-cache-time.test.ts
│ │ ├── embedded-comments-uploads-origin.test.ts
│ │ ├── flag-guest-block-agree.2browsers.test.ts
│ │ ├── flag-member-block-agree.2browsers.test.ts
│ │ ├── forum-drafts-not-logged-in.2browsers.test.ts
│ │ ├── gmail-fb-join-login.extidp.1br.test.ts
│ │ ├── group-mentions-built-in-groups.2browsers.test.ts
│ │ ├── group-mentions-custom-groups.2browsers.test.ts
│ │ ├── group-permissions-similar-topics.2br.mtime.test.ts
│ │ ├── group-profile-change-things.2browsers.test.ts
│ │ ├── imp-exp-imp-exp-site.test.ts
│ │ ├── impersonate-post-as-other.2browsers.test.ts
│ │ ├── impersonate-restricted-areas.test.ts
│ │ ├── invite-to-groups.2browsers.test.ts
│ │ ├── invites-by-adm-click-email-set-pwd-link.2browsers.test.ts
│ │ ├── invites-by-core-try-login-after.2browsers.test.ts
│ │ ├── invites-by-mod-try-signup-after.2browsers.test.ts
│ │ ├── invites-many-retry.2browsers.test.ts
│ │ ├── invites-too-many.2browsers.test.ts
│ │ ├── invites-weird-email-addrs.2browsers.test.ts
│ │ ├── login-expire-idle-after.2br.mtime.test.ts
│ │ ├── login-required-ext-signup-login.1br.extidp.test.ts
│ │ ├── login-required-join-global-chat.2br.test.ts
│ │ ├── manual.2browsers.test.ts
│ │ ├── many-users-mention-list-join-group.2browsers.test.ts
│ │ ├── mod-review.2br.mtime.test.ts
│ │ ├── modn-appr-bef-comb-w-revw-aftr.2br.mtime.test.ts
│ │ ├── modn-approve-before.2br.mtime.test.ts
│ │ ├── modn-from-disc-page-review-after.2browsers.test.ts
│ │ ├── modn-review-after.2br.mtime.test.ts
│ │ ├── navigation-as-admin.test.ts
│ │ ├── navigation-as-impl.ts
│ │ ├── navigation-as-member.test.ts
│ │ ├── navigation-as-stranger.test.ts
│ │ ├── new-member-allow-approve.2br.mtime.test.ts
│ │ ├── new-user-review-ok.2br.mtime.test.ts
│ │ ├── notf-emails-discussion.2br.mtime.test.ts
│ │ ├── notf-override-group-prefs.2browsers.test.ts
│ │ ├── notf-page-cats-site-UNIMPL.2browsers.test.ts
│ │ ├── notf-prefs-custom-groups.2browsers.test.ts
│ │ ├── notf-prefs-pages-replied-to.2br.test.ts
│ │ ├── notf-prefs-private-groups.2browsers.test.ts
│ │ ├── notfs-like-votes.2browsers.test.ts
│ │ ├── notfs-mark-all-as-read.2browsers.test.ts
│ │ ├── notfs-page-gone.2browsers.test.ts
│ │ ├── notfs-snooze-talk.2br.mtime.test.ts
│ │ ├── permissions-edit-wiki-posts.2browsers.test.ts
│ │ ├── promote-demote-by-staff-join-leave-chats.2br.test.ts
│ │ ├── review-edits-ninja-late.2br.mtime.test.ts
│ │ ├── sanitize-posts.2browsers.test.ts
│ │ ├── search-private-chat.2browsers.test.ts
│ │ ├── search-public-basic.2browsers.test.ts
│ │ ├── settings-allow-local-signup-UNIMPL.test.ts
│ │ ├── settings-allow-signup-UNIMPL.test.ts
│ │ ├── settings-allowed-email-domains.extidp.2br.test.ts
│ │ ├── settings-approve-members.2browsers.test.ts
│ │ ├── slow-3g-navigate-edit-drafts.2browsers.test.ts
│ │ ├── spam-basic-akismet-blocked.2br.mtime.test.ts
│ │ ├── spam-basic-akismet-false-negatives.2br.mtime.test.ts
│ │ ├── spam-basic-akismet-false-positives.2br.mtime.test.ts
│ │ ├── spam-basic-local-ip-links-unblock.2br.mtime.test.ts
│ │ ├── spam-basic-local.2browsers.test.ts
│ │ ├── spam-basic-safe-browsing-api-blocked.2br.mtime.test.ts
│ │ ├── sso-access-denied-login.2browsers.test.ts
│ │ ├── sso-admin-extra-login.test.ts
│ │ ├── sso-all-ways-to-login.2browsers.test.ts
│ │ ├── sso-approval-required.UNIMPL.2browsers.test.ts
│ │ ├── sso-login-and-approval-required.UNIMPL.2browsers.test.ts
│ │ ├── sso-login-member-impl.2browsers.test.ts
│ │ ├── sso-login-member.2browsers.test.ts
│ │ ├── sso-login-new-members.2browsers.test.ts
│ │ ├── sso-login-required-w-logout-url.2browsers.test.ts
│ │ ├── sso-login-required.2browsers.test.ts
│ │ ├── sso-one-time-key-errors.2browsers.test.ts
│ │ ├── sso-test.2browsers.test.ts
│ │ ├── sso.logout-url.2br.test.ts
│ │ ├── summary-emails.2br.mtime.test.ts
│ │ ├── unsubscribe.2browsers.test.ts
│ │ ├── upload-images-and-files.2br.test.ts
│ │ ├── user-profile-access.test.ts
│ │ ├── user-profile-cannot-delete-idp-email.1br.extidp.test.ts
│ │ ├── user-profile-change-email.2browsers.test.ts
│ │ ├── user-profile-change-password.2br.mtime.test.ts
│ │ ├── user-profile-change-username.test.ts
│ │ ├── utx-all-logins.1br.extidp.test.ts
│ │ ├── utx-impl.ts
│ │ ├── utx-is-fair-UNIMPL.test.ts
│ │ ├── view-edit-history.2br.mtime.test.ts
│ │ └── weird-usernames.2browsers.test.ts
│ ├── target
│ ├── test-constants.ts
│ ├── test-types.ts
│ ├── test-types2.ts
│ ├── tsconfig.json
│ ├── utils
│ │ ├── log-and-die.ts
│ │ ├── make.ts
│ │ ├── pages-for.ts
│ │ ├── server.ts
│ │ ├── settings-exp-def.ts
│ │ ├── settings.ts
│ │ ├── site-builder.ts
│ │ ├── ty-assert.ts
│ │ └── utils.ts
│ ├── wdio-progress-reporter.ts
│ ├── wdio.conf.js
│ ├── wdio.conf.ts
│ └── yarn.lock
├── emb-forum-irame-1.html
├── int-w
│ ├── ghost
│ │ └── casper-post.hbs
│ └── matrix
│ │ ├── element-web-config.json
│ │ └── homeserver.yaml
└── test-media
├── to-talkyard
├── .gitignore
├── README.md
├── jest.config.js
├── n
├── package.json
├── src
│ ├── from-disqus-to-ty.ts
│ ├── from-wordpress-to-ty.ts
│ ├── to-talkyard.d.ts
│ └── to-talkyard.ts
├── tsconfig.json
├── tslint.json
└── yarn.lock
├── translations
├── de_DE
├── en_US
│ └── i18n.ts
├── es_CL
├── he_IL
├── i18n-README.md
├── lv_LV
├── nl_NL
├── pl_PL
├── pt_BR
│ └── i18n.ts
├── ru_RU
│ └── i18n.ts
├── sv_SE
│ └── i18n.ts
├── uk_UA
└── zh_CN
├── vendors
└── nixos-signing-pub-key.gpg
├── version.txt
├── volumes
└── gulp-home
│ └── .gitkeep
├── wip
├── aliases
│ ├── auto-test-thoughts.txt
│ └── wip.txt
├── bookmarks
│ └── bookmarks-wip.txt
├── cr-priv-prefs.txt
├── joint-decisions
│ └── joint-decisions.txt
├── priv-comts
│ └── priv-comts-wip.txt
├── priv-prefs
│ └── priv-prefs-wip.txt
├── tags
│ └── tags-wip.txt
└── upgr-scala-2.13
│ └── add-collection-seq-import.sh
└── yarn.lock
/.npmignore:
--------------------------------------------------------------------------------
1 | # Numerous always-ignore extensions
2 | *.diff
3 | *.err
4 | *.orig
5 | *.log
6 | *.rej
7 | *.swo
8 | *.swp
9 | *.vi
10 | *~
11 | *.sass-cache
12 |
13 | # OS or Editor folders
14 | .DS_Store
15 | .cache
16 | .project
17 | .settings
18 | .tmproj
19 | nbproject
20 | Thumbs.db
21 |
22 | # NPM packages folder.
23 | node_modules/
24 |
25 | # Brunch folder for temporary files.
26 | tmp/
27 |
--------------------------------------------------------------------------------
/.vscode/settings.json:
--------------------------------------------------------------------------------
1 | {
2 | "editor.rulers": [
3 | 97
4 | ],
5 | "editor.tabSize": 2,
6 | "files.watcherExclude": {
7 | "**/node_modules": true,
8 | "**/dist": true,
9 | "**/build": true,
10 | "**/volumes": true,
11 | "**/target": true,
12 | "**/.bloop": true,
13 | "**/.metals": true,
14 | "**/.ammonite": true
15 | }
16 | }
--------------------------------------------------------------------------------
/.yarnclean:
--------------------------------------------------------------------------------
1 | # Selenium drivers
2 | # What? This has somehow disappeared, 2020-12-13. Running via Docker now anyway.
3 | # ------
4 | #!node_modules/selenium-standalone/.selenium/
5 | # Will keep e.g.:
6 | # node_modules/selenium-standalone/.selenium/chromedriver/2.25-x64-chromedriver
7 | # ------
8 |
9 | # test directories
10 | __tests__
11 | test
12 | tests
13 | powered-test
14 |
15 | # asset directories
16 | # Let's keep docs — nice to have, if offline? [yarnclean_keep_docs]
17 | #docs
18 | #doc
19 | website
20 | images
21 | assets
22 |
23 | # examples
24 | example
25 | examples
26 |
27 | # code coverage directories
28 | coverage
29 | .nyc_output
30 |
31 | # build scripts
32 | Makefile
33 | Gulpfile.js
34 | Gruntfile.js
35 |
36 | # configs
37 | .tern-project
38 | .gitattributes
39 | .editorconfig
40 | .*ignore
41 | !./node_modules/.gitignore
42 | .eslintrc
43 | .jshintrc
44 | .flowconfig
45 | .documentup.json
46 | .yarn-metadata.json
47 | .*.yml
48 | *.yml
49 |
50 | # misc
51 | *.gz
52 |
53 | # Let's keep docs — nice to have, if offline? [yarnclean_keep_docs]
54 | #*.md
55 |
--------------------------------------------------------------------------------
/appsv/model/.gitignore:
--------------------------------------------------------------------------------
1 | scratch.txt
2 | scratch/
3 |
4 | # Maven
5 | target/
6 |
7 | # SBT
8 | lib_managed/
9 | src_managed/
10 | project/
11 |
12 | # Idea
13 | debiki-core.iml
14 | debiki-core.ipr
15 | debiki-core.iws
16 |
17 | # Eclipse
18 | .cache
19 | .classpath
20 | .project
21 | .settings/
22 |
--------------------------------------------------------------------------------
/appsv/model/build.sbt:
--------------------------------------------------------------------------------
1 | name := "ty-model"
2 |
3 | organization := "com.debiki"
4 |
5 | version := ProjectDirectory.versionFileContents
6 |
7 | // Apparently needed for SBT dependencyTree, see plugins.sbt. [dependencyTree_dependency]
8 | resolvers += "Scala-Tools Maven2 Repository" at "https://scala-tools.org/repo-releases"
9 |
10 | libraryDependencies ++= Seq(
11 | Dependencies.Libs.scalactic,
12 | Dependencies.Libs.guava,
13 | Dependencies.Libs.apacheCommonsCodec,
14 | Dependencies.Libs.apacheCommonsValidator,
15 | Dependencies.Libs.apacheCommonsEmail, // needed here for email address validation only
16 | Dependencies.Libs.apacheTika,
17 | Dependencies.Libs.owaspEncoder,
18 | Dependencies.Play.json,
19 | // COULD move to the server module? [mv_scrypt_2_srv]
20 | Dependencies.Libs.lambdaworksScrypt,
21 | // CLEAN_UP remove Mockito and Spec2. Use only ScalaTest, need to edit some tests.
22 | Dependencies.Libs.mockito,
23 | Dependencies.Libs.specs2,
24 | Dependencies.Libs.scalaTest,
25 | )
26 |
27 | compileOrder := CompileOrder.JavaThenScala
28 |
--------------------------------------------------------------------------------
/appsv/model/src/main/java/name/fraser/neil/plaintext/diff_match_patch.java:
--------------------------------------------------------------------------------
1 | ../../../../../../../../../modules/google-diff-match-patch/java/src/name/fraser/neil/plaintext/diff_match_patch.java
--------------------------------------------------------------------------------
/appsv/model/src/main/scala/com/debiki/core/Notice.scala:
--------------------------------------------------------------------------------
1 | package com.debiki.core
2 |
3 | import play.api.libs.json.JsObject
4 |
5 | case class Notice(
6 | siteId: SiteId,
7 | toPatId: PatId,
8 | noticeId: NoticeId,
9 | firstAt: WhenMins,
10 | lastAt: WhenMins,
11 | numTotal: i32,
12 | noticeData: Opt[JsObject],
13 | ) {
14 | // For now, admins only.
15 | require(toPatId == Group.AdminsId, "TyE40fMJ2W4")
16 | require(noticeId >= 1001, "TyE5R02MRSEG4")
17 | require(firstAt.millis <= lastAt.millis, "TyE70SRDE55F")
18 | require(numTotal >= 1, "TyE70SRDE550")
19 | require(noticeData.isEmpty, "TyE40fMJ25MG")
20 | }
21 |
22 |
23 | object Notice {
24 | val TwitterLoginConfigured = 1001
25 | val TwitterLoginUsed = 1002
26 | }
27 |
--------------------------------------------------------------------------------
/appsv/rdb/.gitignore:
--------------------------------------------------------------------------------
1 | scratch.txt
2 | scratch/
3 |
4 | # SBT
5 | target/
6 | lib_managed/
7 | src_managed/
8 | project/boot/
9 | project/target/
10 |
11 | # Idea
12 | .idea/
13 | debiki-dao-oracle.iml
14 | project/project.iml
15 |
16 | # Eclipse
17 | .cache
18 | .classpath
19 | .project
20 | .settings/
21 |
--------------------------------------------------------------------------------
/appsv/rdb/build.sbt:
--------------------------------------------------------------------------------
1 | name := "ty-dao-rdb"
2 |
3 | organization := "com.debiki"
4 |
5 | version := ProjectDirectory.versionFileContents
6 |
7 | libraryDependencies ++= Seq(
8 | Dependencies.Play.json,
9 | Dependencies.Libs.postgresqlJbcdClient,
10 | Dependencies.Libs.flywaydb)
11 |
12 |
--------------------------------------------------------------------------------
/appsv/rdb/scripts/old/flyway-migrations/y2014/v3__no_email.sql:
--------------------------------------------------------------------------------
1 | -- This evolution starts using Null instead of "" if email absent (it is for Twitter users).
2 |
3 | alter table DW1_IDS_OPENID alter column EMAIL drop not null;
4 | update DW1_IDS_OPENID set EMAIL = null where length(EMAIL) = 0;
5 | alter table DW1_IDS_OPENID add constraint DW1_IDS_EMAIL__C_LEN check (length(EMAIL) between 1 and 100);
6 |
7 |
--------------------------------------------------------------------------------
/appsv/rdb/scripts/old/flyway-migrations/y2014/v5__multireply.sql:
--------------------------------------------------------------------------------
1 |
2 | alter table DW1_PAGE_ACTIONS add column MULTIREPLY varchar;
3 | alter table DW1_PAGE_ACTIONS add constraint DW1_PGAS_TYPE_MULTIREPLY__C check (TYPE = 'Post' or MULTIREPLY is null);
4 | alter table DW1_PAGE_ACTIONS add constraint DW1_PGAS_MULTIREPLY__C_NUM check (MULTIREPLY ~ '[0-9,]');
5 |
6 | alter table DW1_POSTS add column MULTIREPLY varchar;
7 | alter table DW1_POSTS add constraint DW1_POSTS_MULTIREPLY__C_NUM check (MULTIREPLY ~ '[0-9,]');
8 |
9 |
--------------------------------------------------------------------------------
/appsv/rdb/scripts/old/flyway-migrations/y2014/v6__always_commonmark.sql:
--------------------------------------------------------------------------------
1 | alter table DW1_PAGE_ACTIONS drop column MARKUP;
2 | alter table DW1_POSTS drop column MARKUP;
3 |
4 |
--------------------------------------------------------------------------------
/appsv/rdb/scripts/old/flyway-migrations/y2014/v8__email_for_each_new_post.sql:
--------------------------------------------------------------------------------
1 |
2 | alter table DW1_USERS add column EMAIL_FOR_EVERY_NEW_POST boolean not null default false;
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/appsv/rdb/scripts/old/flyway-migrations/y2014/v9__page_role_homepage.sql:
--------------------------------------------------------------------------------
1 |
2 | -- Add 'H'omepage role. Rename 'Generic' to Web'P'age (not 'W'iki'P'age).
3 | alter table DW1_PAGES drop constraint DW1_PAGES_PAGEROLE__C_IN;
4 | update DW1_PAGES set PAGE_ROLE = 'P' where PAGE_ROLE = 'G';
5 | alter table DW1_PAGES add constraint DW1_PAGES_PAGEROLE__C_IN check (PAGE_ROLE in (
6 | 'H', 'P', 'EC', 'B', 'BP', 'F', 'FC', 'FT', 'W', 'WP', 'C', 'SP'));
7 |
8 | -- Convert own pages.
9 | update DW1_PAGES set PAGE_ROLE = 'H' where TENANT = '3' and GUID in (
10 | '4xsq1', -- the homepage
11 | '4vkm1'); -- the embedded comments page
12 |
13 |
--------------------------------------------------------------------------------
/appsv/rdb/scripts/old/flyway-migrations/y2015/v10__create_main_site.sql:
--------------------------------------------------------------------------------
1 |
2 | insert into dw1_tenants (id, name)
3 | select '1', 'Main Site'
4 | where not exists (
5 | select id from dw1_tenants where id = '1');
6 |
--------------------------------------------------------------------------------
/appsv/rdb/scripts/old/flyway-migrations/y2015/v11__site_creator_email.sql:
--------------------------------------------------------------------------------
1 |
2 | alter table dw1_tenants drop column creator_tenant_id;
3 | alter table dw1_tenants drop column creator_role_id;
4 |
5 | alter table dw1_tenants add column creator_email_address varchar;
6 | alter table dw1_tenants add constraint dw1_tnt_creatoremail__c
7 | check (creator_email_address like '%@%.%');
8 |
9 | update dw1_tenants set creator_email_address = 'unknown@example.com';
10 | update dw1_tenants set creator_ip = '0.0.0.0' where creator_ip is null;
11 | update dw1_tenants set name = 'embedded-site-' || id where name is null;
12 |
13 | alter table dw1_tenants alter creator_email_address set not null;
14 | alter table dw1_tenants alter creator_ip set not null;
15 | alter table dw1_tenants alter name set not null;
16 |
17 | create index dw1_tenants_creatoremail on dw1_tenants(creator_email_address);
18 |
19 |
--------------------------------------------------------------------------------
/appsv/rdb/scripts/old/flyway-migrations/y2015/v20__target_site_id.sql:
--------------------------------------------------------------------------------
1 |
2 | alter table dw2_audit_log add column target_site_id varchar;
3 | alter table dw2_audit_log add constraint dw2_auditlog_tgtsite__r__sites
4 | foreign key (target_site_id) references dw1_tenants(id);
5 |
6 | -- Previously, a column 'sno' (sequence no) later renamed to 'id' was the primary key.
7 | alter table dw1_identities drop constraint dw1_idsoid_sno__p;
8 | alter table dw1_identities add constraint dw1_ids_siteid_id__p primary key (site_id, id);
9 |
10 |
--------------------------------------------------------------------------------
/appsv/rdb/scripts/old/flyway-migrations/y2015/v23__problems_ideas.sql:
--------------------------------------------------------------------------------
1 |
2 | -- When a problem or idea was accepted / planned to be fixed/done.
3 | alter table dw1_pages add column planned_at timestamp;
4 |
5 | update dw1_pages set planned_at = created_at where done_at is not null;
6 | update dw1_pages set closed_at = done_at where done_at is not null and closed_at is null;
7 | update dw1_pages set closed_at = answered_at where answered_at is not null and closed_at is null;
8 |
9 | alter table dw1_pages add constraint dw1_pages_createdat_plannedat__c_le check (created_at <= planned_at);
10 | alter table dw1_pages add constraint dw1_pages_plannedat_doneat__c_le check (planned_at <= done_at);
11 | alter table dw1_pages add constraint dw1_pages_plannedat_doneat__c_null check (
12 | done_at is null or planned_at is not null);
13 |
14 | -- A topic gets closed when it's marked as done or answered.
15 | alter table dw1_pages add constraint dw1_pages__c_closed_if_done_answered check (
16 | (done_at is null and answered_at is null) or closed_at is not null);
17 |
--------------------------------------------------------------------------------
/appsv/rdb/scripts/old/flyway-migrations/y2015/v26__longer_site_hostname.sql:
--------------------------------------------------------------------------------
1 |
2 | -- Allow long hostnames, so e2e tests can use descriptive hostnames.
3 | -- Change from varchar(50) to varchar any-length, then add a constraint instead.
4 | alter table dw1_tenant_hosts alter host type varchar;
5 | alter table dw1_tenant_hosts add constraint dw1_hosts_host__c_len
6 | check(length(host) between 1 and 100);
7 |
8 |
--------------------------------------------------------------------------------
/appsv/rdb/scripts/old/flyway-migrations/y2015/v27__longer_emails.sql:
--------------------------------------------------------------------------------
1 |
2 | -- Allow longer email columns, e.g. body too short (only 2000).
3 | -- First remove varchar(NNN) length, then add constraints instead.
4 | alter table dw1_emails_out alter sent_to type varchar;
5 | alter table dw1_emails_out alter subject type varchar;
6 | alter table dw1_emails_out alter body_html type varchar;
7 | alter table dw1_emails_out alter provider_email_id type varchar;
8 | alter table dw1_emails_out alter failure_text type varchar;
9 |
10 | alter table dw1_emails_out add constraint dw1_emlot_sentto__c_len check(length(sent_to) <= 200);
11 | alter table dw1_emails_out add constraint dw1_emlot_subject__c_len check(length(subject) between 1 and 200);
12 | alter table dw1_emails_out add constraint dw1_emlot_bodyhtml__c_len check(length(body_html) between 1 and 5000);
13 | alter table dw1_emails_out add constraint dw1_emlot_provideremailid__c_len check(length(provider_email_id) <= 200);
14 | alter table dw1_emails_out add constraint dw1_emlot_failuretext__c_len check(length(failure_text) <= 10000);
15 |
16 |
--------------------------------------------------------------------------------
/appsv/rdb/scripts/old/flyway-migrations/y2016/v35__html_tag_css_classes.sql:
--------------------------------------------------------------------------------
1 |
2 | alter table dw1_pages add column html_tag_css_classes varchar;
3 |
4 | alter table dw1_pages add constraint dw1_pages_htmltagcssclass__c_len check (
5 | length(html_tag_css_classes) between 1 and 100);
6 |
7 |
8 | -- Will be reused, if categories will get their own css class too.
9 | create or replace function is_valid_css_class(text varchar) returns boolean as $$
10 | begin
11 | return text ~ '^[ a-zA-Z0-9_-]+$';
12 | end;
13 | $$ language plpgsql;
14 |
15 | alter table dw1_pages add constraint dw1_pages_htmltagcssclass__c_ptrn check (
16 | is_valid_css_class(html_tag_css_classes));
17 |
18 |
--------------------------------------------------------------------------------
/appsv/rdb/scripts/old/flyway-migrations/y2016/v37__audit_log_email.sql:
--------------------------------------------------------------------------------
1 |
2 | alter table dw2_audit_log add email_address varchar;
3 | alter table dw2_audit_log add constraint dw2_auditlog_emailaddr__c_len check (
4 | length(email_address) between 3 and 200);
5 | alter table dw2_audit_log add constraint dw2_auditlog_emailaddr__c_email check (
6 | email_address like '%_@_%');
7 |
8 |
9 |
--------------------------------------------------------------------------------
/appsv/rdb/scripts/old/play-evolutions/15.sql:
--------------------------------------------------------------------------------
1 | # This evolution adds a per site next page id sequence no.
2 |
3 |
4 | # --- !Ups
5 |
6 |
7 | alter table DW1_TENANTS add column NEXT_PAGE_ID int not null default 1;
8 |
9 | create or replace function INC_NEXT_PAGE_ID(site_id character varying) returns int as $$
10 | declare
11 | next_id int;;
12 | begin
13 | update DW1_TENANTS
14 | set NEXT_PAGE_ID = NEXT_PAGE_ID + 1
15 | where ID = site_id
16 | returning NEXT_PAGE_ID into next_id;;
17 | return next_id - 1;;
18 | end;;
19 | $$ language plpgsql;
20 |
21 |
22 | # --- !Downs
23 |
24 |
25 | alter table DW1_TENANTS drop column NEXT_PAGE_ID;
26 |
27 | drop function INC_NEXT_PAGE_ID(site_id character varying);
28 |
29 |
--------------------------------------------------------------------------------
/appsv/rdb/scripts/old/play-evolutions/8.sql:
--------------------------------------------------------------------------------
1 | -- This evolution is for embedded sites:
2 | -- - Adds EMBEDDING_PAGE_URL column to DW1_PAGES.
3 |
4 |
5 | # --- !Ups
6 |
7 |
8 | alter table DW1_PAGES add column EMBEDDING_PAGE_URL varchar;
9 |
10 | alter table DW1_PAGES add constraint DW1_PAGES_EMBPAGEURL__C_LEN check (
11 | length(EMBEDDING_PAGE_URL) between 1 and 200);
12 |
13 | alter table DW1_PAGES add constraint DW1_PAGES_EMBPAGEURL__C_TRIM check (
14 | trim(EMBEDDING_PAGE_URL) = EMBEDDING_PAGE_URL);
15 |
16 |
17 | # --- !Downs
18 |
19 |
20 | alter table DW1_PAGES drop column EMBEDDING_PAGE_URL;
21 |
22 |
23 |
--------------------------------------------------------------------------------
/appsv/rdb/scripts/pending-evolutions.sql:
--------------------------------------------------------------------------------
1 | /*
2 | Drop: dw1_pgas_magic_id_types__c
3 | or change 0t, 0b, 0c to 65501, 02, 03
4 |
5 |
6 | */
7 |
--------------------------------------------------------------------------------
/appsv/rdb/src/main/resources/db/migration/wip_r__views.sql:
--------------------------------------------------------------------------------
1 | create or replace function pretty_email_status(status integer) returns varchar
2 | language plpgsql as $$
3 | begin
4 | return case status
5 | when 1 then 'undecided'
6 | when 2 then 'skipped'
7 | when 3 then 'created'
8 | else '' || status
9 | end;
10 | end;
11 | $$;
12 |
13 |
14 | select *, pretty_email_status(email_status) as pr_email_status from notifications3 where site_id = -16;
15 |
16 |
17 |
--------------------------------------------------------------------------------
/appsv/rdb/src/main/resources/db/migration/y2016/v10__remove_constraint.sql:
--------------------------------------------------------------------------------
1 |
2 | alter table audit_log3 drop constraint dw2_auditlog_tgtsite__r__sites;
3 |
4 |
--------------------------------------------------------------------------------
/appsv/rdb/src/main/resources/db/migration/y2016/v11__topic_list_style.sql:
--------------------------------------------------------------------------------
1 |
2 | alter table pages3 add column layout bigint not null default 0;
3 |
4 |
5 |
--------------------------------------------------------------------------------
/appsv/rdb/src/main/resources/db/migration/y2016/v13__page_hidden_at.sql:
--------------------------------------------------------------------------------
1 |
2 | alter table pages3 add column hidden_at timestamp;
3 | alter table pages3 add constraint dw1_pages_createdat_hiddenat__c_le CHECK (created_at <= hidden_at);
4 |
5 | alter table audit_log3 drop constraint dw2_auditlog_page_post__c;
6 | delete from audit_log3 where did_what = 3; -- 3 = new page
7 | alter table audit_log3 add constraint dw2_auditlog_page_post__c check (
8 | did_what <> 3 or (page_id is not null and post_id is not null));
9 |
--------------------------------------------------------------------------------
/appsv/rdb/src/main/resources/db/migration/y2016/v14__more_settings.sql:
--------------------------------------------------------------------------------
1 |
2 | alter table settings3 add column invite_only boolean;
3 | alter table settings3 add column allow_signup boolean;
4 | alter table settings3 add column allow_local_signup boolean;
5 |
6 | alter table settings3 drop constraint settings3_auth_guest__c;
7 | alter table settings3 add constraint settings3_auth_guest__c check (
8 | not (allow_guest_login and (
9 | user_must_be_auth or user_must_be_approved or invite_only or not allow_signup)));
10 |
11 | alter table settings3 add constraint settings3_signup__c check (
12 | allow_signup or (not allow_local_signup));
13 |
14 |
15 | alter table users3 add column about varchar;
16 | alter table users3 add constraint users_about__c_len check (length(about) between 1 and 2000);
17 | -- Guests have no about field.
18 | alter table users3 add constraint users_about_guest__c_n check (user_id >= 1 or about is null);
19 |
20 |
--------------------------------------------------------------------------------
/appsv/rdb/src/main/resources/db/migration/y2016/v15__change_usernamed.sql:
--------------------------------------------------------------------------------
1 |
2 | create table usernames3(
3 | site_id varchar not null,
4 | username varchar not null,
5 | in_use_from timestamp not null,
6 | in_use_to timestamp,
7 | user_id int not null,
8 | first_mention_at timestamp,
9 | -- username + from...to should be unique, but we'll verify that in the app server instead.
10 | constraint usernames_p primary key (site_id, username, in_use_from),
11 | constraint usernames_r_users foreign key (site_id, user_id) references users3 (site_id, user_id),
12 | constraint usernames_c_from_lt_to check (in_use_from < in_use_to),
13 | constraint usernames_c_from_le_mention check (in_use_from <= first_mention_at),
14 | constraint usernames_c_mention_le_to check (first_mention_at <= in_use_to),
15 | constraint usernames_c_username_len check (length(username) between 2 and 50)
16 | );
17 |
18 |
--------------------------------------------------------------------------------
/appsv/rdb/src/main/resources/db/migration/y2016/v16__show_settings.sql:
--------------------------------------------------------------------------------
1 |
2 | alter table settings3 add column show_categories boolean;
3 | alter table settings3 add column show_topic_filter boolean;
4 | alter table settings3 add column show_topic_types boolean;
5 | alter table settings3 add column select_topic_type boolean;
6 |
7 |
--------------------------------------------------------------------------------
/appsv/rdb/src/main/resources/db/migration/y2016/v3__unknown_user.sql:
--------------------------------------------------------------------------------
1 |
2 |
3 | -- The unknown user was never created because of a bug in the v1 script, se the_bug below
4 | insert into users3(site_id, user_id, display_name, email, guest_cookie, created_at)
5 | select '1', -3, 'Unknown', '-', 'UU', now_utc()
6 | where not exists (
7 | select 1 from users3 where site_id = '1' and user_id = -3); -- the_bug: -3 was -1
8 |
9 |
--------------------------------------------------------------------------------
/appsv/rdb/src/main/resources/db/migration/y2016/v4__index_queue.sql:
--------------------------------------------------------------------------------
1 |
2 |
3 | -- No foreign keys, because that'd prevent us from deleting the site, page or post.
4 | create table index_queue3(
5 | inserted_at timestamp not null default now_utc(),
6 | -- When the item was created or inserted into the queue or whatever. We sort by this
7 | -- field when determining in which order to index stuff. Or not?
8 | action_at timestamp not null,
9 | site_id varchar not null,
10 | site_version int not null,
11 | page_id varchar,
12 | page_version int,
13 | post_id int,
14 | post_rev_nr int,
15 | constraint ixq_site_page__u unique (site_id, page_id),
16 | constraint ixq_site_post__u unique (site_id, post_id),
17 | constraint ixq_page_or_post__c_xor check (page_id is null or post_id is null),
18 | constraint ixq_page_pageversion__c_nl_eq check ((page_id is null) = (page_version is null)),
19 | constraint ixq_post_postrevnr__c_nl_eq check ((post_id is null) = (post_rev_nr is null))
20 | );
21 |
22 | create index ixq_actionat__i on index_queue3 (action_at desc);
23 |
24 |
25 |
--------------------------------------------------------------------------------
/appsv/rdb/src/main/resources/db/migration/y2016/v5__superadmin.sql:
--------------------------------------------------------------------------------
1 |
2 | alter table sites3 add column status int not null default 1;
3 | alter table users3 add column is_superadmin boolean;
4 |
5 | alter table sites3 add constraint sites_status__c_in check (status between 1 and 7);
6 |
7 |
--------------------------------------------------------------------------------
/appsv/rdb/src/main/resources/db/migration/y2016/v6__branch_sideways.sql:
--------------------------------------------------------------------------------
1 |
2 | alter table posts3 add column branch_sideways smallint;
3 |
4 |
--------------------------------------------------------------------------------
/appsv/rdb/src/main/resources/db/migration/y2016/v9__spam_check_queue.sql:
--------------------------------------------------------------------------------
1 |
2 |
3 | -- No foreign keys, because that'd prevent us from deleting the post.
4 | create table spam_check_queue3(
5 | inserted_at timestamp not null default now_utc(),
6 | -- When the item was created or inserted into the queue or whatever. We sort by this
7 | -- field when determining in which order to check for spam.
8 | action_at timestamp not null,
9 | site_id varchar not null,
10 | post_id int not null,
11 | post_rev_nr int not null,
12 | user_id int not null,
13 | user_id_cookie varchar not null,
14 | browser_fingerprint int not null,
15 | req_uri varchar not null,
16 | req_ip varchar not null,
17 | req_user_agent varchar,
18 | req_referer varchar,
19 |
20 | constraint scq_site_post__p primary key (site_id, post_id)
21 | );
22 |
23 | create index scq_actionat__i on spam_check_queue3 (action_at desc);
24 |
25 |
26 |
--------------------------------------------------------------------------------
/appsv/rdb/src/main/resources/db/migration/y2017/v21__username_lowercase.sql:
--------------------------------------------------------------------------------
1 |
2 | update usernames3 set username = lower(username);
3 | alter table usernames3 rename username to username_lowercase;
4 |
5 |
6 |
--------------------------------------------------------------------------------
/appsv/rdb/src/main/resources/db/migration/y2017/v22__backup_test_log.sql:
--------------------------------------------------------------------------------
1 |
2 | create table backup_test_log3(
3 | logged_at timestamp not null,
4 | logged_by varchar not null,
5 | backup_of_what varchar not null,
6 | random_value varchar not null,
7 | got_ok_message_at timestamp);
8 |
9 | create index backup_test_log_i on backup_test_log3 (logged_at desc);
10 |
11 |
12 |
--------------------------------------------------------------------------------
/appsv/rdb/src/main/resources/db/migration/y2017/v24__page_pop.sql:
--------------------------------------------------------------------------------
1 |
2 | create table page_popularity_scores3(
3 | site_id int not null,
4 | page_id varchar not null,
5 | popular_since timestamp not null,
6 | updated_at timestamp not null,
7 | algorithm smallint not null,
8 | day_score float not null,
9 | week_score float not null,
10 | month_score float not null,
11 | quarter_score float not null,
12 | year_score float not null,
13 | all_score float not null,
14 | constraint pagepopscores_site_page_p primary key (site_id, page_id),
15 | constraint pagepopscores_r_pages foreign key (site_id, page_id) references pages3 (site_id, page_id),
16 | constraint pagepopscores_updat_ge_popsince check (updated_at >= popular_since),
17 | constraint pagepopscores_alg_gtz check (algorithm > 0)
18 | -- Scores can perhaps be < 0? If many Unwanted votes, e.g. no Likes, and orig post = unwanted?
19 | );
20 |
--------------------------------------------------------------------------------
/appsv/rdb/src/main/resources/db/migration/y2017/v25__summary_emails.sql:
--------------------------------------------------------------------------------
1 |
2 | alter table users3 add column summary_email_interval_mins int;
3 | alter table users3 add column summary_email_if_active bool;
4 |
5 | alter table user_stats3 add column last_summary_email_at timestamp;
6 | alter table user_stats3 add column next_summary_email_at timestamp;
7 |
8 | alter table page_users3 add column incl_in_summary_email_at_mins int;
9 |
10 | create index userstats_nextsummary_i on user_stats3 (next_summary_email_at nulls first);
11 |
12 | alter table emails_out3 drop constraint dw1_emlot_type__c_in;
13 | alter table emails_out3 alter column "type" type smallint using (
14 | case "type"
15 | when 'Notf' then 1
16 | when 'AcSm' then 2
17 | when 'Invt' then 11
18 | when 'InAc' then 12
19 | when 'InPw' then 13
20 | when 'CrAc' then 21
21 | when 'RsPw' then 22
22 | end);
23 |
24 | alter table emails_out3 add constraint emailsout_type__c_betw check ("type" between 1 and 50);
25 |
26 |
--------------------------------------------------------------------------------
/appsv/rdb/src/main/resources/db/migration/y2017/v26__nulls_last.sql:
--------------------------------------------------------------------------------
1 |
2 | drop index userstats_nextsummary_i;
3 | create index userstats_nextsummary_i on user_stats3 (next_summary_email_at nulls last);
4 |
5 |
--------------------------------------------------------------------------------
/appsv/rdb/src/main/resources/db/migration/y2017/v27__plan_done_any_role.sql:
--------------------------------------------------------------------------------
1 |
2 | alter table pages3 drop constraint dw1_pages_role_answered__c;
3 | alter table pages3 drop constraint dw1_pages_role_planned_done__c;
4 |
5 | alter table user_stats3 rename column next_summary_email_at to next_summary_maybe_at;
6 |
7 | alter table pages3 add column incl_in_summaries smallint;
8 | alter table categories3 add column incl_in_summaries smallint;
9 |
--------------------------------------------------------------------------------
/appsv/rdb/src/main/resources/db/migration/y2017/v28__allow_embedding.sql:
--------------------------------------------------------------------------------
1 |
2 | alter table settings3 add column allow_embedding_from varchar;
3 | alter table settings3 add constraint settings_allowembeddingfrom__c_len check (
4 | length(allow_embedding_from) between 5 and 100);
5 |
6 | create table alt_page_ids3(
7 | site_id int not null,
8 | alt_page_id varchar not null,
9 | real_page_id varchar not null,
10 | constraint altpageids_p primary key (site_id, alt_page_id),
11 | constraint altpageids_r_pages foreign key (site_id, real_page_id) references pages3(site_id, page_id),
12 | constraint altpageids_altid_c_len check (length(alt_page_id) between 1 and 300)
13 | );
14 |
--------------------------------------------------------------------------------
/appsv/rdb/src/main/resources/db/migration/y2017/v29__remove_columns.sql:
--------------------------------------------------------------------------------
1 |
2 | -- Is now a settings3 column instead.
3 | alter table sites3 drop column embedding_site_url;
4 |
5 | -- These should be removed too, later: (use audit_log3 instead)
6 | alter table sites3 alter column creator_email_address drop not null;
7 | alter table sites3 alter column creator_ip drop not null;
8 |
9 |
--------------------------------------------------------------------------------
/appsv/rdb/src/main/resources/db/migration/y2017/v30__page_started_at_wait_until.sql:
--------------------------------------------------------------------------------
1 | -- Delete the To-Do page role, use Idea in status Planned instead, that's the same thing, right.
2 | update pages3
3 | set page_role = 15 -- idea
4 | where page_role = 13; -- to do
5 |
6 | alter table pages3 add column started_at timestamp;
7 | alter table pages3 add column wait_until timestamp;
8 |
9 | alter table pages3 add constraint pages_c_createdat_le_startedat check (created_at <= started_at);
10 | alter table pages3 add constraint pages_c_not_todo check (page_role <> 13); -- todo
11 |
12 |
--------------------------------------------------------------------------------
/appsv/rdb/src/main/resources/db/migration/y2017/v31__num_posts_total.sql:
--------------------------------------------------------------------------------
1 |
2 | alter table pages3 add column num_posts_total int not null default 0;
3 |
4 | update pages3 pg set num_posts_total = (
5 | select count(*) from posts3 po where pg.site_id = po.site_id and pg.page_id = po.page_id);
6 |
7 | alter table pages3 add constraint pages_c_numpoststotal_ge_numrepliestotal check (
8 | num_posts_total >= num_replies_total);
9 |
--------------------------------------------------------------------------------
/appsv/rdb/src/main/resources/db/migration/y2017/v32__page_constraints.sql:
--------------------------------------------------------------------------------
1 |
2 | alter table pages3 drop constraint dw1_pages_plannedat_doneat__c_null;
3 | alter table pages3 add constraint pages_c_plannedat_le_startedat check (planned_at <= started_at);
4 | alter table pages3 add constraint pages_c_startedat_le_doneat check (started_at <= done_at);
5 |
--------------------------------------------------------------------------------
/appsv/rdb/src/main/resources/db/migration/y2018/v34__longer_allow_embedding.sql:
--------------------------------------------------------------------------------
1 |
2 | -- This constraint might contain many hostnames, so let it be fairly long.
3 | alter table settings3 drop constraint settings_allowembeddingfrom__c_len;
4 | alter table settings3 add constraint settings_c_allowembeddingfrom_btw_5_300 check (
5 | length(allow_embedding_from) between 5 and 300);
6 |
7 |
--------------------------------------------------------------------------------
/appsv/rdb/src/main/resources/db/migration/y2018/v368__no_browser_id_cookie.sql:
--------------------------------------------------------------------------------
1 |
2 | alter table blocks3 alter browser_id_cookie drop not null;
3 |
4 | alter table spam_check_queue3 alter user_id_cookie drop not null;
5 | alter table spam_check_queue3 rename user_id_cookie to browser_id_cookie;
6 |
--------------------------------------------------------------------------------
/appsv/rdb/src/main/resources/db/migration/y2018/v36__publ_site_id.sql:
--------------------------------------------------------------------------------
1 | alter table sites3 add column publ_id varchar;
2 |
3 | -- This generates 10 random hex chars. Future publ ids will be
4 | -- generated by the app server instead, and use base32? 36? + a crypto random gen.
5 | update sites3 set publ_id = substring(md5(random()::text) from 0 for 10 + 1);
6 |
7 | alter table sites3 alter column publ_id set not null;
8 |
9 | create unique index sites_publid_u on sites3 (publ_id);
10 |
11 |
--------------------------------------------------------------------------------
/appsv/rdb/src/main/resources/db/migration/y2018/v370__bump_after_close.sql:
--------------------------------------------------------------------------------
1 | alter table pages3 drop constraint dw1_pages_bumpedat_le_closedat__c;
2 |
--------------------------------------------------------------------------------
/appsv/rdb/src/main/resources/db/migration/y2018/v374__many_invites.sql:
--------------------------------------------------------------------------------
1 |
2 | -- Drop unique index, replace with non-unique. So one can re-send invites.
3 | drop index dw2_invites_email__u;
4 | create index invites_emailaddr_invby_i on invites3 (site_id, email_address, created_by_id);
5 |
6 | create index invites_invat_i on invites3 (site_id, created_at desc);
7 |
8 |
--------------------------------------------------------------------------------
/appsv/rdb/src/main/resources/db/migration/y2018/v376__guest_id_constr.sql:
--------------------------------------------------------------------------------
1 |
2 | alter table users3 drop constraint dw1_users_guestcookie__c_len;
3 | alter table users3 rename guest_cookie to guest_browser_id;
4 | alter table users3 add constraint users_c_guestbrowserid_len check (
5 | length(guest_browser_id) between 2 and 100);
6 |
7 |
--------------------------------------------------------------------------------
/appsv/rdb/src/main/resources/db/migration/y2019/v377__tour_tips_seen.sql:
--------------------------------------------------------------------------------
1 |
2 | alter table user_stats3 add column tour_tips_seen varchar[];
3 | alter table user_stats3 add constraint userstats_c_tourtipsseen_len check (
4 | pg_column_size(tour_tips_seen) <= 400);
5 |
6 | -- Don't show intro tours, for people who have old existing admin accounts already.
7 | -- They might have customized their communities, possibly breaking the tours.
8 | update user_stats3 us
9 | set tour_tips_seen ='{"a_c_a", "a_b_a", "f_c_a", "f_b_a"}'
10 | where us.user_id >= 100
11 | and exists (
12 | select 1 from users3 u
13 | where u.site_id = us.site_id and u.user_id = us.user_id and u.is_admin);
14 |
15 |
16 | alter table users3 add column ui_prefs jsonb;
17 | alter table users3 add constraint users_c_uiprefs_len check (
18 | pg_column_size(ui_prefs) <= 400);
19 |
20 |
21 | alter table settings3 add column expire_idle_after_mins int;
22 |
23 |
24 | -- Unpin about category topics.
25 | update pages3 set pin_order = null, pin_where = null where page_role = 9;
26 |
--------------------------------------------------------------------------------
/appsv/rdb/src/main/resources/db/migration/y2019/v378__more_settings.sql:
--------------------------------------------------------------------------------
1 |
2 | alter table settings3 add column enable_gitlab_login boolean;
3 | alter table settings3 add column enable_linkedin_login boolean;
4 | alter table settings3 add column enable_vk_login boolean;
5 | alter table settings3 add column enable_instagram_login boolean;
6 | alter table settings3 add column enable_forum boolean;
7 | alter table settings3 add column enable_api boolean;
8 | alter table settings3 add column enable_tags boolean;
9 |
10 | alter table settings3 add column embedded_comments_category_id int;
11 | alter table settings3 add constraint settings_embcmtscatid_r_categories
12 | foreign key (site_id, embedded_comments_category_id)
13 | references categories3(site_id, id);
14 |
15 |
--------------------------------------------------------------------------------
/appsv/rdb/src/main/resources/db/migration/y2019/v379__tos_privacy_settings.sql:
--------------------------------------------------------------------------------
1 |
2 | alter table settings3 add column terms_of_use_url varchar;
3 | alter table settings3 add column privacy_url varchar;
4 | alter table settings3 add column rules_url varchar;
5 | alter table settings3 add column contact_email_addr varchar;
6 | alter table settings3 add column contact_url varchar;
7 |
8 |
9 | alter table settings3 add constraint settings_c_termsofuseurl_len check (
10 | length(terms_of_use_url) between 1 and 200);
11 |
12 | alter table settings3 add constraint settings_c_privacyurl_len check (
13 | length(privacy_url) between 1 and 200);
14 |
15 | alter table settings3 add constraint settings_c_rulesurl_len check (
16 | length(rules_url) between 1 and 200);
17 |
18 | alter table settings3 add constraint settings_c_contactemailaddr_len check (
19 | length(contact_email_addr) between 1 and 200);
20 |
21 | alter table settings3 add constraint settings_c_contacturl_len check (
22 | length(contact_url) between 1 and 200);
23 |
24 |
--------------------------------------------------------------------------------
/appsv/rdb/src/main/resources/db/migration/y2019/v380__review_task_notfs.sql:
--------------------------------------------------------------------------------
1 | alter table notifications3 drop constraint dw1_notfs_type__c_in;
2 | update notifications3 set notf_type = notf_type + 300;
3 | update notifications3 set notf_type = 406 where notf_type = 306;
4 | alter table notifications3 add constraint notfs_c_notftype_range check (notf_type between 101 and 999);
5 |
6 |
7 | alter table settings3 drop constraint settings3_auth_guest__c;
8 | alter table settings3 add constraint settings_c_guestlogin_auth check (not (
9 | allow_guest_login and (
10 | user_must_be_auth or user_must_be_approved or invite_only)));
11 |
12 |
--------------------------------------------------------------------------------
/appsv/rdb/src/main/resources/db/migration/y2019/v384__invites_add_to_group.sql:
--------------------------------------------------------------------------------
1 |
2 | alter table invites3 add column start_at_url varchar;
3 | alter table invites3 add constraint invites_c_startaturl_len check (
4 | length(start_at_url) between 1 and 100);
5 |
6 | alter table invites3 add column add_to_group_id int;
7 | alter table invites3 add constraint invites_addtogroup_r_pps -- ix: invites_i_addtogroupid
8 | foreign key (site_id, add_to_group_id) references users3 (site_id, user_id) deferrable;
9 |
10 | create index invites_i_addtogroupid on invites3 (site_id, add_to_group_id)
11 | where add_to_group_id is not null;
12 |
13 |
--------------------------------------------------------------------------------
/appsv/rdb/src/main/resources/db/migration/y2019/v385__sso_logout_url.sql:
--------------------------------------------------------------------------------
1 |
2 | alter table settings3 add column sso_login_required_logout_url varchar;
3 | alter table settings3 add constraint settings_c_ssologinrequiredlogouturl_len check (
4 | length(sso_login_required_logout_url) between 1 and 200);
5 |
6 |
--------------------------------------------------------------------------------
/appsv/rdb/src/main/resources/db/migration/y2019/v386__guests_wo_browserid_use_extid.sql:
--------------------------------------------------------------------------------
1 |
2 | drop index pps_u_site_guest_no_browser_id;
3 | alter table users3 add constraint pps_c_guest_w_no_browserid_has_extid check (
4 | (user_id > 0) or (guest_browser_id is not null) or (ext_id is not null));
5 |
6 |
--------------------------------------------------------------------------------
/appsv/rdb/src/main/resources/db/migration/y2019/v387__email_length.sql:
--------------------------------------------------------------------------------
1 | alter table emails_out3 drop constraint dw1_emlot_bodyhtml__c_len;
2 | alter table emails_out3 add constraint emailsout_c_bodyhtml_len check (
3 | length(body_html) between 1 and 20000);
4 |
5 | -- A Facebook avatar url was 263 chars long, so bump the previous 250 chars limit.
6 | alter table identities3 drop constraint dw1_ids_avatarurl__c_len;
7 | alter table identities3 add constraint identities_c_avatarurl_len check (
8 | length(avatar_url) between 1 and 500);
9 |
10 |
--------------------------------------------------------------------------------
/appsv/rdb/src/main/resources/db/migration/y2019/v388__rm_email_notf_char_check.sql:
--------------------------------------------------------------------------------
1 |
2 | alter table users3 drop constraint dw1_users_emlntf__c;
3 |
--------------------------------------------------------------------------------
/appsv/rdb/src/main/resources/db/migration/y2020/v389__backup_test_log.sql:
--------------------------------------------------------------------------------
1 |
2 | alter table backup_test_log3 add column file_name varchar;
3 | alter table backup_test_log3 add constraint backuptestlog_c_filename_len check (
4 | length(file_name) between 1 and 200);
5 |
6 | alter table sites3 drop column price_plan;
7 |
--------------------------------------------------------------------------------
/appsv/rdb/src/main/resources/db/migration/y2020/v391__root_cat_slug.sql:
--------------------------------------------------------------------------------
1 | update categories3 set slug = '__root_cat_' || id
2 | where parent_id is null;
3 |
4 |
--------------------------------------------------------------------------------
/appsv/rdb/src/main/resources/db/migration/y2020/v392__cors_settings.sql:
--------------------------------------------------------------------------------
1 |
2 | alter table settings3 add column enable_cors boolean;
3 | alter table settings3 add column allow_cors_from varchar;
4 | alter table settings3 add column allow_cors_creds boolean;
5 | alter table settings3 add column cache_cors_prefl_secs int;
6 |
7 | alter table settings3 add constraint settings_c_allowcorsfrom_len check (
8 | length(allow_cors_from) between 1 and 1000);
9 |
10 |
--------------------------------------------------------------------------------
/appsv/rdb/src/main/resources/db/migration/y2020/v393__nav_conf_settings.sql:
--------------------------------------------------------------------------------
1 |
2 | alter table settings3 add column nav_conf jsonb;
3 | alter table settings3 add constraint settings_c_navconf_len check (
4 | pg_column_size(nav_conf) <= 50000);
5 |
6 |
--------------------------------------------------------------------------------
/appsv/rdb/src/main/resources/db/migration/y2020/v394__settings.sql:
--------------------------------------------------------------------------------
1 |
2 | alter table settings3 add column start_of_body_html varchar;
3 | alter table settings3 add constraint settings_c_startofbodyhtml_len check (
4 | length(start_of_body_html) between 1 and 50000);
5 |
6 | alter table user_stats3 add column snooze_notfs_until timestamp;
7 | alter table user_stats3 add column after_snooze_then int;
8 |
9 |
10 |
--------------------------------------------------------------------------------
/appsv/rdb/src/main/resources/db/migration/y2020/v399__site_feature_flags.sql:
--------------------------------------------------------------------------------
1 |
2 | alter table sites3 add column feature_flags_c varchar;
3 | alter table sites3 add constraint sites3_c_featureflags_len check (
4 | length(feature_flags_c) between 1 and 500);
5 |
--------------------------------------------------------------------------------
/appsv/rdb/src/main/resources/db/migration/y2020/v400__missing_fx_ix.sql:
--------------------------------------------------------------------------------
1 |
2 | create index postsread_i_readbyid on post_read_stats3 (site_id, user_id);
3 |
--------------------------------------------------------------------------------
/appsv/rdb/src/main/resources/db/migration/y2021/v404__profile_pic_length.sql:
--------------------------------------------------------------------------------
1 |
2 | -- A Google profile pic URL was 830 chars, so let's allow up to, hmm,
3 | -- 2100, because there has to be *some* max limit, and IE11 apparently cuts urls
4 | -- at 2083 chars (URL path max 2048 chars).
5 | -- https://support.microsoft.com/en-us/topic/maximum-url-length-is-2-083-characters-in-internet-explorer-174e7c8a-6666-f4e0-6fd6-908b53c12246
6 | --
7 | create domain pic_url_d as varchar;
8 | alter domain pic_url_d add constraint picurl_c_len_gz check (length(value) > 0);
9 | alter domain pic_url_d add constraint picurl_c_len_max check (length(value) <= 2100);
10 |
11 | alter table identities3 drop constraint idtys_c_pictureurl_len;
12 | alter table identities3 alter column picture_url_c type pic_url_d;
13 |
14 |
--------------------------------------------------------------------------------
/appsv/rdb/src/main/resources/db/migration/y2021/v407__upvote_features.adoc:
--------------------------------------------------------------------------------
1 | If any upgr problems, then:
2 |
3 | [source, sql]
4 | ----
5 | -- Left trim urls:
6 | update settings3 set sso_logout_redir_url_c = regexp_replace(
7 | sso_logout_redir_url_c, '^(.*)(https?:\/\/.*)$', '\2')
8 | where sso_logout_redir_url_c is not null;
9 | update settings3 set sso_refresh_authn_token_url_c = regexp_replace(
10 | sso_refresh_authn_token_url_c, '^(.*)(https?:\/\/.*)$', '\2')
11 | where sso_refresh_authn_token_url_c is not null;
12 |
13 | -- Fix hostname:
14 | update settings3 set sso_logout_redir_url_c = regexp_replace(
15 | sso_logout_redir_url_c,
16 | '^(https?:\/\/[a-z0-9_.-]+(:[0-9]+)?)[^/]*(.*)$', '\1\3')
17 | where sso_logout_redir_url_c is not null;
18 | update settings3 set sso_refresh_authn_token_url_c = regexp_replace(
19 | sso_refresh_authn_token_url_c,
20 | '^(https?:\/\/[a-z0-9_.-]+(:[0-9]+)?)[^/]*(.*)$', '\1\3')
21 | where sso_refresh_authn_token_url_c is not null;
22 | ----
23 |
--------------------------------------------------------------------------------
/appsv/rdb/src/main/resources/db/migration/y2021/v412__forum_search_box.sql:
--------------------------------------------------------------------------------
1 |
2 | alter table pages3 add column forum_search_box_c i16_gz_d;
3 | alter table pages3 add column forum_main_view_c i16_gz_d;
4 | alter table pages3 add column forum_cats_topics_c i32_gz_d;
5 |
--------------------------------------------------------------------------------
/appsv/rdb/src/main/resources/db/migration/y2022/v414__webhooks_constr.sql:
--------------------------------------------------------------------------------
1 |
2 |
3 | create domain jsonb_ste100_000_d jsonb;
4 | alter domain jsonb_ste100_000_d add
5 | constraint jsonb_ste100_000_d_c_ste100_000 check (pg_column_size(value) <= 100000);
6 |
7 | create domain jsonb_ste250_000_d jsonb;
8 | alter domain jsonb_ste250_000_d add
9 | constraint jsonb_ste250_000_d_c_ste250_000 check (pg_column_size(value) <= 250000);
10 |
11 | create domain jsonb_ste500_000_d jsonb;
12 | alter domain jsonb_ste500_000_d add
13 | constraint jsonb_ste500_000_d_c_ste500_000 check (pg_column_size(value) <= 500000);
14 |
15 | alter table webhook_reqs_out_t alter column sent_json_c type jsonb_ste500_000_d;
16 |
--------------------------------------------------------------------------------
/appsv/rdb/src/main/resources/db/migration/y2022/v415__drop_reply_at_constr.sql:
--------------------------------------------------------------------------------
1 |
2 | -- Was a too strict constraint. Sometimes an old comment gets moved to a new page,
3 | -- then its timestamps are older than the page.
4 | alter table pages3 drop constraint dw1_pages_createdat_replyat__c_le;
5 |
6 |
--------------------------------------------------------------------------------
/appsv/rdb/src/main/resources/db/migration/y2023/v421__sys_settings.sql:
--------------------------------------------------------------------------------
1 |
2 | alter table emails_out3 rename column id to email_id_c;
3 | alter table emails_out3 rename column type to out_type_c;
4 |
5 | alter table emails_out3
6 | alter column out_type_c type i16_gz_lt1000_d,
7 | add column out_sub_type_c i16_gz_lt1000_d,
8 | drop constraint emailsout_type__c_betw;
9 |
10 |
11 | create table system_settings_t (
12 | maintenance_until_unix_secs_c i64_gz_d
13 | );
14 |
15 |
16 | insert into system_settings_t (maintenance_until_unix_secs_c) values (null);
17 |
--------------------------------------------------------------------------------
/appsv/rdb/src/main/resources/db/migration/y2024/wip_v427__alias.sql:
--------------------------------------------------------------------------------
1 |
2 |
3 | alter table page_users3 add column prefer_alias_id_c pat_id_d;
4 | -- +
5 | -- fk deferred
6 | -- ix
7 |
8 |
--------------------------------------------------------------------------------
/appsv/rdb/src/main/resources/db/migration/y2999/wip_v41Y__samesite_none.sql:
--------------------------------------------------------------------------------
1 |
2 | create domain forgotten_d i16_d default 0;
3 | alter domain forgotten_d add
4 | constraint forgotten_d_c_in_0_1_2 check (value between 0 and 2);
5 |
6 | alter table sessions_t add column hash_4_ho_ss_none_c bytea_len32_d;
7 | alter table sessions_t rename column hash_4_http_only_c to hash_5_ho_ss_lax_c;
8 | alter table sessions_t rename column hash_5_strict_c to hash_6_ho_ss_strict_c;
9 |
10 | alter table sessions_t add column forgotten_c not null;
11 |
12 |
13 | create sessions_i_to_forget_a_bit on sessions_t (least(deleted_at_c, expired_at_c))
14 | where forgotten_c = 0;
15 |
16 | create sessions_i_to_forget_more on sessions_t (least(deleted_at_c, expired_at_c))
17 | where forgotten_c = 1;
18 |
19 | create sessions_i_ended_at on sessions_t (least(deleted_at_c, expired_at_c));
20 |
--------------------------------------------------------------------------------
/appsv/rdb/src/main/scala/db/migration/MigrationHelper.scala:
--------------------------------------------------------------------------------
1 | package db.migration
2 |
3 | import com.debiki.core.ScalaBasedDatabaseMigrations
4 | import com.debiki.dao.rdb.RdbSystemTransaction
5 |
6 | object MigrationHelper {
7 |
8 | var scalaBasedMigrations: ScalaBasedDatabaseMigrations = _
9 |
10 | /** Makes a SystemDbDao available to Flyway Java migrations (well, Scala not Java). */
11 | var systemDbDao: RdbSystemTransaction = _
12 |
13 | }
14 |
--------------------------------------------------------------------------------
/appsv/server/debiki/HtmlUtils.scala:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (C) 2012 Kaj Magnus Lindberg (born 1979)
3 | *
4 | * This program is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU Affero General Public License as
6 | * published by the Free Software Foundation, either version 3 of the
7 | * License, or (at your option) any later version.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU Affero General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU Affero General Public License
15 | * along with this program. If not, see
Hi @{member.nameOrUsername},
9 | 10 |11 | To login at @siteAddress, as @@@{member.username}, please follow 12 | 13 | this link. 14 | It expires in @expiresInMinutes minutes, and works just once. 15 |
16 | 17 |Kind regards.
18 |Hello,
7 | 8 |9 | You attempted to create a new account at @siteAddress, 10 | with email address @emailAddress, but you already have such an account.@* [2WABJDD4_] *@ 11 | If you don't remember your password, you can 12 | 13 | reset it here. 14 |
15 | 16 |Kind regards,
17 | Debiki
18 |
4 | Welcome to @siteHostname, @{newMember.nameOrUsername} 5 |
6 | 7 |Your account at @siteHostname has been approved. 8 | Now you can go there and talk with the others: 9 |
10 | 11 | 12 | 13 |Kind regards.
14 | 15 | -------------------------------------------------------------------------------- /appsv/server/views/createaccount/createAccountLinkEmail.scala.html: -------------------------------------------------------------------------------- 1 | @(siteAddress: String, username: String, safeVerificationUrl: String, expirationTimeInHours: Int, globals: debiki.Globals) 2 | 3 | @origin = @{ 4 | globals.originOf(siteAddress) 5 | } 6 | 7 | @* For links you don't want people to click, unless they know what they're doing. *@ 8 | @grayBoringLink(host: String) = { 9 | @host 10 | } 11 | 12 |Hello,
14 | 15 |@* About including @username, see: [20KCQ5Y] *@ 16 | To finish the creation of your account with username @username at @grayBoringLink(siteAddress), please click 17 | this link. 18 | It expires in @{expirationTimeInHours - 1} hours. 19 |
20 | 21 |
22 | Kind regards,
23 | Talkyard
24 |
4 | New member waiting for approval: 5 | @@@{user.usernameParensFullName} 6 |
7 | 8 |Go here to review and approve: 9 |
10 | 11 |@siteOrigin/-/admin/users/waiting
12 | 13 |Kind regards.
14 | 15 | -------------------------------------------------------------------------------- /appsv/server/views/createaccount/welcomePage.scala.html: -------------------------------------------------------------------------------- 1 | @(tpi: debiki.SiteTpi, returnToUrl: Option[String]) 2 | 3 | 4 | @css = @{(""" 5 | 6 | """)} 7 | 8 | @returnToUrlUnescapedHash = @{ 9 | returnToUrl.map(_.replaceAllLiterally("__dwHash__", "#")) 10 | } 11 | @views.html.createsite.main(tpi, css = css) { 12 |You have verified your email address. You are now logged in.
16 | 17 |18 | Continue... 20 |
21 | 22 | } 23 | 24 | -------------------------------------------------------------------------------- /appsv/server/views/createsite/welcomeEmail.scala.html: -------------------------------------------------------------------------------- 1 | // Oops, not in use [welc_em_0used] 2 | @() 3 | @* 4 | @(site: com.debiki.core.Tenant, userName: String) 5 | 6 | @import controllers.CreateEmbeddedSiteController 7 | @import debiki.HtmlUtils.link 8 | 9 | @embeddingSiteUrl = @{ site.embeddingSiteUrl.get } 10 | @adminUrl = @{ CreateEmbeddedSiteController.adminUrlForEmbeddedSite(site.id) } 11 | 12 | @embeddedCommentsInstructionsUrl = @{ 13 | val embeddedSiteOrigin = debiki.Globals.siteByIdOrigin(site.id) 14 | embeddedSiteOrigin + routes.CreateEmbeddedSiteController.embeddingSiteInstructionsPage() 15 | } 16 | 17 |Hi @userName,
19 | 20 |Embedded comments have been setup for your website at @embeddingSiteUrl.
21 | 22 |Please find here getting started instructions:
23 | 24 | Instructions 25 | 26 |You can log in and administrate comments here:
27 | 28 |@link(adminUrl)
29 | 30 |Kind regards, Debiki
31 | www.debiki.com
32 |
Hi,
4 | 5 |You previously invited @{invitedEmailAddress} to join @siteHostname, 6 | and now he or she has accepted your invite (that is, he or she clicked 7 | the link in the invite email). 8 |
9 | 10 |Kind regards.
11 | 12 | -------------------------------------------------------------------------------- /appsv/server/views/invite/inviteEmail.scala.html: -------------------------------------------------------------------------------- 1 | @(inviterName: String, siteHostname: String, probablyUsername: String, secretKey: String, globals: debiki.Globals) 2 | 3 | @siteUrl = @{ globals.originOf(siteHostname) } 4 | 5 | @acceptInviteUrl = @{ 6 | val origin = globals.originOf(siteHostname) 7 | s"$origin${controllers.routes.InviteController.acceptInvite(secretKey)}" 8 | } 9 | 10 |Hi,
11 | 12 |@inviterName invites you to join@* [5FJBAW2_] *@ @siteHostname.
@* I18N *@ 13 | 14 |Click the link below, if you are interested:
15 | 16 | 17 | 18 |An account will then be created for you and you will be logged in, automatically. 19 | Your username will be @probablyUsername (if available, and you can change it later). 20 | We will also send you a choose-password email. 21 |
22 | 23 |Kind regards
24 | 25 | 26 | -------------------------------------------------------------------------------- /appsv/server/views/invite/welcomeSetPasswordEmail.scala.html: -------------------------------------------------------------------------------- 1 | @(siteHostname: String, setPasswordUrl: String, username: String, globals: debiki.Globals) 2 | 3 |Welcome to @siteHostname! And thanks for accepting the invitation.@* [5FJB2AZY_] I18N *@
4 | 5 |We have created an account for you, with username @username. 6 | Please login with that username or your email address. 7 | And you need a password; click the link below to choose a password:
8 | 9 | 10 | 11 |Kind regards
12 | 13 | -------------------------------------------------------------------------------- /appsv/server/views/login/accountsLinkedPleaseLoginAgain.scala.html: -------------------------------------------------------------------------------- 1 | @(tpi: debiki.SiteTpi, origNonceBack: String, tryLoginAgainUrl: String, idpName: String) 2 | 3 | @css = @{(""" 4 | """)} 5 | 6 | @* SECURITY SHOULD compare origNonceBack with the local storage nonce, and 7 | generate a new nonce and use in loginUrlNewNonce below. [br_authn_nonce] 8 | *@ 9 | @tryAgainUrlNewNonce = @{ 10 | tryLoginAgainUrl 11 | } 12 | 13 | @views.html.createsite.main(tpi, css = css) { 14 | 15 |19 | Log in again over at @idpName, please — this time, should work directly: 20 |
21 | 22 |23 | Login again 24 |
25 | 26 | } 27 | 28 | -------------------------------------------------------------------------------- /appsv/server/views/login/accountsNotLinkedPleaseLoginAgain.scala.html: -------------------------------------------------------------------------------- 1 | @(tpi: debiki.SiteTpi, origNonceBack: String, tryLoginAgainUrl: String, idpName: String) 2 | 3 | @css = @{(""" 4 | """)} 5 | 6 | @* SECURITY SHOULD compare origNonceBack with the local storage nonce, and 7 | generate a new nonce and use in loginUrlNewNonce below. [br_authn_nonce] 8 | *@ 9 | @tryAgainUrlNewNonce = @{ 10 | tryLoginAgainUrl 11 | } 12 | 13 | @views.html.createsite.main(tpi, css = css) { 14 | 15 |19 | Would you like to log in again, over at @idpName — 20 | with a different account this time? Or create a new? 21 |
22 | 23 |24 | Login again 25 |
26 | 27 |28 | @* UX SHOULD skip this for embedded comments pages? Then don't know what's at: / 29 | at the embedding website. *@ 30 | Go to topic list page / Home 31 |
32 | 33 | } 34 | 35 | -------------------------------------------------------------------------------- /appsv/server/views/login/verifyYourEmailAddr.scala.html: -------------------------------------------------------------------------------- 1 | @(tpi: debiki.SiteTpi, subject: String, emailToVerify: String, expMins: Int) 2 | 3 | @css = @{(""" 4 | """)} 5 | 6 | @views.html.createsite.main(tpi, css = css) { 7 | 8 |We sent you an email, title: @subject 12 | 13 |
Check your email inbox: @emailToVerify
14 | 15 |You can close this page.
16 | The link in the email expires in @expMins minutes.
17 |
Hi @name,
5 | 6 |7 | You (or someone else) are logging in at @siteAddr 8 | — please click this link, to verify your email address. 9 |
10 | 11 |(If you don't know what this is about, please ignore this email.)
12 | 13 |Kind regards. 14 |
15 |Hi @userName,
9 | 10 |11 | To reset your password at @siteAddress, please follow @* [RSTPWDLNK] *@ 12 | 13 | this link. It expires in @expiresInMinutes minutes. 14 |
15 | 16 |Kind regards.
17 |
You have been unsubscribed.
6 | 7 | @* This is confusing, for embedded comments sites — then should link back to the blog, 8 | instead of to the embedded site. So remove for now: 9 | 10 | *@ 11 | 12 | 13 | -------------------------------------------------------------------------------- /client/app-editor/editor-bundle-already-loaded.d.ts: -------------------------------------------------------------------------------- 1 | 2 | // Things in editor-bundle.js that we can access from outside the bundle, 3 | // once it's been loaded already. 4 | 5 | declare namespace debiki2.editor { 6 | 7 | function getOrCreateEditor(success: (editor: any) => void); 8 | 9 | function markdownToSafeHtml(source: string, hostAndPort?, sanitizerOptions?): string; 10 | 11 | } 12 | 13 | // vim: fdm=marker et ts=2 sw=2 tw=0 fo=r list 14 | -------------------------------------------------------------------------------- /client/app-editor/editor-prelude.editor.ts: -------------------------------------------------------------------------------- 1 | ///