├── .dockerignore ├── .github └── workflows │ ├── phpmd.yml │ └── snyk-security.yml ├── .gitignore ├── CONTRIBUTING.md ├── Dockerfile ├── LICENSE ├── README.md ├── app ├── Announce.php ├── Api │ ├── Base.php │ ├── Better.php │ ├── BonusPoints.php │ ├── Collages.php │ ├── Creators.php │ ├── Friends.php │ ├── Groups.php │ ├── Internal.php │ ├── Meta.php │ ├── Requests.php │ ├── Top10.php │ ├── Torrents.php │ └── Wiki.php ├── App.php ├── Auth.php ├── AutoEnable.php ├── Autocomplete.php ├── Badges.php ├── Better.php ├── BonusPoints.php ├── Bookmarks.php ├── Cache.php ├── Crossref.php ├── Crypto.php ├── Database.php ├── DatabaseOld.php ├── Debug.php ├── Discourse.php ├── ENV.php ├── Escape.php ├── Exception.php ├── Feed.php ├── Format.php ├── Forums.php ├── Friends.php ├── Http.php ├── INVITE_TREE.php ├── Images.php ├── Inbox.php ├── LazyCollection.php ├── LockedAccounts.php ├── Manticore.php ├── Misc.php ├── Models │ ├── Collages.php │ ├── Conversations.php │ ├── Creators.php │ ├── Literature.php │ ├── Messages.php │ ├── ObjectCrud.php │ ├── Organizations.php │ ├── Publications.php │ ├── Requests.php │ ├── Roles.php │ ├── SiteLog.php │ ├── Tags.php │ ├── TorrentGroups.php │ ├── Torrents.php │ ├── Users.php │ └── Wiki.php ├── Ncbi.php ├── NotificationsManager.php ├── NotificationsManagerView.php ├── OpenAI.php ├── OpenAlex.php ├── Permissions.php ├── RecursiveCollection.php ├── Reports.php ├── ResearchOrganizationRegistry.php ├── RevisionHistory.php ├── RevisionHistoryView.php ├── SemanticScholar.php ├── Stats.php ├── Subscriptions.php ├── Text.php ├── Tools.php ├── Top10.php ├── TorrentFunctions.php ├── TorrentsDL.php ├── Tracker.php ├── TrackerOld.php ├── Twig.php ├── UserOld.php ├── UserRank.php ├── Validate.php ├── View.php ├── WebAuthn │ ├── Base.php │ ├── CredentialSourceRepository.php │ └── UserEntityRepository.php ├── Zip.php ├── bencode.class.php ├── bencodedecode.class.php ├── bencodetorrent.class.php └── torrent.class.php ├── bootstrap ├── api.php ├── autoload.php ├── cli.php ├── utilities.php └── web.php ├── composer.json ├── composer.lock ├── config ├── app.php ├── badges.php ├── metadata.php ├── metadataOld.php ├── privateExample.php ├── public.php └── regex.php ├── cron ├── database ├── migrations │ ├── 20240522015737_database_cleanup.php │ ├── 20240522024536_reset_wiki_permissions.php │ ├── 20240522191136_json_tags.php │ ├── 20240522203651_chihaya_tables.php │ ├── 20240601175337_hydrate_slug_columns.php │ ├── 20240601191838_fill_zero_ids.php │ ├── 20240602161518_organizations_tables.php │ ├── 20240602205342_generic_linking_tables.php │ └── 20240603180418_hydrate_organizations_table.php └── migrationsOld │ ├── 20230513020218_web_authn.php │ ├── 20230919194636_reconstruct_badges_table.php │ ├── 20240221150928_hydrate_roles_permissions.php │ ├── 20240520211747_migrate_creators.php │ └── 20240522001652_short_uuid.php ├── design ├── privateheader.php └── views │ └── generic │ └── reply │ └── staffpm.php ├── docker-compose.yml ├── package-lock.json ├── package.json ├── phinx.php ├── public ├── css │ └── vendor │ │ ├── easymde.min.css │ │ ├── highlight.min.css │ │ ├── leaflet │ │ ├── images │ │ │ ├── layers-2x.png │ │ │ ├── layers.png │ │ │ ├── marker-icon-2x.png │ │ │ ├── marker-icon.png │ │ │ └── marker-shadow.png │ │ ├── leaflet-src.esm.js │ │ ├── leaflet-src.esm.js.map │ │ ├── leaflet-src.js │ │ ├── leaflet-src.js.map │ │ ├── leaflet.css │ │ ├── leaflet.js │ │ └── leaflet.js.map │ │ ├── normalize.min.css │ │ ├── skeleton.min.css │ │ ├── sortable-theme-minimal.css │ │ └── tom-select.bootstrap5.min.css ├── feeds.php ├── image.php ├── images │ ├── avatars │ │ └── default.webp │ ├── forums │ │ ├── go_last_read.png │ │ ├── hide.png │ │ ├── locked_read.png │ │ ├── locked_sticky_read.png │ │ ├── locked_sticky_unread.png │ │ ├── locked_unread.png │ │ ├── read.png │ │ ├── show.png │ │ ├── sticky_read.png │ │ ├── sticky_unread.png │ │ └── unread.png │ ├── icons │ │ ├── archive.webp │ │ ├── externalLink.svg │ │ ├── fa-cloud.svg │ │ ├── rss.webp │ │ └── version.webp │ ├── logos │ │ ├── colorfulWaves-whiteShadow-2k.webp │ │ ├── doi.svg │ │ ├── grid.webp │ │ ├── openAccess.svg │ │ ├── openAlex.webp │ │ ├── orcid.webp │ │ ├── patreon.webp │ │ ├── ror.svg │ │ ├── sci-hub.webp │ │ ├── semanticScholar.webp │ │ ├── simpleFavicon-2k.webp │ │ └── torrents.bio.webp │ ├── mascot.webp │ ├── mascotFullVersion.webp │ ├── noartwork.webp │ ├── oink.webp │ └── plausibleOptOut.webp ├── index.php ├── js │ └── vendor │ │ ├── chart.min.js │ │ ├── chartjs-chart-geo.min.js │ │ ├── chartjs-chart-graph.min.js │ │ ├── chartjs-chart-wordcloud.js │ │ ├── easymde.min.js │ │ ├── highlight.min.js │ │ ├── instantpage.min.js │ │ ├── jquery.min.js │ │ ├── leaflet │ │ ├── images │ │ │ ├── layers-2x.png │ │ │ ├── layers.png │ │ │ ├── marker-icon-2x.png │ │ │ ├── marker-icon.png │ │ │ └── marker-shadow.png │ │ ├── leaflet-src.esm.js │ │ ├── leaflet-src.esm.js.map │ │ ├── leaflet-src.js │ │ ├── leaflet-src.js.map │ │ ├── leaflet.css │ │ ├── leaflet.js │ │ └── leaflet.js.map │ │ ├── lodash.core.min.js │ │ ├── lodash.min.js │ │ ├── noty │ │ ├── jquery.noty.js │ │ ├── layouts │ │ │ ├── bottom.js │ │ │ ├── bottomCenter.js │ │ │ ├── bottomLeft.js │ │ │ ├── bottomRight.js │ │ │ ├── center.js │ │ │ ├── centerLeft.js │ │ │ ├── centerRight.js │ │ │ ├── inline.js │ │ │ ├── top.js │ │ │ ├── topCenter.js │ │ │ ├── topLeft.js │ │ │ └── topRight.js │ │ ├── packaged │ │ │ ├── jquery.noty.packaged.js │ │ │ └── jquery.noty.packaged.min.js │ │ ├── promise.js │ │ └── themes │ │ │ ├── bootstrap.js │ │ │ ├── default.js │ │ │ ├── metroui.js │ │ │ ├── relax.js │ │ │ └── semanticUI.js │ │ ├── simplewebauthn.min.js │ │ ├── smartquotes.min.js │ │ ├── sortable.min.js │ │ ├── starboard-wrap.js │ │ ├── tom-select.base.min.js │ │ └── typeahead.bundle.min.js └── opensearch.xml ├── resources ├── buildAssets.sh ├── js │ ├── ajax.class.js │ ├── browse.js │ ├── collage.js │ ├── conversations.js │ ├── cover_art.js │ ├── enable_requests.js │ ├── global.js │ ├── literature.js │ ├── news_ajax.js │ ├── notifications.js │ ├── recommend.js │ ├── reports.js │ ├── reportsv2.js │ ├── requests.js │ ├── staffpm.js │ ├── subscriptions.js │ ├── torrent.js │ ├── upload.js │ ├── user.js │ ├── user_notifications.js │ ├── webAuthnAssert.js │ ├── webAuthnCreate.js │ └── wiki.js ├── php │ └── wordlist.php └── scss │ ├── assets.scss │ ├── assets │ ├── colors.scss │ ├── fonts.scss │ └── icons.scss │ ├── bookish.scss │ ├── bookish │ ├── bookish.scss │ ├── colors.scss │ ├── debug.scss │ ├── fonts.scss │ ├── images │ │ └── sam-komon.png │ ├── layout.scss │ ├── matcha.scss │ └── tables.scss │ ├── development.scss │ ├── development │ └── development.scss │ ├── global.scss │ ├── global │ ├── colors.scss │ ├── fonts.scss │ ├── footer.scss │ ├── forms.scss │ ├── layout.scss │ ├── mainMenu.scss │ ├── skeletonFixes.scss │ ├── tables.scss │ ├── torrents.scss │ └── user.scss │ ├── postmod.scss │ ├── postmod │ ├── colors.scss │ ├── images │ │ ├── Akzidenz.otf │ │ ├── Avant.otf │ │ ├── CorpidOffice.ttf │ │ ├── Officina.otf │ │ ├── alert-overlay.png │ │ ├── bg_footer.png │ │ ├── bg_header.png │ │ ├── bg_inputs.png │ │ ├── bg_menu.png │ │ ├── body.jpg │ │ ├── content.png │ │ ├── content_light.png │ │ ├── external.png │ │ ├── gazelle.png │ │ ├── go_last_read.png │ │ ├── hide.png │ │ ├── leechers.png │ │ ├── load.gif │ │ ├── locked_read.png │ │ ├── locked_sticky_read.png │ │ ├── locked_sticky_unread.png │ │ ├── locked_unread.png │ │ ├── logo.png │ │ ├── nav_matrix.png │ │ ├── nav_matrix_extended.png │ │ ├── nu_nav_matrix.png │ │ ├── poll_left.png │ │ ├── poll_middle.png │ │ ├── poll_right.png │ │ ├── read.png │ │ ├── seeders.png │ │ ├── show.png │ │ ├── snatched.png │ │ ├── sticky_read.png │ │ ├── sticky_unread.png │ │ ├── table_header.png │ │ ├── table_header_dark.png │ │ ├── unread.png │ │ ├── wood.jpg │ │ ├── woodlogo.png │ │ ├── woodlogo.png2 │ │ └── wrapper.png │ ├── layout.scss │ ├── menus.scss │ └── postmod.scss │ ├── public.scss │ ├── public │ └── public.scss │ └── sidebar.scss ├── routes ├── api.php ├── api │ ├── better.php │ ├── bonusPoints.php │ ├── collages.php │ ├── creators.php │ ├── discourse.php │ ├── friends.php │ ├── groups.php │ ├── meta.php │ ├── requests.php │ ├── top10.php │ ├── torrents.php │ └── wiki.php ├── apiAuthentication.php ├── internal.php ├── web.php └── web │ ├── better.php │ ├── bonusPoints.php │ ├── collages.php │ ├── conversations.php │ ├── creators.php │ ├── discourse.php │ ├── feeds.php │ ├── literature.php │ ├── organizations.php │ ├── publications.php │ ├── requests.php │ ├── rules.php │ ├── siteLog.php │ ├── siteText.php │ ├── stats.php │ ├── toolbox.php │ ├── top10.php │ ├── torrentGroups.php │ ├── torrents.php │ ├── user.php │ ├── userAuth.php │ └── wiki.php ├── sections ├── api │ ├── announcements.php │ ├── artist.php │ ├── bookmarks │ │ ├── artists.php │ │ ├── index.php │ │ └── torrents.php │ ├── clear_user_notification.php │ ├── collage.php │ ├── get_user_notifications.php │ ├── inbox │ │ ├── inbox.php │ │ ├── index.php │ │ └── viewconv.php │ ├── info.php │ ├── notifications.php │ ├── request.php │ ├── routerOld.php │ ├── subscriptions.php │ ├── tcomments.php │ ├── top10 │ │ ├── index.php │ │ ├── tags.php │ │ ├── torrents.php │ │ └── users.php │ ├── torrents │ │ ├── group.php │ │ └── torrent.php │ ├── user.php │ └── user_recents.php ├── artist │ ├── change_artistid.php │ ├── download.php │ ├── edit.php │ ├── notify.php │ ├── notifyremove.php │ ├── rename.php │ ├── router.php │ └── takeedit.php ├── better │ ├── badFolders.php │ ├── badTags.php │ ├── missingCitations.php │ ├── missingPictures.php │ └── singleSeeder.php ├── blog │ └── router.php ├── bonusPoints │ ├── checkout.php │ ├── confirm.php │ ├── freeleechpool.php │ ├── promotion.php │ └── store.php ├── bookmarks │ ├── add.php │ ├── artists.php │ ├── remove.php │ ├── router.php │ └── torrents.php ├── collages │ ├── add_torrent.php │ ├── artist_collage.php │ ├── browse.php │ ├── delete.php │ ├── details.php │ ├── download.php │ ├── edit.php │ ├── edit_handle.php │ ├── manage.php │ ├── manage_handle.php │ ├── new_handle.php │ └── updateOrCreate.php ├── comments │ └── router.php ├── commentsOld │ ├── comments.php │ ├── get.php │ ├── take_delete.php │ ├── take_edit.php │ ├── take_post.php │ ├── take_warn.php │ └── warn.php ├── conversations │ ├── createMessage.php │ └── user.php ├── creators │ ├── browse.php │ ├── delete.php │ └── details.php ├── discourse │ ├── boards │ │ ├── category.php │ │ ├── index.php │ │ ├── newEdit.php │ │ └── topic.php │ ├── connect │ │ └── connect.php │ ├── messages │ │ └── index.php │ └── wiki │ │ └── index.php ├── feeds │ └── index.php ├── forums │ └── router.php ├── forumsOld │ ├── add_poll_option.php │ ├── catchup.php │ ├── change_vote.php │ ├── delete.php │ ├── delete_poll_option.php │ ├── forum.php │ ├── get_post.php │ ├── main.php │ ├── mod_thread.php │ ├── newthread.php │ ├── poll_mod.php │ ├── poll_vote.php │ ├── search.php │ ├── sticky_post.php │ ├── take_new_thread.php │ ├── take_reply.php │ ├── take_topic_notes.php │ ├── take_warn.php │ ├── takeedit.php │ ├── thread.php │ └── warn.php ├── image │ ├── err_imgs │ │ ├── badprotocol.png │ │ ├── forbidden.png │ │ ├── invalid.png │ │ ├── invisible.png │ │ ├── nogd.png │ │ ├── small.png │ │ └── timeout.png │ └── router.php ├── inbox │ ├── compose.php │ ├── conversation.php │ ├── forward.php │ ├── get_post.php │ ├── inbox.php │ ├── massdelete_handle.php │ ├── takecompose.php │ └── takeedit.php ├── index │ └── private.php ├── literature │ ├── browse.php │ └── details.php ├── log │ ├── index.php │ ├── sphinx.php │ └── sql.php ├── organizations │ ├── browse.php │ └── details.php ├── publications │ ├── browse.php │ └── details.php ├── reports │ ├── ajax_add_notes.php │ ├── ajax_claim_report.php │ ├── ajax_resolve_report.php │ ├── ajax_unclaim_report.php │ ├── array.php │ ├── compose.php │ ├── report.php │ ├── reports.php │ ├── router.php │ ├── stats.php │ ├── takecompose.php │ ├── takereport.php │ └── takeresolve.php ├── reportsv2 │ ├── ajax_change_resolve.php │ ├── ajax_create_report.php │ ├── ajax_giveback_report.php │ ├── ajax_grab_report.php │ ├── ajax_new_report.php │ ├── ajax_report.php │ ├── ajax_take_pm.php │ ├── ajax_update_comment.php │ ├── ajax_update_resolve.php │ ├── array.php │ ├── header.php │ ├── report.php │ ├── reports.php │ ├── router.php │ ├── search.php │ ├── static.php │ ├── takereport.php │ ├── takeresolve.php │ └── views.php ├── requests │ ├── browse.php │ ├── details.php │ ├── take_delete.php │ ├── take_fill.php │ ├── take_new_edit.php │ ├── take_unfill.php │ └── updateOrCreate.php ├── snatchlist │ └── router.php ├── staffpm │ ├── ajax_delete_response.php │ ├── ajax_edit_response.php │ ├── ajax_get_response.php │ ├── ajax_preview_response.php │ ├── assign.php │ ├── common_responses.php │ ├── get_post.php │ ├── multiresolve.php │ ├── resolve.php │ ├── router.php │ ├── staff_inbox.php │ ├── takepost.php │ ├── unresolve.php │ ├── user_inbox.php │ └── viewconv.php ├── stats │ ├── torrents.php │ └── users.php ├── toolbox │ ├── clientWhitelist.php │ ├── collageRecovery.php │ ├── data │ │ ├── invite_pool.php │ │ ├── ocelot_info.php │ │ ├── registration_log.php │ │ └── upscale_pool.php │ ├── databaseKey.php │ ├── development │ │ ├── misc_values.php │ │ └── service_stats.php │ ├── managers │ │ ├── ajax_take_enable_request.php │ │ ├── bans.php │ │ ├── email_blacklist.php │ │ ├── email_blacklist_alter.php │ │ ├── email_blacklist_search.php │ │ ├── enable_requests.php │ │ ├── forum_alter.php │ │ ├── forum_list.php │ │ ├── global_notification.php │ │ ├── login_watch.php │ │ ├── mass_pm.php │ │ ├── multiple_freeleech.php │ │ ├── news.php │ │ ├── ocelot.php │ │ ├── official_tags.php │ │ ├── sitewide_freeleech.php │ │ ├── tag_aliases.php │ │ ├── take_global_notification.php │ │ ├── take_mass_pm.php │ │ ├── tokens.php │ │ └── whitelist_alter.php │ ├── misc │ │ ├── manipulate_tree.php │ │ ├── quick_ban.php │ │ └── tags.php │ ├── roles │ │ ├── createUpdate.php │ │ └── listAll.php │ └── routerOld.php ├── top10 │ ├── tags.php │ ├── torrents.php │ └── users.php ├── torrentGroups │ ├── add_alias.php │ ├── add_cover_art.php │ ├── browse.php │ ├── create.php │ ├── delete.php │ ├── delete_alias.php │ ├── details.php │ ├── downloadlist.php │ ├── editgroupid.php │ ├── history.php │ ├── manage_artists.php │ ├── merge.php │ ├── nonwikiedit.php │ ├── remove_cover_art.php │ ├── rename.php │ ├── screenshotedit.php │ ├── takedelete.php │ ├── takegroupedit.php │ └── update.php ├── torrents │ ├── delete.php │ ├── details.php │ ├── download.php │ ├── downloadlist.php │ ├── masspm.php │ ├── notify.php │ ├── notify_actions.php │ ├── peerlist.php │ ├── redownload.php │ ├── reseed.php │ ├── snatchlist.php │ ├── takechangecategory.php │ ├── takedelete.php │ ├── takeedit.php │ ├── takemasspm.php │ ├── update.php │ └── user.php ├── upload │ ├── router.php │ ├── upload.php │ └── upload_handle.php ├── user │ ├── advancedsearch.php │ ├── auth │ │ ├── confirm.php │ │ ├── disabled.php │ │ ├── login.php │ │ ├── recover.php │ │ ├── register.php │ │ └── resend.php │ ├── delete_invite.php │ ├── edit.php │ ├── friends.php │ ├── invite.php │ ├── invitetree.php │ ├── linkedfunctions.php │ ├── manage_linked.php │ ├── notify_edit.php │ ├── notify_handle.php │ ├── permissions.php │ ├── points.php │ ├── router.php │ ├── sessions.php │ ├── staff.php │ ├── take_invite.php │ ├── takemoderate.php │ └── user.php ├── userhistory │ ├── catchup.php │ ├── catchup_collages.php │ ├── collage_subscribe.php │ ├── comments_subscribe.php │ ├── ip_tracker_history.php │ ├── post_history.php │ ├── quote_notifications.php │ ├── router.php │ ├── subscribed_collages.php │ ├── subscriptions.php │ ├── thread_subscribe.php │ └── token_history.php └── wiki │ ├── article.php │ ├── browse.php │ ├── compare.php │ ├── create.php │ └── delete.php ├── shell ├── templates ├── _base │ ├── alertBars.twig │ ├── breadcrumbs.twig │ ├── conversation.twig │ ├── footer.twig │ ├── linkObjects.twig │ ├── mainMenu.twig │ ├── metaTags.twig │ ├── publicHeader.twig │ ├── starboardNotebook.twig │ ├── textarea.twig │ └── userInfo.twig ├── admin │ ├── advanced-user-search.twig │ ├── announcekey-history.twig │ ├── bonus-stats.twig │ ├── cache-management.twig │ ├── changelog.twig │ ├── clientWhitelist.twig │ ├── databaseKey.twig │ ├── duplicate-ipaddr.twig │ ├── emailBlacklist.twig │ ├── history-ip-tracker.twig │ ├── login-watch.twig │ ├── miscValues.twig │ ├── notification-sandbox.twig │ ├── ratio-watch.twig │ ├── registration.twig │ ├── roles │ │ ├── createUpdate.twig │ │ └── listAll.twig │ ├── sidebar.twig │ ├── site-info-userrank.twig │ ├── site-option.twig │ ├── siteNews.twig │ ├── staffpm-list.twig │ ├── tools.twig │ ├── tracker-info.twig │ ├── user-custom-permission.twig │ ├── user-info-ipv4.twig │ └── userflow.twig ├── artist │ └── similar.twig ├── base.twig ├── better │ ├── index.twig │ ├── list.twig │ └── sidebar.twig ├── bonusPoints │ ├── bonus-pool.twig │ ├── checkout.twig │ ├── confirm.twig │ ├── sidebar.twig │ └── store.twig ├── bookmark │ ├── body.twig │ ├── footer.twig │ ├── header.twig │ └── none.twig ├── collages │ ├── browse.twig │ ├── details.twig │ ├── search.twig │ ├── sidebar.twig │ └── updateOrCreate.twig ├── collector.twig ├── comment │ ├── comment.twig │ └── warn.twig ├── creators │ ├── browse.twig │ ├── details.twig │ ├── search.twig │ └── sidebar.twig ├── discourse │ ├── boards │ │ ├── category.twig │ │ ├── index.twig │ │ ├── newEdit.twig │ │ ├── sidebar.twig │ │ └── topic.twig │ ├── messages │ │ ├── index.twig │ │ └── sidebar.twig │ └── wiki │ │ └── index.twig ├── email │ ├── changeEmail.twig │ ├── disableWarning.twig │ ├── emailChanged.twig │ ├── enableAccepted.twig │ ├── enableDeclined.twig │ ├── hackedAccount.twig │ ├── inviteMember.twig │ ├── passphraseChanged.twig │ ├── passphraseReset.twig │ └── verifyRegistration.twig ├── error.twig ├── forum │ ├── header-thread.twig │ ├── header.twig │ ├── main.twig │ ├── new-thread.twig │ ├── request-edit.twig │ ├── toc.twig │ └── warn.twig ├── inbox │ └── compose.twig ├── index │ ├── private.twig │ └── sidebar.twig ├── literature │ ├── browse.twig │ ├── details.twig │ ├── search.twig │ └── sidebar.twig ├── manticore │ ├── complexSearch.twig │ ├── dataSize.twig │ ├── files.twig │ ├── formControls.twig │ ├── formats.twig │ ├── misc.twig │ ├── numbers.twig │ ├── ordering.twig │ ├── organization.twig │ ├── pagination.twig │ ├── people.twig │ ├── places.twig │ ├── platforms.twig │ ├── relationships.twig │ ├── simpleSearch.twig │ └── tracker.twig ├── organizations │ ├── browse.twig │ ├── details.twig │ ├── search.twig │ └── sidebar.twig ├── publications │ ├── browse.twig │ ├── details.twig │ ├── search.twig │ └── sidebar.twig ├── reportsv2 │ └── new.twig ├── requests │ ├── browse.twig │ ├── details.twig │ ├── edit-bounty.twig │ ├── search.twig │ ├── sidebarDetails.twig │ ├── sidebarForm.twig │ ├── tableEntry.twig │ └── updateOrCreate.twig ├── siteLog │ ├── index.twig │ └── sidebar.twig ├── siteText │ ├── donate │ │ └── donate.md │ ├── legal │ │ ├── about.md │ │ ├── canary.txt │ │ ├── dmca.md │ │ ├── privacy.md │ │ └── pubkey.txt │ ├── rules.twig │ ├── rules │ │ ├── chat.md │ │ ├── clients.twig │ │ ├── collages.md │ │ ├── golden.md │ │ ├── ratio.twig │ │ ├── requests.md │ │ ├── sidebar.twig │ │ ├── tags.md │ │ └── upload.md │ └── tldr.twig ├── stats │ ├── concepts.twig │ ├── countsByYear.twig │ ├── torrents.twig │ └── users.twig ├── tables │ ├── collages.twig │ ├── creators.twig │ ├── literature.twig │ ├── organizations.twig │ ├── requests.twig │ ├── searchSemanticScholar.twig │ ├── torrentGroups.twig │ └── torrents.twig ├── tag │ ├── alias.twig │ ├── batch-editor.twig │ └── merged.twig ├── top10 │ ├── sidebar.twig │ ├── tags.twig │ ├── torrents.twig │ └── users.twig ├── torrentForm │ ├── announceSource.twig │ ├── archive.twig │ ├── booleans.twig │ ├── categoryId.twig │ ├── creatorList.twig │ ├── formats.twig │ ├── freeleech.twig │ ├── groupDescription.twig │ ├── identifier.twig │ ├── license.twig │ ├── literature.twig │ ├── location.twig │ ├── mirrors.twig │ ├── notice.twig │ ├── picture.twig │ ├── platforms.twig │ ├── scopes.twig │ ├── seqhash.twig │ ├── sidebar.twig │ ├── tagList.twig │ ├── titles.twig │ ├── torrentDescription.twig │ ├── torrentFile.twig │ ├── version.twig │ ├── workgroup.twig │ └── year.twig ├── torrentGroups │ ├── browse.twig │ ├── details.twig │ ├── search.twig │ ├── sidebar.twig │ └── update.twig ├── torrents │ ├── details.twig │ ├── peerlist.twig │ ├── sidebar.twig │ └── upload.twig ├── user │ ├── auth │ │ ├── confirm.twig │ │ ├── disabled.twig │ │ ├── login.twig │ │ ├── recover.twig │ │ └── register.twig │ ├── bonus-history.twig │ ├── edit-buffer.twig │ ├── edit-fltoken.twig │ ├── edit-invite.twig │ ├── edit-lock.twig │ ├── edit-peer-visibility.twig │ ├── edit-rate-limit.twig │ ├── edit-remark.twig │ ├── edit-reset.twig │ ├── edit-secondary-class.twig │ ├── edit-submit.twig │ ├── edit-title.twig │ ├── edit-warn.twig │ ├── friends.twig │ ├── history-freeleech.twig │ ├── invite-tree-bulkedit.twig │ ├── invite-tree.twig │ ├── invited.twig │ ├── linked.twig │ ├── post-history.twig │ ├── privilege-list.twig │ ├── profile │ │ ├── invites.twig │ │ ├── profile.twig │ │ └── sidebar.twig │ ├── quote-notification.twig │ ├── recent.twig │ ├── reset-avatar.twig │ ├── session.twig │ ├── settings │ │ ├── notification.twig │ │ ├── settings.twig │ │ └── sidebar.twig │ ├── sidebar.twig │ ├── staff.twig │ ├── tag-snatch.twig │ └── thread-history.twig └── wiki │ ├── article.twig │ ├── browse.twig │ ├── compare.twig │ └── sidebar.twig ├── tests ├── app │ └── AppTest.php └── go.php ├── utilities ├── config │ ├── crontab.txt │ ├── manticore.conf │ └── nginx.conf ├── crontab │ ├── daily │ │ ├── class_demotions.php │ │ ├── jwtKeyPair.php │ │ ├── openAi.php │ │ ├── ratioRequirements.php │ │ ├── ratioWatch.php │ │ ├── resolveStaffPMs.php │ │ └── semanticScholar.php │ ├── every │ │ ├── bonusPointFreeleeches.php │ │ ├── expireFreeleechTokens.php │ │ ├── lastCommit.php │ │ ├── peerUpdate.php │ │ └── sixHourFreeleeches.php │ ├── hourly │ │ ├── automatedBadges.php │ │ ├── bonusPoints.php │ │ ├── classPromotions.php │ │ ├── deleteDeadPeers.php │ │ ├── deleteDeadSessions.php │ │ ├── deleteExpiredInvites.php │ │ ├── deleteExpiredWarnings.php │ │ ├── disableLeechingPrivileges.php │ │ ├── recordSeedingStats.php │ │ ├── siteApiSecret.php │ │ └── updateSeedTimes.php │ ├── monthly │ │ ├── auctionBadge.php │ │ ├── remoteCreatorData.php │ │ ├── remoteLiteratureData.php │ │ ├── remoteOrganizationData.php │ │ └── updateTopSnatchers.php │ └── weekly │ │ ├── grantInvites.php │ │ └── updateSatis.php ├── docker │ ├── manticore │ │ ├── Dockerfile │ │ ├── entrypoint.sh │ │ └── manticore.conf │ ├── nginx │ │ └── gazelle.conf │ └── php │ │ ├── php.ini │ │ └── snuffleupagus │ │ ├── default_php8.rules │ │ ├── detect_dangerous_extensions.rules │ │ └── ini_protection.rules ├── rootkit │ └── aptEverything ├── schema │ ├── authentication.sql │ ├── gazelle.sql │ └── slackManifest.json ├── scratchpad.php └── vault │ ├── cartalystSentinel │ └── Authentication.php │ ├── cssOnlyMenu │ ├── mainMenu.scss │ ├── mainMenu.twig │ ├── skeletonFixes.scss │ └── userInfo.twig │ ├── eloquentModels │ ├── Base.php │ ├── Collages.php │ ├── Requests.php │ ├── TorrentGroups.php │ ├── Torrents.php │ └── Wiki.php │ └── oldMainMenu │ ├── mainMenu.scss │ ├── mainMenu.twig │ └── menus.js └── yarn.lock /.dockerignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | html/ 3 | .docker/data 4 | .docker/mysql 5 | .docker/sphinxsearch 6 | .idea/ 7 | .vscode/ 8 | cache/ 9 | node_modules/ 10 | vendor/ 11 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ## 2 | # https://tighten.co/blog/converting-a-legacy-app-to-laravel/ 3 | # 4 | 5 | /node_modules 6 | /public/hot 7 | /public/storage 8 | /storage/*.key 9 | /vendor 10 | .env 11 | .env.backup 12 | .phpunit.result.cache 13 | docker-compose.override.yml 14 | Homestead.json 15 | Homestead.yaml 16 | npm-debug.log 17 | yarn-error.log 18 | /.idea 19 | /.vscode 20 | 21 | 22 | ## 23 | # https://github.com/OPSnet/Gazelle/blob/master/.gitignore 24 | # 25 | 26 | # backups 27 | *.*~ 28 | *.bak 29 | *.sw* 30 | 31 | # assets 32 | /public/build/* 33 | /public/css/* 34 | /public/fonts.tgz 35 | /public/fonts/* 36 | /public/js/* 37 | /public/vendor/* 38 | /resources/closureCompiler.jar 39 | 40 | # allow vendor libraries 41 | !/public/css/vendor/ 42 | !/public/js/vendor/ 43 | 44 | # config 45 | /config/private.php 46 | 47 | # https://marketplace.visualstudio.com/items?itemName=mtxr.sqltools 48 | *.session.sql 49 | 50 | # development test script 51 | /utilities/scratchpad.php 52 | 53 | # docker 54 | /utilities/docker/postgres/data/* 55 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2025 Omics Tools LLC 2 | 3 | Permission to use, copy, modify, and distribute this software for any 4 | purpose with or without fee is hereby granted, provided that the above 5 | copyright notice and this permission notice appear in all copies. 6 | 7 | THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 8 | WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 9 | MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 10 | ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 11 | WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 12 | ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 13 | OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 14 | -------------------------------------------------------------------------------- /app/Exception.php: -------------------------------------------------------------------------------- 1 | client = new \GuzzleHttp\Client([ 33 | "base_uri" => $this->baseUri, 34 | "timeout" => 2.0, 35 | ]); 36 | } 37 | } # class 38 | -------------------------------------------------------------------------------- /app/Reports.php: -------------------------------------------------------------------------------- 1 | dbOld->get_query_id(); 26 | 27 | $app->dbOld->query(" 28 | SELECT 29 | RevisionID, 30 | Summary, 31 | Time, 32 | UserID 33 | FROM $Table 34 | WHERE PageID = $PageID 35 | ORDER BY RevisionID DESC"); 36 | 37 | $Ret = $app->dbOld->to_array(); 38 | $app->dbOld->set_query_id($QueryID); 39 | 40 | return $Ret; 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /cron: -------------------------------------------------------------------------------- 1 | 10 | */ 11 | 12 | # cli bootstrap 13 | require_once __DIR__ . "/bootstrap/cli.php"; 14 | 15 | /** */ 16 | 17 | # check the interval 18 | $interval = $argv[1] ?? null; 19 | $allowedIntervals = ["every", "hourly", "daily", "weekly", "monthly", "yearly"]; 20 | if (!in_array($interval, $allowedIntervals)) { 21 | Gazelle\Text::figlet("bad interval", "red"); 22 | return; 23 | } 24 | 25 | # check the token 26 | $token = $argv[2] ?? null; 27 | if ($token !== $app->env->private("cronToken")) { 28 | Gazelle\Text::figlet("bad token", "red"); 29 | return; 30 | } 31 | 32 | # set the process title 33 | $processTitle = "{$interval}GazelleCron"; 34 | cli_set_process_title($processTitle); 35 | 36 | # ensure only one is running 37 | $currentWorkers = intval(exec("ps ax | grep {$processTitle} | grep -v grep | wc -l")); 38 | if ($currentWorkers > 1) { 39 | Gazelle\Text::figlet("too many workers", "red"); 40 | return; 41 | } 42 | 43 | /** */ 44 | 45 | # unlimit 46 | $app->unlimit(); 47 | 48 | # run the scripts for this interval 49 | $app->recursiveGlob(__DIR__ . "/utilities/crontab/{$interval}"); 50 | -------------------------------------------------------------------------------- /database/migrations/20240522024536_reset_wiki_permissions.php: -------------------------------------------------------------------------------- 1 | dbNew->do($query, []); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /database/migrationsOld/20240522001652_short_uuid.php: -------------------------------------------------------------------------------- 1 | dbNew->column($query, []); 26 | 27 | foreach ($ref as $row) { 28 | $query = "alter table {$row} modify column id bigint unsigned not null default uuid_short()"; 29 | $app->dbNew->do($query, []); 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "dependencies": { 3 | "starboard-notebook": "^0.15.7", 4 | "starboard-rich-editor": "^0.15.7", 5 | "starboard-wrap": "^0.4.1" 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /public/css/vendor/highlight.min.css: -------------------------------------------------------------------------------- 1 | /*! 2 | Theme: Default 3 | Description: Original highlight.js style 4 | Author: (c) Ivan Sagalaev 5 | Maintainer: @highlightjs/core-team 6 | Website: https://highlightjs.org/ 7 | License: see project LICENSE 8 | Touched: 2021 9 | */pre code.hljs{display:block;overflow-x:auto;padding:1em}code.hljs{padding:3px 5px}.hljs{background:#f3f3f3;color:#444}.hljs-comment{color:#697070}.hljs-punctuation,.hljs-tag{color:#444a}.hljs-tag .hljs-attr,.hljs-tag .hljs-name{color:#444}.hljs-attribute,.hljs-doctag,.hljs-keyword,.hljs-meta .hljs-keyword,.hljs-name,.hljs-selector-tag{font-weight:700}.hljs-deletion,.hljs-number,.hljs-quote,.hljs-selector-class,.hljs-selector-id,.hljs-string,.hljs-template-tag,.hljs-type{color:#800}.hljs-section,.hljs-title{color:#800;font-weight:700}.hljs-link,.hljs-operator,.hljs-regexp,.hljs-selector-attr,.hljs-selector-pseudo,.hljs-symbol,.hljs-template-variable,.hljs-variable{color:#ab5656}.hljs-literal{color:#695}.hljs-addition,.hljs-built_in,.hljs-bullet,.hljs-code{color:#397300}.hljs-meta{color:#1f7199}.hljs-meta .hljs-string{color:#38a}.hljs-emphasis{font-style:italic}.hljs-strong{font-weight:700} -------------------------------------------------------------------------------- /public/css/vendor/leaflet/images/layers-2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/biotorrents/gazelle/29e89642f3b2da8901643d1db1f36566007f0f96/public/css/vendor/leaflet/images/layers-2x.png -------------------------------------------------------------------------------- /public/css/vendor/leaflet/images/layers.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/biotorrents/gazelle/29e89642f3b2da8901643d1db1f36566007f0f96/public/css/vendor/leaflet/images/layers.png -------------------------------------------------------------------------------- /public/css/vendor/leaflet/images/marker-icon-2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/biotorrents/gazelle/29e89642f3b2da8901643d1db1f36566007f0f96/public/css/vendor/leaflet/images/marker-icon-2x.png -------------------------------------------------------------------------------- /public/css/vendor/leaflet/images/marker-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/biotorrents/gazelle/29e89642f3b2da8901643d1db1f36566007f0f96/public/css/vendor/leaflet/images/marker-icon.png -------------------------------------------------------------------------------- /public/css/vendor/leaflet/images/marker-shadow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/biotorrents/gazelle/29e89642f3b2da8901643d1db1f36566007f0f96/public/css/vendor/leaflet/images/marker-shadow.png -------------------------------------------------------------------------------- /public/images/avatars/default.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/biotorrents/gazelle/29e89642f3b2da8901643d1db1f36566007f0f96/public/images/avatars/default.webp -------------------------------------------------------------------------------- /public/images/forums/go_last_read.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/biotorrents/gazelle/29e89642f3b2da8901643d1db1f36566007f0f96/public/images/forums/go_last_read.png -------------------------------------------------------------------------------- /public/images/forums/hide.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/biotorrents/gazelle/29e89642f3b2da8901643d1db1f36566007f0f96/public/images/forums/hide.png -------------------------------------------------------------------------------- /public/images/forums/locked_read.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/biotorrents/gazelle/29e89642f3b2da8901643d1db1f36566007f0f96/public/images/forums/locked_read.png -------------------------------------------------------------------------------- /public/images/forums/locked_sticky_read.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/biotorrents/gazelle/29e89642f3b2da8901643d1db1f36566007f0f96/public/images/forums/locked_sticky_read.png -------------------------------------------------------------------------------- /public/images/forums/locked_sticky_unread.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/biotorrents/gazelle/29e89642f3b2da8901643d1db1f36566007f0f96/public/images/forums/locked_sticky_unread.png -------------------------------------------------------------------------------- /public/images/forums/locked_unread.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/biotorrents/gazelle/29e89642f3b2da8901643d1db1f36566007f0f96/public/images/forums/locked_unread.png -------------------------------------------------------------------------------- /public/images/forums/read.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/biotorrents/gazelle/29e89642f3b2da8901643d1db1f36566007f0f96/public/images/forums/read.png -------------------------------------------------------------------------------- /public/images/forums/show.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/biotorrents/gazelle/29e89642f3b2da8901643d1db1f36566007f0f96/public/images/forums/show.png -------------------------------------------------------------------------------- /public/images/forums/sticky_read.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/biotorrents/gazelle/29e89642f3b2da8901643d1db1f36566007f0f96/public/images/forums/sticky_read.png -------------------------------------------------------------------------------- /public/images/forums/sticky_unread.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/biotorrents/gazelle/29e89642f3b2da8901643d1db1f36566007f0f96/public/images/forums/sticky_unread.png -------------------------------------------------------------------------------- /public/images/forums/unread.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/biotorrents/gazelle/29e89642f3b2da8901643d1db1f36566007f0f96/public/images/forums/unread.png -------------------------------------------------------------------------------- /public/images/icons/archive.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/biotorrents/gazelle/29e89642f3b2da8901643d1db1f36566007f0f96/public/images/icons/archive.webp -------------------------------------------------------------------------------- /public/images/icons/externalLink.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /public/images/icons/fa-cloud.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /public/images/icons/rss.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/biotorrents/gazelle/29e89642f3b2da8901643d1db1f36566007f0f96/public/images/icons/rss.webp -------------------------------------------------------------------------------- /public/images/icons/version.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/biotorrents/gazelle/29e89642f3b2da8901643d1db1f36566007f0f96/public/images/icons/version.webp -------------------------------------------------------------------------------- /public/images/logos/colorfulWaves-whiteShadow-2k.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/biotorrents/gazelle/29e89642f3b2da8901643d1db1f36566007f0f96/public/images/logos/colorfulWaves-whiteShadow-2k.webp -------------------------------------------------------------------------------- /public/images/logos/grid.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/biotorrents/gazelle/29e89642f3b2da8901643d1db1f36566007f0f96/public/images/logos/grid.webp -------------------------------------------------------------------------------- /public/images/logos/openAlex.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/biotorrents/gazelle/29e89642f3b2da8901643d1db1f36566007f0f96/public/images/logos/openAlex.webp -------------------------------------------------------------------------------- /public/images/logos/orcid.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/biotorrents/gazelle/29e89642f3b2da8901643d1db1f36566007f0f96/public/images/logos/orcid.webp -------------------------------------------------------------------------------- /public/images/logos/patreon.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/biotorrents/gazelle/29e89642f3b2da8901643d1db1f36566007f0f96/public/images/logos/patreon.webp -------------------------------------------------------------------------------- /public/images/logos/sci-hub.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/biotorrents/gazelle/29e89642f3b2da8901643d1db1f36566007f0f96/public/images/logos/sci-hub.webp -------------------------------------------------------------------------------- /public/images/logos/semanticScholar.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/biotorrents/gazelle/29e89642f3b2da8901643d1db1f36566007f0f96/public/images/logos/semanticScholar.webp -------------------------------------------------------------------------------- /public/images/logos/simpleFavicon-2k.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/biotorrents/gazelle/29e89642f3b2da8901643d1db1f36566007f0f96/public/images/logos/simpleFavicon-2k.webp -------------------------------------------------------------------------------- /public/images/logos/torrents.bio.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/biotorrents/gazelle/29e89642f3b2da8901643d1db1f36566007f0f96/public/images/logos/torrents.bio.webp -------------------------------------------------------------------------------- /public/images/mascot.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/biotorrents/gazelle/29e89642f3b2da8901643d1db1f36566007f0f96/public/images/mascot.webp -------------------------------------------------------------------------------- /public/images/mascotFullVersion.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/biotorrents/gazelle/29e89642f3b2da8901643d1db1f36566007f0f96/public/images/mascotFullVersion.webp -------------------------------------------------------------------------------- /public/images/noartwork.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/biotorrents/gazelle/29e89642f3b2da8901643d1db1f36566007f0f96/public/images/noartwork.webp -------------------------------------------------------------------------------- /public/images/oink.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/biotorrents/gazelle/29e89642f3b2da8901643d1db1f36566007f0f96/public/images/oink.webp -------------------------------------------------------------------------------- /public/images/plausibleOptOut.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/biotorrents/gazelle/29e89642f3b2da8901643d1db1f36566007f0f96/public/images/plausibleOptOut.webp -------------------------------------------------------------------------------- /public/js/vendor/leaflet/images/layers-2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/biotorrents/gazelle/29e89642f3b2da8901643d1db1f36566007f0f96/public/js/vendor/leaflet/images/layers-2x.png -------------------------------------------------------------------------------- /public/js/vendor/leaflet/images/layers.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/biotorrents/gazelle/29e89642f3b2da8901643d1db1f36566007f0f96/public/js/vendor/leaflet/images/layers.png -------------------------------------------------------------------------------- /public/js/vendor/leaflet/images/marker-icon-2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/biotorrents/gazelle/29e89642f3b2da8901643d1db1f36566007f0f96/public/js/vendor/leaflet/images/marker-icon-2x.png -------------------------------------------------------------------------------- /public/js/vendor/leaflet/images/marker-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/biotorrents/gazelle/29e89642f3b2da8901643d1db1f36566007f0f96/public/js/vendor/leaflet/images/marker-icon.png -------------------------------------------------------------------------------- /public/js/vendor/leaflet/images/marker-shadow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/biotorrents/gazelle/29e89642f3b2da8901643d1db1f36566007f0f96/public/js/vendor/leaflet/images/marker-shadow.png -------------------------------------------------------------------------------- /public/js/vendor/noty/layouts/bottom.js: -------------------------------------------------------------------------------- 1 | $.noty.layouts.bottom = { 2 | name : 'bottom', 3 | options : {}, 4 | container: { 5 | object : '
    ', 6 | selector: 'ul#noty_bottom_layout_container', 7 | style : function() { 8 | $(this).css({ 9 | bottom : 0, 10 | left : '5%', 11 | position : 'fixed', 12 | width : '90%', 13 | height : 'auto', 14 | margin : 0, 15 | padding : 0, 16 | listStyleType: 'none', 17 | zIndex : 9999999 18 | }); 19 | } 20 | }, 21 | parent : { 22 | object : '
  • ', 23 | selector: 'li', 24 | css : {} 25 | }, 26 | css : { 27 | display: 'none' 28 | }, 29 | addClass : '' 30 | }; 31 | -------------------------------------------------------------------------------- /public/js/vendor/noty/layouts/bottomCenter.js: -------------------------------------------------------------------------------- 1 | $.noty.layouts.bottomCenter = { 2 | name : 'bottomCenter', 3 | options : { // overrides options 4 | 5 | }, 6 | container: { 7 | object : '
      ', 8 | selector: 'ul#noty_bottomCenter_layout_container', 9 | style : function() { 10 | $(this).css({ 11 | bottom : 20, 12 | left : 0, 13 | position : 'fixed', 14 | width : '310px', 15 | height : 'auto', 16 | margin : 0, 17 | padding : 0, 18 | listStyleType: 'none', 19 | zIndex : 10000000 20 | }); 21 | 22 | $(this).css({ 23 | left: ($(window).width() - $(this).outerWidth(false)) / 2 + 'px' 24 | }); 25 | } 26 | }, 27 | parent : { 28 | object : '
    • ', 29 | selector: 'li', 30 | css : {} 31 | }, 32 | css : { 33 | display: 'none', 34 | width : '310px' 35 | }, 36 | addClass : '' 37 | }; 38 | 39 | -------------------------------------------------------------------------------- /public/js/vendor/noty/layouts/bottomLeft.js: -------------------------------------------------------------------------------- 1 | $.noty.layouts.bottomLeft = { 2 | name : 'bottomLeft', 3 | options : { // overrides options 4 | 5 | }, 6 | container: { 7 | object : '
        ', 8 | selector: 'ul#noty_bottomLeft_layout_container', 9 | style : function() { 10 | $(this).css({ 11 | bottom : 20, 12 | left : 20, 13 | position : 'fixed', 14 | width : '310px', 15 | height : 'auto', 16 | margin : 0, 17 | padding : 0, 18 | listStyleType: 'none', 19 | zIndex : 10000000 20 | }); 21 | 22 | if(window.innerWidth < 600) { 23 | $(this).css({ 24 | left: 5 25 | }); 26 | } 27 | } 28 | }, 29 | parent : { 30 | object : '
      • ', 31 | selector: 'li', 32 | css : {} 33 | }, 34 | css : { 35 | display: 'none', 36 | width : '310px' 37 | }, 38 | addClass : '' 39 | }; -------------------------------------------------------------------------------- /public/js/vendor/noty/layouts/bottomRight.js: -------------------------------------------------------------------------------- 1 | $.noty.layouts.bottomRight = { 2 | name : 'bottomRight', 3 | options : { // overrides options 4 | 5 | }, 6 | container: { 7 | object : '
          ', 8 | selector: 'ul#noty_bottomRight_layout_container', 9 | style : function() { 10 | $(this).css({ 11 | bottom : 20, 12 | right : 20, 13 | position : 'fixed', 14 | width : '310px', 15 | height : 'auto', 16 | margin : 0, 17 | padding : 0, 18 | listStyleType: 'none', 19 | zIndex : 10000000 20 | }); 21 | 22 | if(window.innerWidth < 600) { 23 | $(this).css({ 24 | right: 5 25 | }); 26 | } 27 | } 28 | }, 29 | parent : { 30 | object : '
        • ', 31 | selector: 'li', 32 | css : {} 33 | }, 34 | css : { 35 | display: 'none', 36 | width : '310px' 37 | }, 38 | addClass : '' 39 | }; -------------------------------------------------------------------------------- /public/js/vendor/noty/layouts/inline.js: -------------------------------------------------------------------------------- 1 | $.noty.layouts.inline = { 2 | name : 'inline', 3 | options : {}, 4 | container: { 5 | object : '
            ', 6 | selector: 'ul.noty_inline_layout_container', 7 | style : function() { 8 | $(this).css({ 9 | width : '100%', 10 | height : 'auto', 11 | margin : 0, 12 | padding : 0, 13 | listStyleType: 'none', 14 | zIndex : 9999999 15 | }); 16 | } 17 | }, 18 | parent : { 19 | object : '
          • ', 20 | selector: 'li', 21 | css : {} 22 | }, 23 | css : { 24 | display: 'none' 25 | }, 26 | addClass : '' 27 | }; -------------------------------------------------------------------------------- /public/js/vendor/noty/layouts/top.js: -------------------------------------------------------------------------------- 1 | $.noty.layouts.top = { 2 | name : 'top', 3 | options : {}, 4 | container: { 5 | object : '
              ', 6 | selector: 'ul#noty_top_layout_container', 7 | style : function() { 8 | $(this).css({ 9 | top : 0, 10 | left : '5%', 11 | position : 'fixed', 12 | width : '90%', 13 | height : 'auto', 14 | margin : 0, 15 | padding : 0, 16 | listStyleType: 'none', 17 | zIndex : 9999999 18 | }); 19 | } 20 | }, 21 | parent : { 22 | object : '
            • ', 23 | selector: 'li', 24 | css : {} 25 | }, 26 | css : { 27 | display: 'none' 28 | }, 29 | addClass : '' 30 | }; -------------------------------------------------------------------------------- /public/js/vendor/noty/layouts/topCenter.js: -------------------------------------------------------------------------------- 1 | $.noty.layouts.topCenter = { 2 | name : 'topCenter', 3 | options : { // overrides options 4 | 5 | }, 6 | container: { 7 | object : '
                ', 8 | selector: 'ul#noty_topCenter_layout_container', 9 | style : function() { 10 | $(this).css({ 11 | top : 20, 12 | left : 0, 13 | position : 'fixed', 14 | width : '310px', 15 | height : 'auto', 16 | margin : 0, 17 | padding : 0, 18 | listStyleType: 'none', 19 | zIndex : 10000000 20 | }); 21 | 22 | $(this).css({ 23 | left: ($(window).width() - $(this).outerWidth(false)) / 2 + 'px' 24 | }); 25 | } 26 | }, 27 | parent : { 28 | object : '
              • ', 29 | selector: 'li', 30 | css : {} 31 | }, 32 | css : { 33 | display: 'none', 34 | width : '310px' 35 | }, 36 | addClass : '' 37 | }; 38 | -------------------------------------------------------------------------------- /public/js/vendor/noty/layouts/topLeft.js: -------------------------------------------------------------------------------- 1 | $.noty.layouts.topLeft = { 2 | name : 'topLeft', 3 | options : { // overrides options 4 | 5 | }, 6 | container: { 7 | object : '
                  ', 8 | selector: 'ul#noty_topLeft_layout_container', 9 | style : function() { 10 | $(this).css({ 11 | top : 20, 12 | left : 20, 13 | position : 'fixed', 14 | width : '310px', 15 | height : 'auto', 16 | margin : 0, 17 | padding : 0, 18 | listStyleType: 'none', 19 | zIndex : 10000000 20 | }); 21 | 22 | if(window.innerWidth < 600) { 23 | $(this).css({ 24 | left: 5 25 | }); 26 | } 27 | } 28 | }, 29 | parent : { 30 | object : '
                • ', 31 | selector: 'li', 32 | css : {} 33 | }, 34 | css : { 35 | display: 'none', 36 | width : '310px' 37 | }, 38 | addClass : '' 39 | }; -------------------------------------------------------------------------------- /public/js/vendor/noty/layouts/topRight.js: -------------------------------------------------------------------------------- 1 | $.noty.layouts.topRight = { 2 | name : 'topRight', 3 | options : { // overrides options 4 | 5 | }, 6 | container: { 7 | object : '
                    ', 8 | selector: 'ul#noty_topRight_layout_container', 9 | style : function() { 10 | $(this).css({ 11 | top : 20, 12 | right : 20, 13 | position : 'fixed', 14 | width : '310px', 15 | height : 'auto', 16 | margin : 0, 17 | padding : 0, 18 | listStyleType: 'none', 19 | zIndex : 10000000 20 | }); 21 | 22 | if(window.innerWidth < 600) { 23 | $(this).css({ 24 | right: 5 25 | }); 26 | } 27 | } 28 | }, 29 | parent : { 30 | object : '
                  • ', 31 | selector: 'li', 32 | css : {} 33 | }, 34 | css : { 35 | display: 'none', 36 | width : '310px' 37 | }, 38 | addClass : '' 39 | }; -------------------------------------------------------------------------------- /public/opensearch.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | torrents.bio 5 | An open platform for libre biology data 6 | api biological-data biological-sequences biology bittorrent bittorrent-tracker website 7 | hello@torrents.bio 8 | 10 | Search torrents.bio for BitTorrent biology data 11 | https://torrents.bio/images/logos/simpleFavicon-2k.webp 12 | 13 | Omics Tools LLC 14 | 15 | Copyright (c) 2021 Omics Tools LLC 16 | 17 | open 18 | false 19 | en-us 20 | UTF-8 21 | UTF-8 22 | 23 | -------------------------------------------------------------------------------- /resources/buildAssets.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | 4 | ## 5 | # compile static assets 6 | # 7 | 8 | # cascading style sheets 9 | scss="./scss/*.scss" 10 | for f in $scss 11 | do 12 | echo ">>> compiling $f..." 13 | basename=$(basename -s .scss $f) 14 | sass "./scss/$basename.scss" > "../public/css/$basename.css" 15 | done 16 | 17 | # javascript 18 | js="./js/*.js" 19 | for f in $js 20 | do 21 | echo ">>> compiling $f..." 22 | basename=$(basename -s .js $f) 23 | java -jar closureCompiler.jar \ 24 | --compilation_level SIMPLE_OPTIMIZATIONS \ 25 | --js "./js/$basename.js" \ 26 | --js_output_file "../public/js/$basename.js" 27 | done 28 | -------------------------------------------------------------------------------- /resources/scss/assets.scss: -------------------------------------------------------------------------------- 1 | /** 2 | * assets 3 | * 4 | * all variables, mixins, functions, etc., 5 | * should be included here for common use 6 | */ 7 | 8 | @import "./assets/colors"; 9 | @import "./assets/fonts"; 10 | @import "./assets/icons"; 11 | -------------------------------------------------------------------------------- /resources/scss/bookish.scss: -------------------------------------------------------------------------------- 1 | /** 2 | * bookish 3 | */ 4 | 5 | @import "./assets"; 6 | @import "./bookish/bookish"; 7 | @import "./bookish/matcha"; 8 | 9 | @import "./bookish/colors"; 10 | @import "./bookish/fonts"; 11 | @import "./bookish/layout"; 12 | @import "./bookish/tables"; 13 | -------------------------------------------------------------------------------- /resources/scss/bookish/debug.scss: -------------------------------------------------------------------------------- 1 | /* Messages */ 2 | @mixin message($color) { 3 | .save_message { 4 | padding: 1rem; 5 | width: 50%; 6 | margin: 2em auto; 7 | background: $color; 8 | text-align: center; 9 | color: #222; 10 | font-weight: bold; 11 | box-shadow: $shadow; 12 | } 13 | } 14 | 15 | .error_message { 16 | @include message(#ffcdd2); 17 | } 18 | 19 | .save_message { 20 | @include message(#ffe0b2); 21 | } 22 | 23 | .elem_error { 24 | border: 2px solid rgba(255, 0, 0, 0.5); 25 | } 26 | -------------------------------------------------------------------------------- /resources/scss/bookish/images/sam-komon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/biotorrents/gazelle/29e89642f3b2da8901643d1db1f36566007f0f96/resources/scss/bookish/images/sam-komon.png -------------------------------------------------------------------------------- /resources/scss/development.scss: -------------------------------------------------------------------------------- 1 | /** 2 | * development 3 | */ 4 | 5 | @import "./assets"; 6 | @import "./development/development"; 7 | -------------------------------------------------------------------------------- /resources/scss/global.scss: -------------------------------------------------------------------------------- 1 | /** 2 | * global 3 | */ 4 | 5 | @import "./assets"; 6 | 7 | @import "./global/colors"; 8 | @import "./global/footer"; 9 | @import "./global/fonts"; 10 | @import "./global/forms"; 11 | @import "./global/layout"; 12 | @import "./global/mainMenu"; 13 | @import "./global/user"; 14 | @import "./global/skeletonFixes"; 15 | @import "./global/tables"; 16 | @import "./global/torrents"; 17 | -------------------------------------------------------------------------------- /resources/scss/global/footer.scss: -------------------------------------------------------------------------------- 1 | /** 2 | * footer 3 | */ 4 | 5 | footer { 6 | #footerIcons { 7 | display: flex; 8 | flex-flow: row nowrap; 9 | gap: 5rem; 10 | justify-content: center; 11 | 12 | a { 13 | text-decoration: none; 14 | } 15 | 16 | i { 17 | font-size: larger; 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /resources/scss/global/user.scss: -------------------------------------------------------------------------------- 1 | /** 2 | * user settings page 3 | */ 4 | 5 | .userSettings { 6 | th { 7 | vertical-align: text-top; 8 | width: 33% !important; 9 | } 10 | 11 | input[type="text"], 12 | input[type="email"], 13 | input[type="password"], 14 | textarea { 15 | width: 100%; 16 | } 17 | 18 | #publicKey { 19 | font-family: monospace; 20 | } 21 | } 22 | 23 | /** 24 | * user profile page 25 | */ 26 | 27 | #userProfilePercentiles, 28 | #userProfileRequests { 29 | td { 30 | text-align: right; 31 | } 32 | } 33 | 34 | #userProfileAvatar { 35 | text-align: center; 36 | 37 | figcaption { 38 | margin-top: 2rem; 39 | } 40 | } 41 | 42 | .badgesFlex { 43 | display: flex; 44 | flex-flow: row wrap; 45 | gap: 1rem; 46 | user-select: none; 47 | } 48 | 49 | /* recent torrent activity, e.g., last five uploads */ 50 | .recentTorrentActivity { 51 | display: flex; 52 | flex-flow: row nowrap; 53 | gap: 1rem; 54 | align-items: center; 55 | } -------------------------------------------------------------------------------- /resources/scss/postmod.scss: -------------------------------------------------------------------------------- 1 | /** 2 | * postmod 3 | */ 4 | 5 | @import "./assets"; 6 | @import "./postmod/postmod"; 7 | 8 | @import "./postmod/colors"; 9 | @import "./postmod/layout"; 10 | @import "./postmod/menus"; 11 | -------------------------------------------------------------------------------- /resources/scss/postmod/colors.scss: -------------------------------------------------------------------------------- 1 | /** 2 | * Alerts, Toolbox, etc. 3 | * Needs one unified error display 4 | * (torrent form, API keys use their own) 5 | */ 6 | @mixin alertbar($bg) { 7 | background: $bg; 8 | text-align: center; 9 | color: white; 10 | font-weight: bold; 11 | /* width: 33%; */ 12 | margin: 2em auto; 13 | padding: 1rem; 14 | 15 | /* postmod.scss */ 16 | box-shadow: 0 1px 3px rgba(0, 0, 0, 0.5); 17 | -moz-box-shadow: 0 1px 3px rgba(0, 0, 0, 0.5); 18 | -webkit-box-shadow: 0 1px 3px rgba(0, 0, 0, 0.5); 19 | } 20 | 21 | .alertbar { 22 | @include alertbar(transparent url($images + "content.png")); 23 | 24 | .warning { 25 | background: #ffe0b2; 26 | } 27 | 28 | .error { 29 | background: #ffcdd2; 30 | } 31 | } 32 | 33 | .token_error { 34 | @include alertbar(#ffcdd2); 35 | } 36 | 37 | .modbar a { 38 | margin: 0 0.5rem; 39 | } 40 | 41 | /* Torrent titles */ 42 | .torrentTitle { 43 | font-size: larger; 44 | } 45 | -------------------------------------------------------------------------------- /resources/scss/postmod/images/Akzidenz.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/biotorrents/gazelle/29e89642f3b2da8901643d1db1f36566007f0f96/resources/scss/postmod/images/Akzidenz.otf -------------------------------------------------------------------------------- /resources/scss/postmod/images/Avant.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/biotorrents/gazelle/29e89642f3b2da8901643d1db1f36566007f0f96/resources/scss/postmod/images/Avant.otf -------------------------------------------------------------------------------- /resources/scss/postmod/images/CorpidOffice.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/biotorrents/gazelle/29e89642f3b2da8901643d1db1f36566007f0f96/resources/scss/postmod/images/CorpidOffice.ttf -------------------------------------------------------------------------------- /resources/scss/postmod/images/Officina.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/biotorrents/gazelle/29e89642f3b2da8901643d1db1f36566007f0f96/resources/scss/postmod/images/Officina.otf -------------------------------------------------------------------------------- /resources/scss/postmod/images/alert-overlay.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/biotorrents/gazelle/29e89642f3b2da8901643d1db1f36566007f0f96/resources/scss/postmod/images/alert-overlay.png -------------------------------------------------------------------------------- /resources/scss/postmod/images/bg_footer.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/biotorrents/gazelle/29e89642f3b2da8901643d1db1f36566007f0f96/resources/scss/postmod/images/bg_footer.png -------------------------------------------------------------------------------- /resources/scss/postmod/images/bg_header.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/biotorrents/gazelle/29e89642f3b2da8901643d1db1f36566007f0f96/resources/scss/postmod/images/bg_header.png -------------------------------------------------------------------------------- /resources/scss/postmod/images/bg_inputs.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/biotorrents/gazelle/29e89642f3b2da8901643d1db1f36566007f0f96/resources/scss/postmod/images/bg_inputs.png -------------------------------------------------------------------------------- /resources/scss/postmod/images/bg_menu.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/biotorrents/gazelle/29e89642f3b2da8901643d1db1f36566007f0f96/resources/scss/postmod/images/bg_menu.png -------------------------------------------------------------------------------- /resources/scss/postmod/images/body.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/biotorrents/gazelle/29e89642f3b2da8901643d1db1f36566007f0f96/resources/scss/postmod/images/body.jpg -------------------------------------------------------------------------------- /resources/scss/postmod/images/content.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/biotorrents/gazelle/29e89642f3b2da8901643d1db1f36566007f0f96/resources/scss/postmod/images/content.png -------------------------------------------------------------------------------- /resources/scss/postmod/images/content_light.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/biotorrents/gazelle/29e89642f3b2da8901643d1db1f36566007f0f96/resources/scss/postmod/images/content_light.png -------------------------------------------------------------------------------- /resources/scss/postmod/images/external.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/biotorrents/gazelle/29e89642f3b2da8901643d1db1f36566007f0f96/resources/scss/postmod/images/external.png -------------------------------------------------------------------------------- /resources/scss/postmod/images/gazelle.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/biotorrents/gazelle/29e89642f3b2da8901643d1db1f36566007f0f96/resources/scss/postmod/images/gazelle.png -------------------------------------------------------------------------------- /resources/scss/postmod/images/go_last_read.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/biotorrents/gazelle/29e89642f3b2da8901643d1db1f36566007f0f96/resources/scss/postmod/images/go_last_read.png -------------------------------------------------------------------------------- /resources/scss/postmod/images/hide.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/biotorrents/gazelle/29e89642f3b2da8901643d1db1f36566007f0f96/resources/scss/postmod/images/hide.png -------------------------------------------------------------------------------- /resources/scss/postmod/images/leechers.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/biotorrents/gazelle/29e89642f3b2da8901643d1db1f36566007f0f96/resources/scss/postmod/images/leechers.png -------------------------------------------------------------------------------- /resources/scss/postmod/images/load.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/biotorrents/gazelle/29e89642f3b2da8901643d1db1f36566007f0f96/resources/scss/postmod/images/load.gif -------------------------------------------------------------------------------- /resources/scss/postmod/images/locked_read.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/biotorrents/gazelle/29e89642f3b2da8901643d1db1f36566007f0f96/resources/scss/postmod/images/locked_read.png -------------------------------------------------------------------------------- /resources/scss/postmod/images/locked_sticky_read.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/biotorrents/gazelle/29e89642f3b2da8901643d1db1f36566007f0f96/resources/scss/postmod/images/locked_sticky_read.png -------------------------------------------------------------------------------- /resources/scss/postmod/images/locked_sticky_unread.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/biotorrents/gazelle/29e89642f3b2da8901643d1db1f36566007f0f96/resources/scss/postmod/images/locked_sticky_unread.png -------------------------------------------------------------------------------- /resources/scss/postmod/images/locked_unread.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/biotorrents/gazelle/29e89642f3b2da8901643d1db1f36566007f0f96/resources/scss/postmod/images/locked_unread.png -------------------------------------------------------------------------------- /resources/scss/postmod/images/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/biotorrents/gazelle/29e89642f3b2da8901643d1db1f36566007f0f96/resources/scss/postmod/images/logo.png -------------------------------------------------------------------------------- /resources/scss/postmod/images/nav_matrix.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/biotorrents/gazelle/29e89642f3b2da8901643d1db1f36566007f0f96/resources/scss/postmod/images/nav_matrix.png -------------------------------------------------------------------------------- /resources/scss/postmod/images/nav_matrix_extended.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/biotorrents/gazelle/29e89642f3b2da8901643d1db1f36566007f0f96/resources/scss/postmod/images/nav_matrix_extended.png -------------------------------------------------------------------------------- /resources/scss/postmod/images/nu_nav_matrix.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/biotorrents/gazelle/29e89642f3b2da8901643d1db1f36566007f0f96/resources/scss/postmod/images/nu_nav_matrix.png -------------------------------------------------------------------------------- /resources/scss/postmod/images/poll_left.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/biotorrents/gazelle/29e89642f3b2da8901643d1db1f36566007f0f96/resources/scss/postmod/images/poll_left.png -------------------------------------------------------------------------------- /resources/scss/postmod/images/poll_middle.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/biotorrents/gazelle/29e89642f3b2da8901643d1db1f36566007f0f96/resources/scss/postmod/images/poll_middle.png -------------------------------------------------------------------------------- /resources/scss/postmod/images/poll_right.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/biotorrents/gazelle/29e89642f3b2da8901643d1db1f36566007f0f96/resources/scss/postmod/images/poll_right.png -------------------------------------------------------------------------------- /resources/scss/postmod/images/read.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/biotorrents/gazelle/29e89642f3b2da8901643d1db1f36566007f0f96/resources/scss/postmod/images/read.png -------------------------------------------------------------------------------- /resources/scss/postmod/images/seeders.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/biotorrents/gazelle/29e89642f3b2da8901643d1db1f36566007f0f96/resources/scss/postmod/images/seeders.png -------------------------------------------------------------------------------- /resources/scss/postmod/images/show.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/biotorrents/gazelle/29e89642f3b2da8901643d1db1f36566007f0f96/resources/scss/postmod/images/show.png -------------------------------------------------------------------------------- /resources/scss/postmod/images/snatched.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/biotorrents/gazelle/29e89642f3b2da8901643d1db1f36566007f0f96/resources/scss/postmod/images/snatched.png -------------------------------------------------------------------------------- /resources/scss/postmod/images/sticky_read.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/biotorrents/gazelle/29e89642f3b2da8901643d1db1f36566007f0f96/resources/scss/postmod/images/sticky_read.png -------------------------------------------------------------------------------- /resources/scss/postmod/images/sticky_unread.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/biotorrents/gazelle/29e89642f3b2da8901643d1db1f36566007f0f96/resources/scss/postmod/images/sticky_unread.png -------------------------------------------------------------------------------- /resources/scss/postmod/images/table_header.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/biotorrents/gazelle/29e89642f3b2da8901643d1db1f36566007f0f96/resources/scss/postmod/images/table_header.png -------------------------------------------------------------------------------- /resources/scss/postmod/images/table_header_dark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/biotorrents/gazelle/29e89642f3b2da8901643d1db1f36566007f0f96/resources/scss/postmod/images/table_header_dark.png -------------------------------------------------------------------------------- /resources/scss/postmod/images/unread.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/biotorrents/gazelle/29e89642f3b2da8901643d1db1f36566007f0f96/resources/scss/postmod/images/unread.png -------------------------------------------------------------------------------- /resources/scss/postmod/images/wood.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/biotorrents/gazelle/29e89642f3b2da8901643d1db1f36566007f0f96/resources/scss/postmod/images/wood.jpg -------------------------------------------------------------------------------- /resources/scss/postmod/images/woodlogo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/biotorrents/gazelle/29e89642f3b2da8901643d1db1f36566007f0f96/resources/scss/postmod/images/woodlogo.png -------------------------------------------------------------------------------- /resources/scss/postmod/images/woodlogo.png2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/biotorrents/gazelle/29e89642f3b2da8901643d1db1f36566007f0f96/resources/scss/postmod/images/woodlogo.png2 -------------------------------------------------------------------------------- /resources/scss/postmod/images/wrapper.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/biotorrents/gazelle/29e89642f3b2da8901643d1db1f36566007f0f96/resources/scss/postmod/images/wrapper.png -------------------------------------------------------------------------------- /resources/scss/postmod/layout.scss: -------------------------------------------------------------------------------- 1 | /* logo */ 2 | #logo { 3 | background: url("/images/logos/liquidrop-postmod.png") no-repeat center; 4 | background-size: contain; 5 | width: 50px; 6 | min-width: 50px; 7 | height: 100%; 8 | min-height: 100%; 9 | margin: 0 0 0 10%; 10 | 11 | a { 12 | border: none; 13 | display: block; 14 | width: 100%; 15 | height: 50px; 16 | } 17 | 18 | a:hover { 19 | border: none; 20 | } 21 | } 22 | 23 | /* category icons */ 24 | .categoryColumn div { 25 | width: 3rem; 26 | height: 3rem; 27 | } 28 | 29 | /* headers */ 30 | .header { 31 | margin-bottom: 2rem; 32 | text-align: center; 33 | } 34 | 35 | /* footer */ 36 | footer { 37 | margin-top: 2rem; 38 | width: 100%; 39 | 40 | p { 41 | text-align: center; 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /resources/scss/public.scss: -------------------------------------------------------------------------------- 1 | /** 2 | * public 3 | */ 4 | 5 | @import "./assets"; 6 | @import "./public/public"; 7 | -------------------------------------------------------------------------------- /resources/scss/public/public.scss: -------------------------------------------------------------------------------- 1 | /** 2 | * header 3 | */ 4 | 5 | header { 6 | height: 4.2rem; 7 | line-height: 4.2rem; 8 | max-width: 100%; 9 | 10 | background: $skeletonHalfDark; 11 | padding: 0 1%; 12 | /* position: sticky; */ 13 | text-align: right; 14 | top: 0; 15 | z-index: 1; 16 | 17 | a { 18 | color: white; 19 | text-decoration: none; 20 | margin: 0 1rem; 21 | 22 | &:hover { 23 | color: white; 24 | text-decoration: underline; 25 | } 26 | } 27 | } 28 | 29 | 30 | /** 31 | * logo 32 | */ 33 | 34 | figure#publicLogo { 35 | margin-bottom: 0; 36 | margin-top: 10rem; 37 | text-align: center; 38 | 39 | img { 40 | height: 5rem; 41 | } 42 | 43 | &:after { 44 | content: "℠"; 45 | font-size: small; 46 | vertical-align: top; 47 | } 48 | } 49 | 50 | 51 | /** 52 | * forms 53 | */ 54 | 55 | form { 56 | display: flex; 57 | flex-flow: column wrap; 58 | gap: 2rem; 59 | 60 | a.button { 61 | margin-bottom: 0; 62 | } 63 | 64 | ul { 65 | list-style: none !important; 66 | } 67 | } 68 | 69 | 70 | /** 71 | * misc 72 | */ 73 | 74 | .mouseless { 75 | cursor: default; 76 | margin: 5rem; 77 | } -------------------------------------------------------------------------------- /resources/scss/sidebar.scss: -------------------------------------------------------------------------------- 1 | /* desktop */ 2 | @media (orientation: landscape) { 3 | #main { 4 | display: inline-grid; 5 | grid-template-areas: 6 | "content sidebar"; 7 | 8 | grid-template-columns: 2fr 1fr; 9 | gap: 2rem; 10 | 11 | #content { 12 | grid-area: content; 13 | margin-left: 5rem; 14 | } 15 | 16 | #sidebar { 17 | grid-area: sidebar; 18 | margin-right: 5rem; 19 | } 20 | } 21 | } 22 | 23 | /* mobile */ 24 | @media (orientation: portrait) { 25 | #main { 26 | display: inline-grid; 27 | grid-template-areas: 28 | "content" 29 | "sidebar"; 30 | 31 | grid-template-columns: 1fr; 32 | gap: 2rem; 33 | 34 | #content { 35 | grid-area: content; 36 | margin: 0 2rem; 37 | } 38 | 39 | #sidebar { 40 | grid-area: sidebar; 41 | margin: 0 2rem; 42 | } 43 | } 44 | } -------------------------------------------------------------------------------- /routes/api.php: -------------------------------------------------------------------------------- 1 | 11 | * Date: Thu Oct 15 00:09:15 2020 +0000 12 | * 13 | * @see https://flightphp.com/learn 14 | */ 15 | 16 | # require the route files 17 | $app = Gazelle\App::go(); 18 | $app->recursiveGlob(__DIR__ . "/api"); 19 | 20 | # not found 21 | Flight::route("*", function () { 22 | Gazelle\Api\Base::failure(404, "not found"); 23 | }); 24 | 25 | # start the router 26 | Flight::start(); 27 | -------------------------------------------------------------------------------- /routes/api/bonusPoints.php: -------------------------------------------------------------------------------- 1 | addMiddleware(function () { 12 | $app = Gazelle\App::go(); 13 | $app->middleware(["collages" => "read"]); 14 | }); 15 | 16 | 17 | # create 18 | Flight::post("/api/collages", ["Gazelle\Api\Collages", "create"])->addMiddleware(function () { 19 | $app = Gazelle\App::go(); 20 | $app->middleware(["collages" => "create"]); 21 | }); 22 | 23 | 24 | # read 25 | Flight::route("/api/collages/@identifier", ["Gazelle\Api\Collages", "read"])->addMiddleware(function () { 26 | $app = Gazelle\App::go(); 27 | $app->middleware(["collages" => "read"]); 28 | }); 29 | 30 | 31 | # update 32 | Flight::patch("/api/collages/@identifier", ["Gazelle\Api\Collages", "update"])->addMiddleware(function () { 33 | $app = Gazelle\App::go(); 34 | $app->middleware(["collages" => "update"]); 35 | }); 36 | 37 | 38 | # delete 39 | Flight::delete("/api/collages/@identifier", ["Gazelle\Api\Collages", "delete"])->addMiddleware(function () { 40 | $app = Gazelle\App::go(); 41 | $app->middleware(["collages" => "delete"]); 42 | }); 43 | -------------------------------------------------------------------------------- /routes/api/creators.php: -------------------------------------------------------------------------------- 1 | addMiddleware(function () { 12 | $app = Gazelle\App::go(); 13 | $app->middleware(["creators" => "read"]); 14 | }); 15 | 16 | 17 | # create 18 | Flight::post("/api/creators", ["Gazelle\Api\Creators", "create"])->addMiddleware(function () { 19 | $app = Gazelle\App::go(); 20 | $app->middleware(["creators" => "create"]); 21 | }); 22 | 23 | 24 | # read 25 | Flight::route("/api/creators/@identifier", ["Gazelle\Api\Creators", "read"])->addMiddleware(function () { 26 | $app = Gazelle\App::go(); 27 | $app->middleware(["creators" => "read"]); 28 | }); 29 | 30 | 31 | # update 32 | Flight::patch("/api/creators/@identifier", ["Gazelle\Api\Creators", "update"])->addMiddleware(function () { 33 | $app = Gazelle\App::go(); 34 | $app->middleware(["creators" => "update"]); 35 | }); 36 | 37 | 38 | # delete 39 | Flight::delete("/api/creators/@identifier", ["Gazelle\Api\Creators", "delete"])->addMiddleware(function () { 40 | $app = Gazelle\App::go(); 41 | $app->middleware(["creators" => "delete"]); 42 | }); 43 | -------------------------------------------------------------------------------- /routes/api/friends.php: -------------------------------------------------------------------------------- 1 | addMiddleware(function () { 12 | $app = Gazelle\App::go(); 13 | $app->middleware(["userProfiles" => "create"]); 14 | }); 15 | 16 | 17 | # read 18 | Flight::route("/api/friends(/@identifier)", ["Gazelle\Api\Friends", "read"])->addMiddleware(function () { 19 | $app = Gazelle\App::go(); 20 | $app->middleware(["userProfiles" => "read"]); 21 | }); 22 | 23 | 24 | # update 25 | Flight::patch("/api/friends/@identifier", ["Gazelle\Api\Friends", "update"])->addMiddleware(function () { 26 | $app = Gazelle\App::go(); 27 | $app->middleware(["userProfiles" => "update"]); 28 | }); 29 | 30 | 31 | # delete 32 | Flight::delete("/api/friends/@identifier", ["Gazelle\Api\Friends", "delete"])->addMiddleware(function () { 33 | $app = Gazelle\App::go(); 34 | $app->middleware(["userProfiles" => "delete"]); 35 | }); 36 | -------------------------------------------------------------------------------- /routes/api/meta.php: -------------------------------------------------------------------------------- 1 | addMiddleware(function () { 12 | $app = Gazelle\App::go(); 13 | $app->middleware(["requests" => "read"]); 14 | }); 15 | 16 | 17 | # create 18 | Flight::post("/api/requests", ["Gazelle\Api\Requests", "create"])->addMiddleware(function () { 19 | $app = Gazelle\App::go(); 20 | $app->middleware(["requests" => "create"]); 21 | }); 22 | 23 | 24 | # read 25 | Flight::route("/api/requests/@identifier", ["Gazelle\Api\Requests", "read"])->addMiddleware(function () { 26 | $app = Gazelle\App::go(); 27 | $app->middleware(["requests" => "read"]); 28 | }); 29 | 30 | 31 | # update 32 | Flight::patch("/api/requests/@identifier", ["Gazelle\Api\Requests", "update"])->addMiddleware(function () { 33 | $app = Gazelle\App::go(); 34 | $app->middleware(["requests" => "update"]); 35 | }); 36 | 37 | 38 | # delete 39 | Flight::delete("/api/requests/@identifier", ["Gazelle\Api\Requests", "delete"])->addMiddleware(function () { 40 | $app = Gazelle\App::go(); 41 | $app->middleware(["requests" => "delete"]); 42 | }); 43 | -------------------------------------------------------------------------------- /routes/api/top10.php: -------------------------------------------------------------------------------- 1 | addMiddleware(function () { 12 | $app = Gazelle\App::go(); 13 | $app->middleware(["torrents" => "read"]); 14 | }); 15 | 16 | 17 | # tags 18 | Flight::route("/api/top10/tags(/@limit)", ["Gazelle\Api\Top10", "tags"])->addMiddleware(function () { 19 | $app = Gazelle\App::go(); 20 | $app->middleware(["tags" => "read"]); 21 | }); 22 | 23 | 24 | # users 25 | Flight::route("/api/top10/users(/@limit)", ["Gazelle\Api\Top10", "users"])->addMiddleware(function () { 26 | $app = Gazelle\App::go(); 27 | $app->middleware(["userProfiles" => "read"]); 28 | }); 29 | -------------------------------------------------------------------------------- /routes/api/torrents.php: -------------------------------------------------------------------------------- 1 | addMiddleware(function () { 12 | $app = Gazelle\App::go(); 13 | $app->middleware(["torrents" => "create"]); 14 | }); 15 | 16 | 17 | # read 18 | Flight::route("/api/torrents/@identifier", ["Gazelle\Api\Torrents", "read"])->addMiddleware(function () { 19 | $app = Gazelle\App::go(); 20 | $app->middleware(["torrents" => "read"]); 21 | }); 22 | 23 | 24 | # update 25 | Flight::patch("/api/torrents/@identifier", ["Gazelle\Api\Torrents", "update"])->addMiddleware(function () { 26 | $app = Gazelle\App::go(); 27 | $app->middleware(["torrents" => "update"]); 28 | }); 29 | 30 | 31 | # delete 32 | Flight::delete("/api/torrents/@identifier", ["Gazelle\Api\Torrents", "delete"])->addMiddleware(function () { 33 | $app = Gazelle\App::go(); 34 | $app->middleware(["torrents" => "delete"]); 35 | }); 36 | -------------------------------------------------------------------------------- /routes/api/wiki.php: -------------------------------------------------------------------------------- 1 | addMiddleware(function () { 12 | $app = Gazelle\App::go(); 13 | $app->middleware(["wiki" => "create"]); 14 | }); 15 | 16 | 17 | # read 18 | Flight::route("/api/wiki/@identifier", ["Gazelle\Api\Wiki", "read"])->addMiddleware(function () { 19 | $app = Gazelle\App::go(); 20 | $app->middleware(["wiki" => "read"]); 21 | }); 22 | 23 | 24 | # update 25 | Flight::patch("/api/wiki/@identifier", ["Gazelle\Api\Wiki", "update"])->addMiddleware(function () { 26 | $app = Gazelle\App::go(); 27 | $app->middleware(["wiki" => "update"]); 28 | }); 29 | 30 | 31 | # delete 32 | Flight::delete("/api/wiki/@identifier", ["Gazelle\Api\Wiki", "delete"])->addMiddleware(function () { 33 | $app = Gazelle\App::go(); 34 | $app->middleware(["wiki" => "delete"]); 35 | }); 36 | -------------------------------------------------------------------------------- /routes/apiAuthentication.php: -------------------------------------------------------------------------------- 1 | env->serverRoot}/sections/bonusPoints/store.php"; 14 | }); 15 | 16 | 17 | # checkout 18 | Flight::route("/store/checkout/@item", function ($item) { 19 | $app = Gazelle\App::go(); 20 | require_once "{$app->env->serverRoot}/sections/bonusPoints/checkout.php"; 21 | }); 22 | 23 | 24 | # confirm 25 | Flight::route("/store/confirm", function () { 26 | $app = Gazelle\App::go(); 27 | require_once "{$app->env->serverRoot}/sections/bonusPoints/confirm.php"; 28 | }); 29 | -------------------------------------------------------------------------------- /routes/web/conversations.php: -------------------------------------------------------------------------------- 1 | middleware(["conversations" => "create"]); 14 | require_once "{$app->env->serverRoot}/sections/conversations/createMessage.php"; 15 | }); 16 | 17 | # user conversations 18 | Flight::route("/userNew/conversations", function () { 19 | $app = Gazelle\App::go(); 20 | $app->middleware(["conversations" => "read"]); 21 | require_once "{$app->env->serverRoot}/sections/conversations/user.php"; 22 | }); 23 | -------------------------------------------------------------------------------- /routes/web/siteLog.php: -------------------------------------------------------------------------------- 1 | middleware(["torrents" => "read"]); 14 | require_once "{$app->env->serverRoot}/sections/log/index.php"; 15 | 16 | }); 17 | -------------------------------------------------------------------------------- /routes/web/stats.php: -------------------------------------------------------------------------------- 1 | env->serverRoot}/sections/stats/torrents.php"; 14 | }); 15 | 16 | 17 | # users 18 | Flight::route("/stats/users", function () { 19 | $app = Gazelle\App::go(); 20 | require_once "{$app->env->serverRoot}/sections/stats/users.php"; 21 | }); 22 | -------------------------------------------------------------------------------- /routes/web/top10.php: -------------------------------------------------------------------------------- 1 | middleware(["torrents" => "read"]); 14 | require_once "{$app->env->serverRoot}/sections/top10/torrents.php"; 15 | }); 16 | 17 | 18 | # tags 19 | Flight::route("/top10/tags", function () { 20 | $app = Gazelle\App::go(); 21 | $app->middleware(["tags" => "read"]); 22 | require_once "{$app->env->serverRoot}/sections/top10/tags.php"; 23 | }); 24 | 25 | 26 | # users 27 | Flight::route("/top10/users", function () { 28 | $app = Gazelle\App::go(); 29 | $app->middleware(["userProfiles" => "read"]); 30 | require_once "{$app->env->serverRoot}/sections/top10/users.php"; 31 | }); 32 | -------------------------------------------------------------------------------- /routes/web/user.php: -------------------------------------------------------------------------------- 1 | env->serverRoot}/sections/user/friends.php"; 14 | }); 15 | 16 | 17 | # staff 18 | Flight::route("/staff", function () { 19 | $app = Gazelle\App::go(); 20 | require_once "{$app->env->serverRoot}/sections/user/staff.php"; 21 | }); 22 | 23 | 24 | # inbox 25 | Flight::route("/inbox", function () { 26 | $app = Gazelle\App::go(); 27 | require_once "{$app->env->serverRoot}/sections/inbox/inbox.php"; 28 | }); 29 | -------------------------------------------------------------------------------- /sections/api/bookmarks/index.php: -------------------------------------------------------------------------------- 1 | 'failure' 44 | ) 45 | ); 46 | error(); 47 | */ 48 | } 49 | -------------------------------------------------------------------------------- /sections/api/get_user_notifications.php: -------------------------------------------------------------------------------- 1 | user->core['id'], $Skip); 9 | \Gazelle\Api\Base::success(200, $NotificationsManager->get_notifications()); 10 | -------------------------------------------------------------------------------- /sections/api/inbox/index.php: -------------------------------------------------------------------------------- 1 | 'failure')); 11 | error(); 12 | } 13 | -------------------------------------------------------------------------------- /sections/api/top10/index.php: -------------------------------------------------------------------------------- 1 | 'failure')); 26 | break; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /sections/better/badFolders.php: -------------------------------------------------------------------------------- 1 | twig->display("better/list.twig", [ 22 | "title" => "Torrent groups with bad folder names", 23 | "header" => "Torrent groups with bad folder names", 24 | "sidebar" => true, 25 | 26 | "breadcrumbs" => [ 27 | "/torrents" => "torrents", 28 | "/better" => "better", 29 | ], 30 | 31 | "torrentGroups" => $torrentGroups, 32 | "snatchedOnly" => $snatchedOnly, 33 | "currentPage" => "bad-folders", 34 | ]); 35 | -------------------------------------------------------------------------------- /sections/better/badTags.php: -------------------------------------------------------------------------------- 1 | twig->display("better/list.twig", [ 22 | "title" => "Torrents with bad tags", 23 | "header" => "Torrents with bad tags", 24 | "sidebar" => true, 25 | 26 | "breadcrumbs" => [ 27 | "/torrents" => "torrents", 28 | "/better" => "better", 29 | ], 30 | 31 | "torrentGroups" => $torrentGroups, 32 | "snatchedOnly" => $snatchedOnly, 33 | "currentPage" => "bad-tags", 34 | ]); 35 | -------------------------------------------------------------------------------- /sections/better/missingCitations.php: -------------------------------------------------------------------------------- 1 | twig->display("better/list.twig", [ 22 | "title" => "Torrent groups with no publications", 23 | "header" => "Torrent groups with no publications", 24 | "sidebar" => true, 25 | 26 | "breadcrumbs" => [ 27 | "/torrents" => "torrents", 28 | "/better" => "better", 29 | ], 30 | 31 | "torrentGroups" => $torrentGroups, 32 | "snatchedOnly" => $snatchedOnly, 33 | "currentPage" => "missing-citations", 34 | ]); 35 | -------------------------------------------------------------------------------- /sections/better/missingPictures.php: -------------------------------------------------------------------------------- 1 | twig->display("better/list.twig", [ 22 | "title" => "Torrent groups groups with no picture", 23 | "header" => "Torrent groups groups with no picture", 24 | "sidebar" => true, 25 | 26 | "breadcrumbs" => [ 27 | "/torrents" => "torrents", 28 | "/better" => "better", 29 | ], 30 | 31 | "torrentGroups" => $torrentGroups, 32 | "snatchedOnly" => $snatchedOnly, 33 | "currentPage" => "missing-pictures", 34 | ]); 35 | -------------------------------------------------------------------------------- /sections/better/singleSeeder.php: -------------------------------------------------------------------------------- 1 | twig->display("better/list.twig", [ 17 | "title" => "Torrent groups with only one seeder", 18 | "header" => "Torrent groups with only one seeder", 19 | "sidebar" => true, 20 | 21 | "breadcrumbs" => [ 22 | "/torrents" => "torrents", 23 | "/better" => "better", 24 | ], 25 | 26 | "torrentGroups" => $torrentGroups, 27 | "snatchedOnly" => null, 28 | "currentPage" => "single-seeder", 29 | ]); 30 | -------------------------------------------------------------------------------- /sections/bookmarks/remove.php: -------------------------------------------------------------------------------- 1 | dbOld->query(" 21 | DELETE FROM $Table 22 | WHERE UserID = {$app->user->core['id']} 23 | AND $Col = $PageID"); 24 | $app->cache->delete("bookmarks_{$Type}_$UserID"); 25 | 26 | if ($app->dbOld->affected_rows()) { 27 | if ($Type === 'torrent') { 28 | $app->cache->delete("bookmarks_group_ids_$UserID"); 29 | } elseif ($Type === 'request') { 30 | $app->dbOld->query(" 31 | SELECT UserID 32 | FROM $Table 33 | WHERE $Col = $PageID"); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /sections/collages/delete.php: -------------------------------------------------------------------------------- 1 | error(404); 15 | } 16 | 17 | try { 18 | $collage = new Gazelle\Collages($id); 19 | $collage->delete(); 20 | } catch (Throwable $e) { 21 | $app->error(404); 22 | } 23 | 24 | # redirect to collages index 25 | Gazelle\Http::redirect("/collages"); 26 | -------------------------------------------------------------------------------- /sections/commentsOld/get.php: -------------------------------------------------------------------------------- 1 | dbOld->query(" 13 | SELECT Body 14 | FROM comments 15 | WHERE ID = $PostID"); 16 | list($Body) = $app->dbOld->next_record(MYSQLI_NUM); 17 | 18 | echo trim($Body); 19 | -------------------------------------------------------------------------------- /sections/commentsOld/take_delete.php: -------------------------------------------------------------------------------- 1 | user->cant(["messages" => "delete"])) { 12 | error(403); 13 | } 14 | 15 | \Gazelle\Conversations::delete((int)$_GET['postid']); 16 | -------------------------------------------------------------------------------- /sections/commentsOld/take_edit.php: -------------------------------------------------------------------------------- 1 | user->extra['DisablePosting']) { 10 | error('Your posting privileges have been removed.'); 11 | } 12 | 13 | $SendPM = isset($_POST['pm']) && $_POST['pm']; 14 | \Gazelle\Conversations::edit((int)$_POST['postid'], $_POST['body'], $SendPM); 15 | 16 | // This gets sent to the browser, which echoes it in place of the old body 17 | echo \Gazelle\Text::parse($_POST['body']); 18 | -------------------------------------------------------------------------------- /sections/commentsOld/take_post.php: -------------------------------------------------------------------------------- 1 | user->cant(["messages" => "create"])) { 25 | error("Your posting privileges have been removed."); 26 | } 27 | */ 28 | 29 | $Page = $_REQUEST['page']; 30 | $PageID = (int)$_POST['pageid']; 31 | if (!$PageID) { 32 | error(404); 33 | } 34 | 35 | if (isset($_POST['subscribe']) && Subscriptions::has_subscribed_comments($Page, $PageID) === false) { 36 | Subscriptions::subscribe_comments($Page, $PageID); 37 | } 38 | 39 | $PostID = \Gazelle\Conversations::post($Page, $PageID, $_POST['body']); 40 | 41 | header("Location: " . \Gazelle\Conversations::get_url($Page, $PageID, $PostID)); 42 | die(); 43 | -------------------------------------------------------------------------------- /sections/conversations/user.php: -------------------------------------------------------------------------------- 1 | user->core["id"]); 13 | !d($conversations);exit; 14 | -------------------------------------------------------------------------------- /sections/discourse/boards/category.php: -------------------------------------------------------------------------------- 1 | getCategory($categorySlug); 12 | $category = array_shift($category); 13 | #!d($category);exit; 14 | 15 | # topics 16 | $topics = $discourse->listCategoryTopics($categorySlug); 17 | $topics = array_column($topics, "topics"); 18 | $topics = array_shift($topics); 19 | #!d($topics);exit; 20 | 21 | 22 | $app->twig->display( 23 | "discourse/boards/category.twig", 24 | [ 25 | "sidebar" => true, 26 | "title" => $category["name"], 27 | "category" => $category, 28 | "topics" => $topics, 29 | ] 30 | ); 31 | -------------------------------------------------------------------------------- /sections/discourse/boards/newEdit.php: -------------------------------------------------------------------------------- 1 | getCategory($categorySlug); 13 | $category = array_shift($category); 14 | #!d($category);exit; 15 | 16 | # topics 17 | $topics = $discourse->listCategoryTopics($categorySlug); 18 | $topics = array_column($topics, "topics"); 19 | $topics = array_shift($topics); 20 | #!d($topics);exit; 21 | */ 22 | 23 | $app->twig->display( 24 | "discourse/boards/newEdit.twig", 25 | [ 26 | "sidebar" => true, 27 | "title" => "Manage your topic", 28 | #"category" => $category, 29 | #"topics" => $topics, 30 | ] 31 | ); 32 | -------------------------------------------------------------------------------- /sections/discourse/boards/topic.php: -------------------------------------------------------------------------------- 1 | listCategoryTopics($categorySlug); 13 | $topics = array_column($topics, "topics"); 14 | $topics = array_shift($topics); 15 | #!d($topics);exit; 16 | 17 | # find the right one 18 | # (by path slug) 19 | $topicId ??= null; 20 | foreach ($topics as $topic) { 21 | if ($topicSlug === $topic["slug"]) { 22 | $topicId = $topic["id"]; 23 | break; 24 | } 25 | } 26 | 27 | $topic = $discourse->getTopic($topicId); 28 | #!d($topic);exit; 29 | 30 | 31 | $app->twig->display( 32 | "discourse/boards/topic.twig", 33 | [ 34 | "sidebar" => true, 35 | "title" => $topic["title"], 36 | "category" => $categorySlug, 37 | "topic" => $topic, 38 | ] 39 | ); 40 | -------------------------------------------------------------------------------- /sections/forumsOld/catchup.php: -------------------------------------------------------------------------------- 1 | dbOld->query(" 12 | UPDATE users_info 13 | SET CatchupTime = NOW() 14 | WHERE UserID = {$app->user->core['id']}"); 15 | $app->cache->delete('user_info_' . $app->user->core['id']); 16 | Gazelle\Http::redirect("forums.php"); 17 | } else { 18 | // Insert a value for each topic 19 | $app->dbOld->query(" 20 | INSERT INTO forums_last_read_topics (UserID, TopicID, PostID) 21 | SELECT '{$app->user->core['id']}', ID, LastPostID 22 | FROM forums_topics 23 | WHERE (LastPostTime > '" . time_minus(3600 * 24 * 30) . "' OR IsSticky = '1') 24 | AND ForumID = " . $_GET['forumid'] . " 25 | ON DUPLICATE KEY UPDATE 26 | PostID = LastPostID"); 27 | 28 | header('Location: forums.php?action=viewforum&forumid=' . $_GET['forumid']); 29 | } 30 | -------------------------------------------------------------------------------- /sections/forumsOld/change_vote.php: -------------------------------------------------------------------------------- 1 | user->cant(["polls" => "update"])) { 14 | $app->dbOld->query(" 15 | SELECT 16 | `ForumID` 17 | FROM 18 | `forums_topics` 19 | WHERE 20 | `ID` = $ThreadID 21 | "); 22 | list($ForumID) = $app->dbOld->next_record(); 23 | 24 | /* 25 | if (!in_array($ForumID, FORUMS_TO_REVEAL_VOTERS)) { 26 | error(403); 27 | } 28 | */ 29 | } 30 | 31 | $app->dbOld->query( 32 | " 33 | UPDATE 34 | `forums_polls_votes` 35 | SET 36 | `Vote` = $NewVote 37 | WHERE 38 | `TopicID` = $ThreadID 39 | AND `UserID` = " . $app->user->core['id'] 40 | ); 41 | 42 | $app->cache->delete("polls_$ThreadID"); 43 | Gazelle\Http::redirect("forums.php?action=viewthread&threadid=$ThreadID"); 44 | } else { 45 | error(404); 46 | } 47 | -------------------------------------------------------------------------------- /sections/forumsOld/take_topic_notes.php: -------------------------------------------------------------------------------- 1 | user->cant(["admin" => "moderateForums"])) { 6 | error(403); 7 | } 8 | 9 | if (!isset($_POST['topicid'], $_POST['body']) || !is_numeric($_POST['topicid']) || $_POST['body'] == '') { 10 | error(404); 11 | } 12 | 13 | $TopicID = (int) $_POST['topicid']; 14 | 15 | Forums::add_topic_note($TopicID, $_POST['body']); 16 | 17 | Gazelle\Http::redirect("forums.php?action=viewthread&threadid=$TopicID#thread_notes"); 18 | die(); 19 | -------------------------------------------------------------------------------- /sections/image/err_imgs/badprotocol.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/biotorrents/gazelle/29e89642f3b2da8901643d1db1f36566007f0f96/sections/image/err_imgs/badprotocol.png -------------------------------------------------------------------------------- /sections/image/err_imgs/forbidden.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/biotorrents/gazelle/29e89642f3b2da8901643d1db1f36566007f0f96/sections/image/err_imgs/forbidden.png -------------------------------------------------------------------------------- /sections/image/err_imgs/invalid.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/biotorrents/gazelle/29e89642f3b2da8901643d1db1f36566007f0f96/sections/image/err_imgs/invalid.png -------------------------------------------------------------------------------- /sections/image/err_imgs/invisible.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/biotorrents/gazelle/29e89642f3b2da8901643d1db1f36566007f0f96/sections/image/err_imgs/invisible.png -------------------------------------------------------------------------------- /sections/image/err_imgs/nogd.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/biotorrents/gazelle/29e89642f3b2da8901643d1db1f36566007f0f96/sections/image/err_imgs/nogd.png -------------------------------------------------------------------------------- /sections/image/err_imgs/small.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/biotorrents/gazelle/29e89642f3b2da8901643d1db1f36566007f0f96/sections/image/err_imgs/small.png -------------------------------------------------------------------------------- /sections/image/err_imgs/timeout.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/biotorrents/gazelle/29e89642f3b2da8901643d1db1f36566007f0f96/sections/image/err_imgs/timeout.png -------------------------------------------------------------------------------- /sections/log/sql.php: -------------------------------------------------------------------------------- 1 | user->cant(["admin" => "readSiteLog"])) { 33 | if ($Search) { 34 | $SQL .= ' AND '; 35 | } else { 36 | $SQL .= ' WHERE '; 37 | } 38 | $SQL .= " Time>'" . time_minus(3600 * 24 * 28) . "' "; 39 | } 40 | 41 | $SQL .= " 42 | ORDER BY 43 | `ID` 44 | DESC 45 | LIMIT $Limit 46 | "; 47 | 48 | $Log = $app->dbOld->query($SQL); 49 | $app->dbOld->query('SELECT FOUND_ROWS()'); 50 | list($NumResults) = $app->dbOld->next_record(); 51 | $TotalMatches = $NumResults; 52 | $app->dbOld->set_query_id($Log); 53 | -------------------------------------------------------------------------------- /sections/publications/details.php: -------------------------------------------------------------------------------- 1 | id) { 17 | throw new Exception("not found"); 18 | } 19 | } catch (Throwable $e) { 20 | $app->error(404); 21 | } 22 | 23 | # request variables 24 | $get = Gazelle\Http::request("get"); 25 | $post = Gazelle\Http::request("post"); 26 | 27 | # create a conversation if it doesn't exist 28 | $conversation = Gazelle\Conversations::createIfNotExists($publication->id, "publications"); 29 | 30 | # twig template 31 | $app->twig->display("publication/details.twig", [ 32 | "title" => $publication->attributes->name, 33 | "sidebar" => true, 34 | 35 | "css" => [], 36 | "js" => ["conversations"], 37 | 38 | "breadcrumbs" => [ 39 | "/publications" => "publications", 40 | "/publications/{$publication->id}" => $publication->attributes->name, 41 | ], 42 | 43 | "publication" => $publication, 44 | 45 | "enableConversation" => true, 46 | "conversation" => $conversation, 47 | ]); 48 | -------------------------------------------------------------------------------- /sections/reports/ajax_add_notes.php: -------------------------------------------------------------------------------- 1 | user->cant(["admin" => "reports"]) || empty($_POST['id'])) { 8 | print 9 | json_encode( 10 | array( 11 | 'status' => 'failure' 12 | ) 13 | ); 14 | die(); 15 | } 16 | 17 | $ID = (int)$_POST['id']; 18 | 19 | $Notes = $_POST['notes']; 20 | 21 | $app->dbOld->query(" 22 | UPDATE reports 23 | SET Notes = ? 24 | WHERE ID = ?", $Notes, $ID); 25 | print 26 | json_encode( 27 | array( 28 | 'status' => 'success' 29 | ) 30 | ); 31 | die(); 32 | -------------------------------------------------------------------------------- /sections/reports/ajax_claim_report.php: -------------------------------------------------------------------------------- 1 | user->cant(["admin" => "reports"]) || empty($_POST['id'])) { 8 | print 9 | json_encode( 10 | array( 11 | 'status' => 'failure' 12 | ) 13 | ); 14 | die(); 15 | } 16 | 17 | $ID = (int)$_POST['id']; 18 | $app->dbOld->query(" 19 | SELECT ClaimerID 20 | FROM reports 21 | WHERE ID = '$ID'"); 22 | list($ClaimerID) = $app->dbOld->next_record(); 23 | if ($ClaimerID) { 24 | print 25 | json_encode( 26 | array( 27 | 'status' => 'dupe' 28 | ) 29 | ); 30 | die(); 31 | } else { 32 | $UserID = $app->user->core['id']; 33 | $app->dbOld->query(" 34 | UPDATE reports 35 | SET ClaimerID = '$UserID' 36 | WHERE ID = '$ID'"); 37 | print 38 | json_encode( 39 | array( 40 | 'status' => 'success', 41 | 'username' => $app->user->core['username'] 42 | ) 43 | ); 44 | die(); 45 | } 46 | -------------------------------------------------------------------------------- /sections/reports/ajax_unclaim_report.php: -------------------------------------------------------------------------------- 1 | user->cant(["admin" => "moderateForums"]) || empty($_POST['id']) || empty($_POST['remove'])) { 8 | print 9 | json_encode( 10 | array( 11 | 'status' => 'failure' 12 | ) 13 | ); 14 | die(); 15 | } 16 | $ID = (int)$_POST['id']; 17 | $app->dbOld->query("UPDATE reports SET ClaimerID = '0' WHERE ID = '$ID'"); 18 | print 19 | json_encode( 20 | array( 21 | 'status' => 'success', 22 | ) 23 | ); 24 | die(); 25 | -------------------------------------------------------------------------------- /sections/reportsv2/ajax_giveback_report.php: -------------------------------------------------------------------------------- 1 | user->cant(["admin" => "reports"])) { 6 | error('403'); 7 | } 8 | 9 | if (!is_numeric($_GET['id'])) { 10 | error(); 11 | } 12 | 13 | $app->dbOld->prepared_query(" 14 | SELECT Status 15 | FROM reportsv2 16 | WHERE ID = ".$_GET['id']); 17 | list($Status) = $app->dbOld->next_record(); 18 | if (isset($Status)) { 19 | $app->dbOld->prepared_query(" 20 | UPDATE reportsv2 21 | SET Status = 'New', ResolverID = 0 22 | WHERE ID = ".$_GET['id']); 23 | } 24 | -------------------------------------------------------------------------------- /sections/reportsv2/ajax_grab_report.php: -------------------------------------------------------------------------------- 1 | user->cant(["admin" => "reports"])) { 10 | //error(403); 11 | echo '403'; 12 | error(); 13 | } 14 | 15 | if (!is_numeric($_GET['id'])) { 16 | error(); 17 | } 18 | 19 | $app->dbOld->prepared_query(" 20 | UPDATE reportsv2 21 | SET Status = 'InProgress', 22 | ResolverID = " . $app->user->core['id'] . " 23 | WHERE ID = " . $_GET['id']); 24 | 25 | if ($app->dbOld->affected_rows() == 0) { 26 | echo '0'; 27 | } else { 28 | echo '1'; 29 | } 30 | -------------------------------------------------------------------------------- /sections/reportsv2/ajax_update_comment.php: -------------------------------------------------------------------------------- 1 | user->cant(["admin" => "reports"])) { 10 | error(403); 11 | } 12 | 13 | $ReportID = (int) $_POST['reportid']; 14 | 15 | $Message = db_string($_POST['comment']); 16 | //Message can be blank! 17 | 18 | $app->dbOld->prepared_query(" 19 | SELECT ModComment 20 | FROM reportsv2 21 | WHERE ID = $ReportID"); 22 | list($ModComment) = $app->dbOld->next_record(); 23 | if (isset($ModComment)) { 24 | $app->dbOld->prepared_query(" 25 | UPDATE reportsv2 26 | SET ModComment = '$Message' 27 | WHERE ID = $ReportID"); 28 | } 29 | -------------------------------------------------------------------------------- /sections/reportsv2/ajax_update_resolve.php: -------------------------------------------------------------------------------- 1 | user->cant(["admin" => "reports"])) { 8 | error(403); 9 | } 10 | 11 | if (empty($_GET['newresolve'])) { 12 | echo "No new resolve"; 13 | error(); 14 | } 15 | 16 | $ReportID = (int) $_GET['reportid']; 17 | $CategoryID = (int) $_GET['categoryid']; 18 | $NewType = $_GET['newresolve']; 19 | 20 | if (!empty($Types[$CategoryID])) { 21 | $TypeList = $Types['master'] + $Types[$CategoryID]; 22 | $Priorities = []; 23 | foreach ($TypeList as $Key => $Value) { 24 | $Priorities[$Key] = $Value['priority']; 25 | } 26 | array_multisort($Priorities, SORT_ASC, $TypeList); 27 | } else { 28 | $TypeList = $Types['master']; 29 | } 30 | 31 | if (!array_key_exists($NewType, $TypeList)) { 32 | echo "No resolve from that category"; 33 | error(); 34 | } 35 | 36 | $app->dbOld->prepared_query(" 37 | UPDATE reportsv2 38 | SET Type = '$NewType' 39 | WHERE ID = $ReportID"); 40 | -------------------------------------------------------------------------------- /sections/reportsv2/header.php: -------------------------------------------------------------------------------- 1 | 6 | 14 | -------------------------------------------------------------------------------- /sections/reportsv2/search.php: -------------------------------------------------------------------------------- 1 | .> 6 | */ 7 | 8 | if ($app->user->cant(["admin" => "reports"])) { 9 | error(403); 10 | } 11 | 12 | View::header('Reports V2!', 'reportsv2'); 13 | ?> 14 | 15 |
                    16 |

                    Search

                    17 | 18 |
                    19 |
                    20 | On hold until someone fixes the main torrents search. 21 |
                    22 | dbOld->query( 9 | " 10 | SELECT 11 | i.SupportFor, 12 | p.DisplayStaff 13 | FROM users_info AS i 14 | JOIN users_main AS m ON m.ID = i.UserID 15 | JOIN permissions AS p ON p.ID = m.PermissionID 16 | WHERE i.UserID = ".$app->user->core['id'] 17 | ); 18 | list($SupportFor, $DisplayStaff) = $app->dbOld->next_record(); 19 | 20 | if (!($SupportFor != '' || $DisplayStaff == '1')) { 21 | // Logged in user is not FLS or Staff 22 | error(403); 23 | } 24 | 25 | if ($ID = (int)$_POST['id']) { 26 | $app->dbOld->query(" 27 | DELETE FROM staff_pm_responses 28 | WHERE ID = $ID"); 29 | echo '1'; 30 | } else { 31 | // No ID 32 | echo '-1'; 33 | } 34 | -------------------------------------------------------------------------------- /sections/staffpm/ajax_get_response.php: -------------------------------------------------------------------------------- 1 | dbOld->query( 9 | " 10 | SELECT 11 | i.SupportFor, 12 | p.DisplayStaff 13 | FROM users_info AS i 14 | JOIN users_main AS m ON m.ID = i.UserID 15 | JOIN permissions AS p ON p.ID = m.PermissionID 16 | WHERE i.UserID = ".$app->user->core['id'] 17 | ); 18 | list($SupportFor, $DisplayStaff) = $app->dbOld->next_record(); 19 | 20 | if (!$IsFLS) { 21 | // Logged in user is not FLS or Staff 22 | error(403); 23 | } 24 | 25 | if ($ID = (int)$_GET['id']) { 26 | $app->dbOld->query(" 27 | SELECT Message 28 | FROM staff_pm_responses 29 | WHERE ID = $ID"); 30 | list($Message) = $app->dbOld->next_record(); 31 | if ($_GET['plain'] == 1) { 32 | echo $Message; 33 | } else { 34 | echo \Gazelle\Text::parse($Message); 35 | } 36 | } else { 37 | // No ID 38 | echo '-1'; 39 | } 40 | -------------------------------------------------------------------------------- /sections/staffpm/ajax_preview_response.php: -------------------------------------------------------------------------------- 1 | dbOld->query(" 8 | SELECT UserID, AssignedToUser 9 | FROM staff_pm_conversations 10 | WHERE ID = $ID"); 11 | list($UserID, $AssignedToUser) = $app->dbOld->next_record(); 12 | 13 | if ($UserID == $app->user->core['id'] || $IsFLS || $AssignedToUser == $app->user->core['id']) { 14 | // Conversation belongs to user or user is staff, resolve it 15 | $app->dbOld->query(" 16 | UPDATE staff_pm_conversations 17 | SET Status = 'Resolved', ResolverID = {$app->user->core['id']} 18 | WHERE ID = $ID"); 19 | $app->cache->delete("staff_pm_new_{$app->user->core['id']}"); 20 | $app->cache->delete("num_staff_pms_{$app->user->core['id']}"); 21 | 22 | Gazelle\Http::redirect("staffpm.php"); 23 | } else { 24 | // Conversation does not belong to user 25 | error(403); 26 | } 27 | } else { 28 | // No ID 29 | Gazelle\Http::redirect("staffpm.php"); 30 | } 31 | -------------------------------------------------------------------------------- /sections/stats/torrents.php: -------------------------------------------------------------------------------- 1 | economyOverTime(); 14 | $trackerEconomy = $stats->trackerEconomy(); 15 | $torrentsTimeline = $stats->torrentsTimeline(); 16 | $categoryDistribution = $stats->categoryDistribution(); 17 | $databaseSpecifics = $stats->databaseSpecifics(); 18 | 19 | $app->twig->display("stats/torrents.twig", [ 20 | "title" => "Detailed torrent statistics", 21 | "js" => ["vendor/chart.min"], 22 | 23 | "economyOverTime" => $economyOverTime, 24 | "trackerEconomy" => $trackerEconomy, 25 | "torrentsTimeline" => $torrentsTimeline, 26 | "categoryDistribution" => $categoryDistribution, 27 | "databaseSpecifics" => $databaseSpecifics, 28 | ]); 29 | -------------------------------------------------------------------------------- /sections/toolbox/databaseKey.php: -------------------------------------------------------------------------------- 1 | twig->display("admin/databaseKey.twig", [ 24 | "title" => "Database encryption key", 25 | "sidebar" => true, 26 | "isKeySet" => Gazelle\Crypto::apcuExists(), 27 | ]); 28 | -------------------------------------------------------------------------------- /sections/toolbox/managers/email_blacklist.php: -------------------------------------------------------------------------------- 1 | dbNew->multi($query, []); 25 | #!d($data);exit; 26 | 27 | # crud actions 28 | # todo 29 | 30 | # twig template 31 | $app->twig->display("admin/emailBlacklist.twig", [ 32 | "title" => "Manage email blacklist", 33 | "sidebar" => true, 34 | "data" => $data, 35 | "search" => $get["search"], 36 | ]); 37 | -------------------------------------------------------------------------------- /sections/toolbox/managers/email_blacklist_search.php: -------------------------------------------------------------------------------- 1 | dbOld->prepared_query(" 10 | SELECT 11 | ID, 12 | UserID, 13 | Time, 14 | Email, 15 | Comment 16 | FROM email_blacklist 17 | WHERE Email LIKE '%$Search%'"); 18 | 19 | $EmailResults = $app->dbOld->to_array(false, MYSQLI_ASSOC, false); 20 | 21 | $Results = []; 22 | $Count = $app->dbOld->record_count(); 23 | $Results['count'] = $Count; 24 | 25 | $Emails = []; 26 | 27 | if ($Count > 0) { 28 | foreach ($EmailResults as $Email) { 29 | $Emails[] = array( 30 | 'id' => (int)$Email['ID'], 31 | 'email' => $Email['Email'], 32 | 'comment' => $Email['Comment'], 33 | 'userid' => (int)$Email['UserID'], 34 | 'time' => $Email['Time']); 35 | } 36 | } 37 | $Results['emails'] = $Emails; 38 | $JSON['results'] = $Results; 39 | 40 | echo json_encode($JSON); 41 | exit(); 42 | -------------------------------------------------------------------------------- /sections/toolbox/managers/take_global_notification.php: -------------------------------------------------------------------------------- 1 | user->core['id'] : 0; 19 | 20 | $app->dbOld->query(" 21 | (SELECT ID AS UserID FROM users_main WHERE PermissionID = '$PermissionID' AND ID != '$FromID') UNION (SELECT UserID FROM users_levels WHERE PermissionID = '$PermissionID' AND UserID != '$FromID')"); 22 | 23 | while (list($UserID) = $app->dbOld->next_record()) { 24 | Misc::send_pm($UserID, $FromID, $Subject, $Body); 25 | } 26 | 27 | Gazelle\Http::redirect("tools.php"); 28 | -------------------------------------------------------------------------------- /sections/toolbox/misc/quick_ban.php: -------------------------------------------------------------------------------- 1 | dbOld->query('DELETE FROM ip_bans WHERE ID='.$_GET['id']); 14 | $Bans = $app->cache->delete('ip_bans_'.$IPA); 15 | } elseif ($_GET['perform'] == 'create') { 16 | $Notes = db_string($_GET['notes']); 17 | $IP = Tools::ip_to_unsigned($_GET['ip']); //Sanitized by Validation regex 18 | $app->dbOld->query(" 19 | INSERT INTO ip_bans (FromIP, ToIP, Reason) 20 | VALUES ('$IP','$IP', '$Notes')"); 21 | $app->cache->delete('ip_bans_'.$IPA); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /sections/toolbox/roles/listAll.php: -------------------------------------------------------------------------------- 1 | twig->display("admin/roles/listAll.twig", [ 16 | "title" => "User roles", 17 | "roles" => $allRoles, 18 | ]); 19 | -------------------------------------------------------------------------------- /sections/top10/tags.php: -------------------------------------------------------------------------------- 1 | twig->display("top10/tags.twig", [ 19 | "title" => "Top tags", 20 | "sidebar" => true, 21 | 22 | "page" => "tags", 23 | "limit" => $limit, 24 | 25 | "torrentTags" => $torrentTags, 26 | "requestTags" => $requestTags, 27 | ]); 28 | -------------------------------------------------------------------------------- /sections/top10/users.php: -------------------------------------------------------------------------------- 1 | twig->display("top10/users.twig", [ 26 | "title" => "Top users", 27 | "sidebar" => true, 28 | 29 | "page" => "users", 30 | "limit" => $limit, 31 | 32 | "dataUploaded" => $dataUploaded, 33 | "dataDownloaded" => $dataDownloaded, 34 | "uploadCount" => $uploadCount, 35 | ]); 36 | -------------------------------------------------------------------------------- /sections/torrentGroups/history.php: -------------------------------------------------------------------------------- 1 | dbOld->query(" 12 | SELECT `title` 13 | FROM `torrents_group` 14 | WHERE `id` = $GroupID"); 15 | if (!$app->dbOld->has_results()) { 16 | error(404); 17 | } 18 | list($Name) = $app->dbOld->next_record(); 19 | 20 | View::header("Revision history for $Name"); 21 | ?> 22 |
                    23 |
                    24 |

                    Revision history for

                    25 |
                    26 | 29 |
                    30 | user->cant(["torrentGroups" => "update"])) { 7 | error(403); 8 | } 9 | 10 | $ID = $_GET['id']; 11 | $GroupID = $_GET['groupid']; 12 | 13 | 14 | if (!is_numeric($ID) || !is_numeric($ID) || !is_numeric($GroupID) || !is_numeric($GroupID)) { 15 | error(404); 16 | } 17 | 18 | $app->dbOld->query(" 19 | SELECT Image, Summary 20 | FROM cover_art 21 | WHERE ID = '$ID'"); 22 | list($Image, $Summary) = $app->dbOld->next_record(); 23 | 24 | $app->dbOld->query(" 25 | DELETE FROM cover_art 26 | WHERE ID = '$ID'"); 27 | 28 | $app->dbOld->query(" 29 | INSERT INTO group_log 30 | (GroupID, UserID, Time, Info) 31 | VALUES 32 | ('$GroupID', ".$app->user->core['id'].", NOW(), '".db_string("Additional cover \"$Summary - $Image\" removed from group")."')"); 33 | 34 | $app->cache->delete("torrents_cover_art_$GroupID"); 35 | header('Location: '.$_SERVER['HTTP_REFERER']); 36 | -------------------------------------------------------------------------------- /sections/upload/router.php: -------------------------------------------------------------------------------- 1 | user->cant(["torrents" => "create"])) { 22 | error('Please read the site wiki for information on how to become a Member and gain upload privileges.'); 23 | } 24 | 25 | /* 26 | if ($app->user->extra['DisableUpload']) { 27 | error('Your upload privileges have been revoked.'); 28 | } 29 | */ 30 | 31 | // Build the page 32 | if (!empty($_POST['submit'])) { 33 | require_once 'upload_handle.php'; 34 | } else { 35 | require_once serverRoot.'/sections/upload/upload.php'; 36 | } 37 | -------------------------------------------------------------------------------- /sections/user/auth/disabled.php: -------------------------------------------------------------------------------- 1 | env->FEATURE_EMAIL_REENABLE && !empty($username) && !empty($email)) { 21 | # handle auto-enable request 22 | $output = AutoEnable::new_request($username, $email); 23 | } 24 | 25 | $app->twig->display("user/auth/disabled.twig", ["username" => $username, "email" => $email]); 26 | -------------------------------------------------------------------------------- /sections/user/auth/resend.php: -------------------------------------------------------------------------------- 1 | error(400); 18 | } 19 | 20 | try { 21 | $response = $auth->resendConfirmation($identifier); 22 | #!d($response);exit; 23 | 24 | # todo: need to handle warnings vs. errors in response html 25 | $response = "We've sent you a new confirmation email"; 26 | $success = true; 27 | } catch (Throwable $e) { 28 | $response = $e->getMessage(); 29 | $success = false; 30 | } 31 | 32 | # twig template 33 | $app->twig->display("user/auth/confirm.twig", [ 34 | "title" => "Confirm account", 35 | "response" => $response ?? null, 36 | "success" => $success ?? null, 37 | "resendConfirmation" => $resendConfirmation ?? false, 38 | ]); 39 | -------------------------------------------------------------------------------- /sections/user/friends.php: -------------------------------------------------------------------------------- 1 | twig->display("user/friends.twig", [ 17 | "title" => "Friends", 18 | "js" => ["user"], 19 | #"sidebar" => true, 20 | 21 | "friends" => $friends, 22 | "error" => $error ?? null, 23 | ]); 24 | -------------------------------------------------------------------------------- /sections/user/staff.php: -------------------------------------------------------------------------------- 1 | twig->display("user/staff.twig", [ 15 | "title" => "Staff", 16 | "staff" => $staff ?? [], 17 | ]); 18 | -------------------------------------------------------------------------------- /sections/userhistory/catchup_collages.php: -------------------------------------------------------------------------------- 1 | dbOld->query("UPDATE users_collage_subs SET LastVisit = NOW() WHERE UserID = " . $app->user->core['id'] . $Where); 13 | $app->cache->delete('collage_subs_user_new_' . $app->user->core['id']); 14 | 15 | Gazelle\Http::redirect("userhistory.php?action=subscribed_collages"); 16 | -------------------------------------------------------------------------------- /sections/userhistory/comments_subscribe.php: -------------------------------------------------------------------------------- 1 | user->extra['DisableForums'])) { 9 | error(403); 10 | } 11 | 12 | if (!is_numeric($_GET['topicid'])) { 13 | error(0); 14 | } 15 | 16 | $TopicID = (int)$_GET['topicid']; 17 | 18 | $app->dbOld->prepared_query(" 19 | SELECT f.ID 20 | FROM forums_topics AS t 21 | JOIN forums AS f ON f.ID = t.ForumID 22 | WHERE t.ID = $TopicID"); 23 | list($ForumID) = $app->dbOld->next_record(); 24 | if (!Forums::check_forumperm($ForumID)) { 25 | error(); 26 | } 27 | 28 | Subscriptions::subscribe($_GET['topicid']); 29 | -------------------------------------------------------------------------------- /sections/wiki/browse.php: -------------------------------------------------------------------------------- 1 | twig->display("wiki/browse.twig", [ 25 | "title" => "Search the wiki", 26 | 27 | "searchWhat" => $searchWhat, 28 | "titlesOnly" => $titlesOnly, 29 | 30 | "searchResults" => $searchResults, 31 | "resultCount" => $resultCount, 32 | 33 | "isEditorAvailable" => false, 34 | "enableConversation" => false, 35 | ]); 36 | -------------------------------------------------------------------------------- /sections/wiki/create.php: -------------------------------------------------------------------------------- 1 | hydrateNewArticle(); 15 | 16 | # twig template 17 | $app->twig->display("wiki/article.twig", [ 18 | "title" => $article->attributes->title, 19 | "sidebar" => true, 20 | "js" => ["wiki"], 21 | 22 | "article" => $article, 23 | "aliases" => $article->getAliases(), 24 | "roles" => Gazelle\Roles::getAll(), 25 | 26 | "isEditorAvailable" => true, 27 | "enableConversation" => false, 28 | ]); 29 | -------------------------------------------------------------------------------- /sections/wiki/delete.php: -------------------------------------------------------------------------------- 1 | error(404); 16 | } 17 | 18 | # is the id an integer? 19 | if (!is_numeric($id)) { 20 | # no, it's not an integer, so it must be an alias 21 | $id = Gazelle\Wiki::getIdByAlias($id); 22 | } 23 | 24 | # load the article 25 | $article = new Gazelle\Wiki($id); 26 | if (!$article->id) { 27 | $app->error(404); 28 | } 29 | 30 | # try to delete the article 31 | try { 32 | $article->delete($id); 33 | } catch (Throwable $e) { 34 | $app->error($e->getMessage()); 35 | } 36 | 37 | # redirect to the wiki index 38 | Gazelle\Http::redirect("/wiki"); 39 | -------------------------------------------------------------------------------- /shell: -------------------------------------------------------------------------------- 1 | [ __DIR__ . "/bootstrap/cli.php" ], 20 | "updateCheck" => "never", 21 | 22 | # https://github.com/bobthecow/psysh/wiki/Themes 23 | "theme" => [ 24 | "prompt" => "gazelle ⟫ ", 25 | "bufferPrompt" => "⋯ ", 26 | "replayPrompt" => "⤑ ", 27 | "returnValue" => "⇒ ", 28 | ], 29 | ]); 30 | 31 | # load a psysh instance 32 | $shell = new Psy\Shell($config); 33 | $shell->run(); 34 | -------------------------------------------------------------------------------- /templates/_base/breadcrumbs.twig: -------------------------------------------------------------------------------- 1 | {## 2 | # breadcrumbs 3 | #} 4 | 5 | 13 | -------------------------------------------------------------------------------- /templates/_base/metaTags.twig: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 6 | 7 | 8 | 9 | 10 | {# default "index, follow" #} 11 | 12 | 13 | 14 | {# https://developers.facebook.com/tools/debug/ #} 15 | 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /templates/_base/publicHeader.twig: -------------------------------------------------------------------------------- 1 | {# left #} 2 | 3 | Log In 4 | About 5 | Docs 6 | 7 | 8 | {# right #} 9 | 10 | Privacy 11 | DMCA 12 | {# 13 | GitHub 14 | Patreon 15 | #} 16 | -------------------------------------------------------------------------------- /templates/_base/starboardNotebook.twig: -------------------------------------------------------------------------------- 1 | {## 2 | # {% set variables = { "id": someVar, "content": someVar } %} 3 | # {% include "_base/starboardNotebook.twig" with variables %} 4 | # 5 | # https://github.com/gzuidhof/starboard-wrap 6 | #} 7 | 8 |
                    9 | 10 | 21 | -------------------------------------------------------------------------------- /templates/admin/announcekey-history.twig: -------------------------------------------------------------------------------- 1 |
                    2 |

                    {{ user.username }} › Announce Key History

                    3 |
                    4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | {% for change in user.announceKeyHistory %} 12 | 13 | 14 | 15 | 16 | 17 | 18 | {% endfor %} 19 |
                    OldNewChangedIP
                    {{ change.old }}{{ change.new }}{{ change.date|time_diff }}{{ change.ipaddr }}
                    20 | -------------------------------------------------------------------------------- /templates/admin/databaseKey.twig: -------------------------------------------------------------------------------- 1 | {% extends "base.twig" %} 2 | 3 | {% block content %} 4 | 5 |

                    Database encryption key

                    6 | 7 | {# yes key #} 8 | {% if isKeySet %} 9 |
                    10 | There's already a key loaded. 11 |
                    12 | 13 | {# no key #} 14 | {% else %} 15 |
                    16 | There's no key loaded. 17 |
                    18 | 19 | 20 | {% endif %} 21 | 22 |
                    23 |
                    24 | 25 | {{ form_token(http.server.REQUEST_URI) }} 26 | 27 |

                    28 | 29 |

                    30 | 31 |

                    32 | 33 |

                    34 | 35 |
                    36 |
                    37 | 38 | {% endblock %} 39 | 40 | 41 | {% block sidebar %} 42 | 43 | {{ include("admin/sidebar.twig") }} 44 | 45 | {% endblock %} 46 | -------------------------------------------------------------------------------- /templates/admin/duplicate-ipaddr.twig: -------------------------------------------------------------------------------- 1 | {% from 'macro/ipv4.twig' import ajax_ipv4 %} 2 | 3 | {% if list is empty %} 4 |

                    There are currently no users with more than {{ overlap }} IP overlaps.

                    5 | {% else %} 6 | {{ paginator.linkbox|raw }} 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | {% for item in list %} 15 | 16 | 17 | 20 | 21 | 22 | 23 | {% endfor %} 24 |
                    UserIP addressDupesJoined
                    {{ item.user_id }} 18 | {{ ajax_ipv4(item.ipaddr) }} ({{ item.ipaddr }})H S 19 | {{ item.uses|number_format }}{{ item.joined|time_diff }}
                    25 | {{ paginator.linkbox|raw }} 26 | {% endif %} 27 | -------------------------------------------------------------------------------- /templates/admin/sidebar.twig: -------------------------------------------------------------------------------- 1 |

                    Action templates

                    2 | 3 |
                    4 | 5 | create 6 | 7 | read 8 | 9 | update 10 | 11 | delete 12 | 13 |
                    14 | -------------------------------------------------------------------------------- /templates/admin/staffpm-list.twig: -------------------------------------------------------------------------------- 1 | {% for pm in list %} 2 | {% if loop.first %} 3 |
                    4 |
                    5 | Staff PMs View 6 |
                    7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | {% endif %} 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | {% if loop.last %} 24 | 25 |
                    26 | {% endif %} 27 | {% endfor %} 28 | -------------------------------------------------------------------------------- /templates/admin/user-custom-permission.twig: -------------------------------------------------------------------------------- 1 |
                    2 | {% if list is empty %} 3 |

                    There are no users with custom permissions.

                    4 | {% else %} 5 | 6 | 7 | 8 | 9 | 10 | 11 | {% for user_id, permission in list %} 12 | 13 | 14 | 21 | 22 | 23 | {% endfor %} 24 |
                    UserCustom PermissionsAction
                    {{ user_id }} 15 |
                      16 | {% for name, value in permission %} 17 |
                    • {{ name }}
                    • 18 | {% endfor %} 19 |
                    20 |
                    Manage
                    25 | {% endif %} 26 |
                    27 |
                    28 | -------------------------------------------------------------------------------- /templates/admin/user-info-ipv4.twig: -------------------------------------------------------------------------------- 1 | {{ title }} 2 | 3 | Address IPv4 4 | First seen 5 | Last seen 6 | 7 | {% for i in info %} 8 | 9 | {{ i.0 }} 10 | WI 11 | 12 | {{ i.1 }} 13 | {{ i.2 }} 14 | 15 | {% endfor %} 16 | -------------------------------------------------------------------------------- /templates/admin/userflow.twig: -------------------------------------------------------------------------------- 1 |
                    2 | {% if show_flow %} 3 |
                    4 |
                    5 |
                    6 | {% endif %} 7 | {{ paginator.linkbox|raw }} 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | {% for d in details %} 19 | {% set total_out = d.ratio + d.inactivity + d.manual %} 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | {% endfor %} 30 |
                    Date(+) Joined(-) Manual(-) Ratio(-) Inactivity(-) TotalNet Growth
                    {{ d.date }}{{ d.joined|number_format }}{{ d.manual|number_format }}{{ d.ratio|number_format }}{{ d.inactivity|number_format }}{{ total_out|number_format }}{{ (d.joined - total_out)|number_format }}
                    31 | {{ paginator.linkbox|raw }} 32 |
                    33 | 7 |

                    {{ header }}

                    8 | 9 | {# no torrents #} 10 | {% if torrentGroups is empty %} 11 |

                    No torrents found :)

                    12 | {% else %} 13 | {# torrent list #} 14 | {{ include("tables/torrentGroups.twig") }} 15 | {% endif %} 16 | 17 | 18 | {% endblock %} 19 | 20 | 21 | {% block sidebar %} 22 | 23 | {{ include("better/sidebar.twig") }} 24 | 25 | {% endblock %} -------------------------------------------------------------------------------- /templates/better/sidebar.twig: -------------------------------------------------------------------------------- 1 |

                    Actions

                    2 | 3 |
                    4 | single seeder 5 | 6 | missing citations 7 | 8 | missing pictures 9 | 10 | bad tags 11 | 12 | bad folders 13 | 14 |
                    15 | 16 | {% if snatchedOnly %} 17 | show all torrents 18 | {% else %} 19 | show snatched torrents 20 | {% endif %} 21 | 22 | back to index 23 |
                    24 | -------------------------------------------------------------------------------- /templates/bookmark/body.twig: -------------------------------------------------------------------------------- 1 | {% for b in list %} 2 | 3 | 4 | 5 | 6 | {{ loop.index }} 7 | {{ b.year }} 8 | {{ b.artist|raw }}{% if showcase %} [VH]{% endif %} 9 | {{ b.name }} 10 | {{ b.added|time_diff }} 11 | 12 | 13 | {% endfor %} 14 | -------------------------------------------------------------------------------- /templates/bookmark/footer.twig: -------------------------------------------------------------------------------- 1 | 2 | 3 |
                    4 | 5 | 6 |
                    7 |
                    8 | 9 | 10 | 11 |
                    12 | 13 | 14 | -------------------------------------------------------------------------------- /templates/bookmark/none.twig: -------------------------------------------------------------------------------- 1 |
                    2 |
                    3 |

                    No torrents found.

                    4 |
                    5 |
                    6 |

                    Add some torrents and come back later.

                    7 |
                    8 |
                    9 | -------------------------------------------------------------------------------- /templates/collages/browse.twig: -------------------------------------------------------------------------------- 1 | {% extends "base.twig" %} 2 | 3 | {% block content %} 4 | 5 |

                    Browse collages

                    6 | 7 | {# include the main search form #} 8 | {{ include("collages/search.twig") }} 9 | 10 | {# no results message #} 11 | {% if pagination.resultCount == 0 %} 12 |
                    13 |

                    No search results :(

                    14 |

                    Please ensure you didn't make too many typos or apply too many filters.

                    15 |
                    16 | {% else %} 17 | {{ include("manticore/pagination.twig") }} 18 | {{ include("tables/collages.twig", {"grouping": "grouping"}) }} 19 | {{ include("manticore/pagination.twig") }} 20 | {% endif %} 21 | 22 | {% endblock %} 23 | -------------------------------------------------------------------------------- /templates/collector.twig: -------------------------------------------------------------------------------- 1 | {{ constant('siteName') }} Collector Summary for {{ title }} 2 | 3 | User: {{ user.username }} 4 | Passkey: {{ user.announceKey }} 5 | Announce: {{ user.announceUrl }} 6 | 7 | Torrent groups scanned: {{ total }} 8 | Torrents included: {{ added }} 9 | Torrent groups skipped: {{ skipped|length }} 10 | 11 | Total size of torrents: {{ size|octet_size }} 12 | Your buffer: {{ user.buffer[1]|octet_size }} 13 | To download this collection as freeleech, you will need {{ tokens|number_format }} token{{ tokens|plural }}. 14 | 15 | {% if error %} 16 | Some torrents could not be added to the archive. See ERRORS.txt for details. 17 | {% endif %} 18 | {% if skipped %} 19 | Albums unavailable given your criteria (consider making a request for your desired format) 20 | {% for file in skipped %} 21 | {{- file }} 22 | {% endfor %} 23 | {% endif %} 24 | 25 | Date: {{ date }} 26 | Used: {{ used|octet_size }} 27 | CPU: {{ time|number_format(2) }} ms 28 | -------------------------------------------------------------------------------- /templates/creators/browse.twig: -------------------------------------------------------------------------------- 1 | {% extends "base.twig" %} 2 | 3 | {% block content %} 4 | 5 |

                    Browse creators

                    6 | 7 | {# include the main search form #} 8 | {{ include("creators/search.twig") }} 9 | 10 | {# no results message #} 11 | {% if pagination.resultCount == 0 %} 12 |
                    13 |

                    No search results :(

                    14 |

                    Please ensure you didn't make too many typos or apply too many filters.

                    15 |
                    16 | {% else %} 17 | {{ include("manticore/pagination.twig") }} 18 | {{ include("tables/creators.twig", {"grouping": "grouping"}) }} 19 | {{ include("manticore/pagination.twig") }} 20 | {% endif %} 21 | 22 | {% endblock %} 23 | -------------------------------------------------------------------------------- /templates/discourse/boards/index.twig: -------------------------------------------------------------------------------- 1 | {% extends "base.twig" %} 2 | 3 | 4 | {% block content %} 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | {% for category in categories %} 14 | 15 | 20 | 21 | 22 | 23 | 24 | {% endfor %} 25 | 26 |
                    CategoryTopicsPosts
                    16 | {{ category.name }} 17 |
                    18 | {{ category.description_text }} 19 |
                    {{ category.topic_count }}{{ category.post_count }}
                    27 | 28 | {% endblock %} 29 | 30 | 31 | {% block sidebar %} 32 | 33 | {{ include("discourse/boards/sidebar.twig") }} 34 | 35 | {% endblock %} -------------------------------------------------------------------------------- /templates/email/changeEmail.twig: -------------------------------------------------------------------------------- 1 | Hello {{ user.username }}, 2 | 3 | You recently updated your email address at {{ env.siteName }}. This email is to confirm your new address. 4 | 5 | Please click this link within 24 hours to verify your email and update your account: 6 | 7 | {{ uri }} 8 | 9 | 10 | -- {{ env.siteName }} -------------------------------------------------------------------------------- /templates/email/disableWarning.twig: -------------------------------------------------------------------------------- 1 | Dear {{ username }}, 2 | 3 | It's been a while since we last saw you at {{ env.siteName }}. Thank you for seeding and being part of the community. 4 | 5 | Please log into the site to ensure your account remains active. Why don't you stop by and check out the forums or the Top 10? 6 | 7 | If you don't sign in within 10 days, your account will be disabled. It's as easy as clicking here: 8 | 9 | {{ uri }} 10 | 11 | 12 | -- {{ env.siteName }} -------------------------------------------------------------------------------- /templates/email/emailChanged.twig: -------------------------------------------------------------------------------- 1 | {# todo 2 | Dear {{ username }}, 3 | 4 | At {{ now }} UTC, a request from {{ ipaddr }} was received 5 | to change your email address for {{ constant('siteName') }}. 6 | 7 | The new address is {{ new_email }} . Please take a moment to 8 | verify that you did not made a mistake when entering it. 9 | 10 | If you made this change then you may safely ignore this message. 11 | 12 | If you did not request this change yourself, or do not recognize the 13 | address, then either someone has guessed your password or you left a 14 | session logged in somewhere. In either case, you should contact us 15 | immediately. Come to {{ constant('BOT_SERVER') }} and join the {{ constant('BOT_DISABLED_CHAN') }} channel. 16 | 17 | If you receive another email saying your password was changed 18 | and you did not request it, you account has almost certainly 19 | been taken over by a third party. 20 | 21 | The useragent string sent by the browser was: 22 | {{ user_agent }} 23 | #} -------------------------------------------------------------------------------- /templates/email/enableAccepted.twig: -------------------------------------------------------------------------------- 1 | Dear {{ username }}, 2 | 3 | Your request to re-enable your account has been accepted. Please use the following link to activate your account. 4 | 5 | This link is valid for 48 hours and may be clicked only once: 6 | 7 | {{ uri}} 8 | 9 | 10 | -- {{ env.siteName }} -------------------------------------------------------------------------------- /templates/email/enableDeclined.twig: -------------------------------------------------------------------------------- 1 | Dear {{ username }}, 2 | 3 | Your request to re-enable your account was denied for one or more of these reasons: 4 | 5 | * We may require more information to verify your account ownership. 6 | * The email address you provided does not match our records. 7 | * Your account may not qualify for automatic re-enabling due to rule violations. 8 | 9 | 10 | -- {{ env.siteName }} -------------------------------------------------------------------------------- /templates/email/hackedAccount.twig: -------------------------------------------------------------------------------- 1 | Dear {{ username }}, 2 | 3 | Your {{ env.siteName }} account may be compromised. As a security measure, we disabled your account. 4 | 5 | Let's work together in good faith to resolve this matter. Please visit us on the Slack #support channel: 6 | 7 | {{ uri }} 8 | 9 | 10 | -- {{ env.siteName }} -------------------------------------------------------------------------------- /templates/email/inviteMember.twig: -------------------------------------------------------------------------------- 1 | Hello, 2 | 3 | The member {{ username }} invited you to join {{ env.siteName }}. They specified this address {{ email }} as your email address. If you don't know them, please ignore this email. 4 | 5 | Please note that selling, trading, or publicly giving invites away is strictly forbidden. If you received your invite as a result of any of these things, don't bother signing up You'll be banned and lose your chances of ever signing up legitimately. 6 | 7 | If you previously had a {{ env.siteName }} account, don't use this invite. Please join the Slack #support channel so we can help you re-enable your account: 8 | 9 | {{ supportUri }} 10 | 11 | During registration, you may use another email address if you prefer. After you register, you'll receive an email to verify your account. Please use this link to redeem yout {{ env.siteName }} invite: 12 | 13 | {{ inviteUri }} 14 | 15 | Please note that the invite will expire in 3 days if unused.We urge you to read the rules and the wiki once you join. 16 | 17 | 18 | -- {{ env.siteName }} -------------------------------------------------------------------------------- /templates/email/passphraseChanged.twig: -------------------------------------------------------------------------------- 1 | {# todo 2 | Dear {{ username }}, 3 | 4 | At {{ now }} UTC, a request from {{ ipaddr }} was received 5 | to change your password for {{ constant('siteName') }}. 6 | 7 | If you made this change then you may safely ignore this message. 8 | 9 | If you did not request this change yourself then either someone has 10 | guessed your existing password or you left a session logged in 11 | somewhere. In either case, you should contact us immediately. 12 | Come to {{ constant('BOT_SERVER') }} and join the {{ constant('BOT_DISABLED_CHAN') }} channel. 13 | 14 | If you receive another email saying your email address was 15 | changed and you did not request it, you account has almost 16 | certainly been taken over by a third party. 17 | 18 | The useragent string sent by the browser was: 19 | {{ user_agent }} 20 | #} -------------------------------------------------------------------------------- /templates/email/passphraseReset.twig: -------------------------------------------------------------------------------- 1 | Hello, 2 | 3 | You recently requested a passphrase reset for {{ env.siteName }}. To finish this process, please click this link within the hour: 4 | 5 | {{ uri }} 6 | 7 | If you didn't make the request, please disregard this email. The request came from the IP address {{ ip }}. 8 | 9 | 10 | -- {{ env.siteName }} -------------------------------------------------------------------------------- /templates/email/verifyRegistration.twig: -------------------------------------------------------------------------------- 1 | {# 2 | The username, at this point, has not yet been confirmed as acceptable to the owner of the email address. 3 | It could contain offensive or misleading language chosen by someone who is not actually the owner of the address. 4 | #} 5 | 6 | Hello, 7 | 8 | Thanks for registering an account at {{ env.siteName }}. This email is to confirm your newly created account. 9 | 10 | Please click this link within 24 hours to verify your email and enable your account: 11 | 12 | {{ uri }} 13 | 14 | 15 | -- {{ env.siteName }} -------------------------------------------------------------------------------- /templates/error.twig: -------------------------------------------------------------------------------- 1 | {% extends "base.twig" %} 2 | 3 | {% block content %} 4 | 5 |
                    6 |

                    {{ subject }}

                    7 | 8 |

                    {{ body }}

                    9 | 10 |

                    11 | 12 | {# 13 |

                    14 | Search the site log 15 |

                    16 | #} 17 |
                    18 | 19 | {% endblock %} 20 | -------------------------------------------------------------------------------- /templates/forum/request-edit.twig: -------------------------------------------------------------------------------- 1 | [user]{{ username }}[/user] has submitted an editing request for: [url={{ url }}]{{ name }}[/url]. 2 | 3 | [quote=Comments]{{ details }}[/quote] 4 | -------------------------------------------------------------------------------- /templates/forum/toc.twig: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | {{ cut_title }} 8 | 9 | {{ page_links|raw }} 10 | 11 | {% if is_read %} 12 | 13 | 14 | 15 | {% endif %} 16 | by {{ last_post_user|raw }} {{ last_post_diff|raw }} 17 | 18 | {{ replies|number_format }} 19 | {{ author|raw }} 20 | 21 | -------------------------------------------------------------------------------- /templates/inbox/compose.twig: -------------------------------------------------------------------------------- 1 |
                    2 |
                    3 |

                    Send a message to {{ username }}

                    4 |
                    5 |
                    6 |
                    7 | 8 | 9 | 10 |
                    11 |

                    Subject

                    12 |
                    13 |

                    Body

                    14 | 15 |
                    16 | 17 |
                    18 | 19 |
                    20 |
                    21 |
                    22 |
                    23 | -------------------------------------------------------------------------------- /templates/literature/browse.twig: -------------------------------------------------------------------------------- 1 | {% extends "base.twig" %} 2 | 3 | {% block content %} 4 | 5 |

                    Browse literature

                    6 | 7 | {# include the main search form #} 8 | {{ include("literature/search.twig") }} 9 | 10 | {# no results message #} 11 | {% if pagination.resultCount == 0 %} 12 |
                    13 |

                    No search results :(

                    14 |

                    Please ensure you didn't make too many typos or apply too many filters.

                    15 |
                    16 | {% else %} 17 | {{ include("manticore/pagination.twig") }} 18 | {{ include("tables/literature.twig", {"grouping": "grouping"}) }} 19 | {{ include("manticore/pagination.twig") }} 20 | {% endif %} 21 | 22 | {% endblock %} 23 | -------------------------------------------------------------------------------- /templates/manticore/complexSearch.twig: -------------------------------------------------------------------------------- 1 | {## 2 | # complex search (title and id fields) 3 | #} 4 | 5 | {% set placeholder = "Title, subject, or object" %} 6 | 7 | {% if manticore.context == "collages" %} 8 | {% set placeholder = "Title or description" %} 9 | {% endif %} 10 | 11 | {% if manticore.context == "creators" %} 12 | {% set placeholder = "Name, aliases, or ORCiD" %} 13 | {% endif %} 14 | 15 | {% if manticore.context == "literature" %} 16 | {% set placeholder = "Title, abstract, citation, or DOI" %} 17 | {% endif %} 18 | 19 | {% if manticore.context == "organizations" %} 20 | {% set placeholder = "Name, acronym, or ROR" %} 21 | {% endif %} 22 | 23 | {% if manticore.context == "requests" %} 24 | {% set placeholder = "Title, organism, strain or variety, or identifier" %} 25 | {% endif %} 26 | 27 | {% if manticore.context == "torrentGroups" %} 28 | {% set placeholder = "Title, organism, strain or variety, or identifier" %} 29 | {% endif %} 30 | 31 | 32 | Essentials 33 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /templates/manticore/dataSize.twig: -------------------------------------------------------------------------------- 1 | {## 2 | # dataSize 3 | #} 4 | 5 | {% set id = "dataSize" %} 6 | {% set header = "Data size" %} 7 | 8 | {% if manticore.context == "requests" %} 9 | {% set id = "bounty" %} 10 | {% set header = "Bounty" %} 11 | {% endif %} 12 | 13 | 14 | {{ header }} 15 | 16 | 17 | – 18 | 19 | 20 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /templates/manticore/files.twig: -------------------------------------------------------------------------------- 1 | {## 2 | # files 3 | #} 4 | 5 | 6 | Files 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /templates/manticore/formControls.twig: -------------------------------------------------------------------------------- 1 | {## 2 | # formControls 3 | #} 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /templates/manticore/numbers.twig: -------------------------------------------------------------------------------- 1 | {## 2 | # numbers 3 | #} 4 | 5 | 6 | Numbers 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /templates/manticore/pagination.twig: -------------------------------------------------------------------------------- 1 | {## 2 | # result pagination 3 | #} 4 | 5 |
                    6 |

                    {{ pagination.offset + 1 }}–{{ pagination.limit }} of {{ pagination.resultCount }} results

                    7 | 8 |
                    9 | {% if pagination.currentPage != pagination.firstPage %} 10 | « first 11 | {% endif %} 12 | 13 | {% if pagination.currentPage > pagination.previousPage %} 14 | ‹ previous 15 | {% endif %} 16 | 17 | {% if pagination.currentPage < pagination.nextPage and pagination.currentPage < pagination.lastPage %} 18 | next › 19 | {% endif %} 20 | 21 | {% if pagination.currentPage != pagination.lastPage %} 22 | last » 23 | {% endif %} 24 |
                    25 |
                    26 | -------------------------------------------------------------------------------- /templates/manticore/people.twig: -------------------------------------------------------------------------------- 1 | {## 2 | # people 3 | #} 4 | 5 | 6 | People 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /templates/manticore/places.twig: -------------------------------------------------------------------------------- 1 | {## 2 | # places 3 | #} 4 | 5 | {% set placeholder = "Workgroup, institution, or ROR" %} 6 | 7 | {% if manticore.context == "organizations" %} 8 | {% set placeholder = "Torrent workgroup or creator affiliation" %} 9 | {% endif %} 10 | 11 | 12 | Places 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /templates/manticore/relationships.twig: -------------------------------------------------------------------------------- 1 | {## 2 | # relationships 3 | #} 4 | 5 | 6 | Relationships 7 | 8 | {% if manticore.context != "torrentGroups" %} 9 | 10 | {% endif %} 11 | 12 | {% if manticore.context != "collages" %} 13 | 14 | {% endif %} 15 | 16 | {% if manticore.context != "requests" %} 17 | 18 | {% endif %} 19 | 20 | 21 | -------------------------------------------------------------------------------- /templates/manticore/simpleSearch.twig: -------------------------------------------------------------------------------- 1 | {## 2 | # simple search (all fields) 3 | #} 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /templates/manticore/tracker.twig: -------------------------------------------------------------------------------- 1 | {## 2 | # tracker 3 | #} 4 | 5 | 6 | Tracker 7 | 8 | {# leech status #} 9 | 15 | 16 | 17 | 18 | {# #} 19 | 20 | 21 | -------------------------------------------------------------------------------- /templates/organizations/browse.twig: -------------------------------------------------------------------------------- 1 | {% extends "base.twig" %} 2 | 3 | {% block content %} 4 | 5 |

                    Browse organizations

                    6 | 7 | {# include the main search form #} 8 | {{ include("organizations/search.twig") }} 9 | 10 | {# no results message #} 11 | {% if pagination.resultCount == 0 %} 12 |
                    13 |

                    No search results :(

                    14 |

                    Please ensure you didn't make too many typos or apply too many filters.

                    15 |
                    16 | {% else %} 17 | {{ include("manticore/pagination.twig") }} 18 | {{ include("tables/organizations.twig", {"grouping": "grouping"}) }} 19 | {{ include("manticore/pagination.twig") }} 20 | {% endif %} 21 | 22 | {% endblock %} 23 | -------------------------------------------------------------------------------- /templates/publications/browse.twig: -------------------------------------------------------------------------------- 1 | {% extends "base.twig" %} 2 | 3 | {% block content %} 4 | 5 |

                    Browse publications

                    6 | 7 | {# include the main search form #} 8 | {{ include("publications/search.twig") }} 9 | 10 | {# no results message #} 11 | {% if pagination.resultCount == 0 %} 12 |
                    13 |

                    No search results :(

                    14 |

                    Please ensure you didn't make too many typos or apply too many filters.

                    15 |
                    16 | {% else %} 17 | {{ include("manticore/pagination.twig") }} 18 | {{ include("tables/publications.twig", {"grouping": "grouping"}) }} 19 | {{ include("manticore/pagination.twig") }} 20 | {% endif %} 21 | 22 | {% endblock %} 23 | -------------------------------------------------------------------------------- /templates/reportsv2/new.twig: -------------------------------------------------------------------------------- 1 | The following torrent has been reported for {{ title }}. 2 | 3 | [pl]{{ id }}[/pl] 4 | 5 | The reason given was:[quote]{{ reason }}[/quote] 6 | You may send a Staff PM to the moderators if you believe that the report is unwarranted or you would like more information. 7 | -------------------------------------------------------------------------------- /templates/requests/browse.twig: -------------------------------------------------------------------------------- 1 | {% extends "base.twig" %} 2 | 3 | {% block content %} 4 | 5 |

                    Browse requests

                    6 | 7 | {# include the main search form #} 8 | {{ include("requests/search.twig") }} 9 | 10 | {# no results message #} 11 | {% if pagination.resultCount == 0 %} 12 |
                    13 |

                    No search results :(

                    14 |

                    Please ensure you didn't make too many typos or apply too many filters.

                    15 |
                    16 | {% else %} 17 | {{ include("manticore/pagination.twig") }} 18 | {{ include("tables/requests.twig", {"grouping": "grouping"}) }} 19 | {{ include("manticore/pagination.twig") }} 20 | {% endif %} 21 | 22 | {% endblock %} 23 | -------------------------------------------------------------------------------- /templates/requests/sidebarForm.twig: -------------------------------------------------------------------------------- 1 | {# actions #} 2 |
                    3 |

                    Actions

                    4 | 5 |
                    6 | 7 | 8 | 9 | autofill by doi 10 | 11 | 12 | 13 |
                    14 | 15 | request rules 16 | 17 | categories wiki 18 | 19 | 24 | 25 |
                    26 | 27 | search torrents 28 | 29 | 33 | 34 |
                    35 |
                    36 | -------------------------------------------------------------------------------- /templates/siteLog/index.twig: -------------------------------------------------------------------------------- 1 | {% extends "base.twig" %} 2 | 3 | {% block content %} 4 | 5 |

                    Site log

                    6 | 7 |
                    8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | {% for item in results %} 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | {% endfor %} 29 | 30 |
                    UserEventContent typeDetailsTime
                    {{ item.userId|formatUsername }}{{ item.action }}{{ item.contentType }}{{ item.description }}{{ item.createdAt|relativeTime }}
                    31 | 32 |
                    33 | 34 | {% endblock %} 35 | 36 | 37 | {# 38 | {% block sidebar %} 39 | 40 | {% include "torrents/sidebar.twig" %} 41 | 42 | {% endblock %} 43 | #} 44 | -------------------------------------------------------------------------------- /templates/siteText/legal/about.md: -------------------------------------------------------------------------------- 1 | ## About BioTorrents.de 2 | 3 | BioTorrents.de is a functional experiment in comfy data distribution. 4 | The tagline is "What.cd for genome sequences." 5 | The scope is multidisciplinary and social science friendly. 6 | 7 | It indexes a wide variety of biology data and serves it on a fast BitTorrent network. 8 | The semantic website promotes organic content discovery and community annotations. 9 | Other interfaces include a JSON API, RSS feeds, and IRC channels. 10 | 11 | BioTorrents.de is an open platform for disadvantaged researchers to host their data. 12 | More importantly, it provides the necessary tools for others to find and cite it later. 13 | It's a place for the Google Drives, FTP folders, and network shares that may not be accepted elsewhere. 14 | It also plays well with institutional repositories and can efficiently mirror their data. 15 | 16 | A mature software product and draft publication are expected by Easter 2024. 17 | Thank you for your curiosity, patience, and support as we grow the service. 18 | 19 | ### Email 20 | 21 | hello at torrents dot bio 22 | 23 | Please use 24 | [GPG A1D095A5DEC74A8B](/pubkey) 25 | if you wish. 26 | -------------------------------------------------------------------------------- /templates/siteText/legal/canary.txt: -------------------------------------------------------------------------------- 1 | -----BEGIN PGP SIGNED MESSAGE----- 2 | Hash: SHA512 3 | 4 | BioTorrents.de confirms our system's integrity: 5 | - under our exclusive control, 6 | - not compromised or data breached, 7 | - no forced user data disclosure, 8 | - and no forced software updates. 9 | 10 | Updated 2021-02-12. 11 | 12 | -----BEGIN PGP SIGNATURE----- 13 | 14 | iQIzBAEBCgAdFiEEAYUanUikDJomLCqjodCVpd7HSosFAmAnHa0ACgkQodCVpd7H 15 | SovM7RAAr598dxNLjUEGxauG2/DJj5Uv9jUFumhZ6CCgEAIg9H69SUN7coDnth7j 16 | 6Z0EncuY264pgNLzCkTZjh92b3inMAD7yiYG8cfBC9xbrL/2BX7UBYuW0vzCzY1D 17 | RXab1N1DIYzAWVRJDzMM2/4cZ9Lhe5cyAom2XCRitRnZRZ6Su2Mcv0gtsAcC8ejL 18 | MIf/6zCgrac0gftfe+izociDc3U6LxBklsBOEdPro63ZXM0T3EN80c3JdkSsd3zY 19 | uEcEe1EZR0rmSQkMEuaFzYWgKUzJncyPzoOtEJgkkwF5T/8XmuSZ0ggl/JDUPwLR 20 | Z3AM4ajPbCWkYq9jCwm8WjZY8qvmFtkkcEMQeZAKZDwX7HAKdIxk0Ce1KHxqb6x6 21 | YrqhH6SvLS/Td6HZVxoirs75M4dvEkF85Cx6SSSke2Z/c1UtCTmcdR7hBrxPcHRc 22 | rj77ndKZ9hwQvv/gh0nYLCEXlYczwuKNFZP5OpHJ5CcfpRYQwT2Pw0K1HHP9Od73 23 | jzuP0YaMANKZbKqCwf4bGplWg3o3XCvCuF7/rG6zUSTCLSb/c54MYLsh6a5YCPQ3 24 | jgN1mtzw7NBbh2gJohdkCc+weCGzaLGl6ABZn5FxLv+BN7ORx0PUM/3+I3bAgzwr 25 | xJ8jJU5T8/z5aCRqgUb9aOMe9lfx+aS8UTAW9qCG5MDi5Sc3n/A= 26 | =9R94 27 | -----END PGP SIGNATURE----- 28 | -------------------------------------------------------------------------------- /templates/siteText/rules.twig: -------------------------------------------------------------------------------- 1 | {% extends "base.twig" %} 2 | 3 | 4 | {% block content %} 5 | 6 |
                    7 | {{ content|raw }} 8 |
                    9 | 10 | {% if enableConversation and conversation %} 11 | {% set variables = { "conversation": conversation } %} 12 | {% include "_base/conversation.twig" with variables %} 13 | {% endif %} 14 | 15 | {% endblock %} 16 | 17 | 18 | {% block sidebar %} 19 | 20 | {% include "siteText/rules/sidebar.twig" %} 21 | 22 | {% endblock %} -------------------------------------------------------------------------------- /templates/siteText/rules/sidebar.twig: -------------------------------------------------------------------------------- 1 |

                    Other rule pages

                    2 | 3 |
                    4 | upload 5 |

                    If you only read one rules page, this is the most important one to read

                    6 | 7 | ratio 8 |

                    There's really two mandatory rules pages: required ratio table and calculation

                    9 | 10 | requests 11 | 12 | collages 13 | 14 | clients 15 | 16 | chat 17 | 18 | tags 19 | 20 |
                    21 | 22 | golden rules 23 |
                    24 | -------------------------------------------------------------------------------- /templates/siteText/tldr.twig: -------------------------------------------------------------------------------- 1 | {% extends "base.twig" %} 2 | 3 | 4 | {% block content %} 5 | 6 |
                    7 | {{ content|raw }} 8 |
                    9 | 10 | {% endblock %} -------------------------------------------------------------------------------- /templates/stats/concepts.twig: -------------------------------------------------------------------------------- 1 | {## 2 | # get OpenAlex's concepts property 3 | #} 4 | 5 | 6 | 7 |
                    8 |

                    Top subjects

                    9 | 10 | 11 | 32 |
                    33 | -------------------------------------------------------------------------------- /templates/tables/searchSemanticScholar.twig: -------------------------------------------------------------------------------- 1 | {# 2 | # semantic scholar ajax search 3 | #} 4 | 5 |
                    6 | 7 | 8 | 9 | 10 | {# 11 |
                    12 | 13 | 14 | 15 | 16 | 17 | 18 | 22 | 23 | 24 | 25 | 26 |
                    19 | 20 | 21 |
                    27 |
                    28 | #} 29 |
                    30 | 31 | 32 | -------------------------------------------------------------------------------- /templates/tag/alias.twig: -------------------------------------------------------------------------------- 1 | {% for name, a in alias %} 2 | 3 |
                    4 | 5 | 6 | 7 | {% if is_mod %} 8 | 9 | {% else %} 10 | {{ a.alias }} 11 | {% endif %} 12 | 13 | 14 | {% if is_mod %} 15 | 16 | {% else %} 17 | {{ a.bad }} 18 | {% endif %} 19 | 20 | {% if is_mod %} 21 | 22 | 23 | 24 | 25 | {% endif %} 26 |
                    27 | 28 | {% endfor %} 29 | -------------------------------------------------------------------------------- /templates/torrentForm/announceSource.twig: -------------------------------------------------------------------------------- 1 | {# announce and source #} 2 |
                    3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 15 | 16 | 19 | 20 |
                    Announce URIsSource key
                    11 | {% for item in announceUris %} 12 | 13 | {% endfor %} 14 | 17 | 18 |
                    21 |
                    22 | -------------------------------------------------------------------------------- /templates/torrentForm/archive.twig: -------------------------------------------------------------------------------- 1 | {# archive #} 2 | 3 | 4 | 5 | 6 | 7 | 8 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /templates/torrentForm/booleans.twig: -------------------------------------------------------------------------------- 1 | {# annotated #} 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | {# anonymous #} 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /templates/torrentForm/categoryId.twig: -------------------------------------------------------------------------------- 1 | {# categoryId #} 2 | 3 | 4 | 5 | 6 | 7 | 8 | 13 | 14 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /templates/torrentForm/creatorList.twig: -------------------------------------------------------------------------------- 1 | {# creatorList #} 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /templates/torrentForm/formats.twig: -------------------------------------------------------------------------------- 1 | {# formats #} 2 | {% for key, items in env.categories %} 3 | 4 | 5 | 6 | 7 | 8 | 9 | {# can't be required #} 10 | 20 | 21 | 22 | {% endfor %} 23 | -------------------------------------------------------------------------------- /templates/torrentForm/freeleech.twig: -------------------------------------------------------------------------------- 1 | {# freeleech #} 2 | {% if can({"admin": "freeleechTorrents"}) %} 3 | 4 | 5 | 6 | 7 | 8 | 9 | 14 | 15 | 16 | 17 | 24 | 25 | 26 | {% endif %} 27 | -------------------------------------------------------------------------------- /templates/torrentForm/groupDescription.twig: -------------------------------------------------------------------------------- 1 | {# groupDescription #} 2 | 3 | 4 | 5 | 6 | 7 | 8 | {% set variables = {"id": "groupDescription", "name": "groupDescription", "placeholder": db.description, "value": value, "required": true} %} 9 | {% include "_base/textarea.twig" with variables %} 10 | 11 | 12 | -------------------------------------------------------------------------------- /templates/torrentForm/identifier.twig: -------------------------------------------------------------------------------- 1 | {# identifier #} 2 | 3 | 4 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /templates/torrentForm/license.twig: -------------------------------------------------------------------------------- 1 | {# license #} 2 | 3 | 4 | 5 | 6 | 7 | 8 | 14 | 15 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /templates/torrentForm/literature.twig: -------------------------------------------------------------------------------- 1 | {# literature #} 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /templates/torrentForm/location.twig: -------------------------------------------------------------------------------- 1 | {# location #} 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /templates/torrentForm/mirrors.twig: -------------------------------------------------------------------------------- 1 | {# mirrors #} 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /templates/torrentForm/notice.twig: -------------------------------------------------------------------------------- 1 | {# notice #} 2 |
                    3 | The site automatically adds the Announce and Source fields. 4 | Simply download and seed the new torrent after you upload it. 5 |
                    6 | -------------------------------------------------------------------------------- /templates/torrentForm/picture.twig: -------------------------------------------------------------------------------- 1 | {# picture #} 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /templates/torrentForm/platforms.twig: -------------------------------------------------------------------------------- 1 | {# platforms #} 2 | {% for key, items in env.categories %} 3 | 4 | 5 | 6 | 7 | 8 | 9 | {# can't be required #} 10 | 16 | 17 | 18 | {% endfor %} 19 | -------------------------------------------------------------------------------- /templates/torrentForm/scopes.twig: -------------------------------------------------------------------------------- 1 | {# scopes #} 2 | {% for key, value in env.categories %} 3 | 4 | 5 | 6 | 7 | 8 | 9 | 19 | 20 | 21 | {% endfor %} 22 | -------------------------------------------------------------------------------- /templates/torrentForm/tagList.twig: -------------------------------------------------------------------------------- 1 | {# tagList #} 2 | 3 | 4 | 5 | 6 | 7 | 8 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /templates/torrentForm/titles.twig: -------------------------------------------------------------------------------- 1 | {# title #} 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | {# subject #} 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | {# object #} 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /templates/torrentForm/torrentDescription.twig: -------------------------------------------------------------------------------- 1 | {# torrentDescription #} 2 | 3 | 4 | 5 | 6 | 7 | 8 | {% set variables = {"id": "torrentDescription", "name": "torrentDescription", "placeholder": "Specific info about the protocols and equipment used to produce the data", "value": value} %} 9 | {% include "_base/textarea.twig" with variables %} 10 | 11 | 12 | -------------------------------------------------------------------------------- /templates/torrentForm/torrentFile.twig: -------------------------------------------------------------------------------- 1 | {# torrentFile #} 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /templates/torrentForm/version.twig: -------------------------------------------------------------------------------- 1 | {# version #} 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /templates/torrentForm/workgroup.twig: -------------------------------------------------------------------------------- 1 | {# workgroup #} 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /templates/torrentForm/year.twig: -------------------------------------------------------------------------------- 1 | {# year #} 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /templates/user/auth/confirm.twig: -------------------------------------------------------------------------------- 1 | {% extends "base.twig" %} 2 | 3 | {% block content %} 4 | 5 |

                    Confirm your account

                    6 | 7 | {% if response %} 8 |

                    9 | {{ response }} 10 |

                    11 | 12 | {# resend confirmation #} 13 | {% if resendConfirmation %} 14 |

                    15 | send new confirmation 16 |

                    17 | {% endif %} 18 | 19 | {% else %} 20 |

                    21 | Thanks for confirming your account. 22 | Please enjoy the site! 23 |

                    24 | 25 |

                    26 | rules 27 | wiki 28 |

                    29 | {% endif %} 30 | 31 | {% endblock %} 32 | -------------------------------------------------------------------------------- /templates/user/edit-fltoken.twig: -------------------------------------------------------------------------------- 1 | 2 | FL Tokens: 3 | 4 | 5 | -------------------------------------------------------------------------------- /templates/user/edit-invite.twig: -------------------------------------------------------------------------------- 1 | 2 | Invites: 3 | 4 | 5 | -------------------------------------------------------------------------------- /templates/user/edit-lock.twig: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | 7 | 8 | 9 | 12 | 13 | 14 | 15 | 21 | 22 | {% if can_logout %} 23 | 24 | 25 | 26 | 27 | {% endif %} 28 |
                    4 | Lock Account 5 |
                    Lock Account: 10 | You must give the reason below when locking. 11 |
                    Lock Reason: 16 | 20 |
                    Log out:
                    29 | -------------------------------------------------------------------------------- /templates/user/edit-peer-visibility.twig: -------------------------------------------------------------------------------- 1 | 2 | Visible in peer lists: 3 | 4 | 5 | -------------------------------------------------------------------------------- /templates/user/edit-rate-limit.twig: -------------------------------------------------------------------------------- 1 | 2 | Unlimited Torrent Downloads 3 | 4 | 5 | -------------------------------------------------------------------------------- /templates/user/edit-remark.twig: -------------------------------------------------------------------------------- 1 | 2 | FLS/Staff remark: 3 | 4 | 5 | -------------------------------------------------------------------------------- /templates/user/edit-reset.twig: -------------------------------------------------------------------------------- 1 | 2 | Reset: 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /templates/user/edit-secondary-class.twig: -------------------------------------------------------------------------------- 1 | 2 | Secondary classes: 3 | 4 | {% for p in permission %} 5 |   7 | {{ cycle(['', '', '
                    ' ], loop.index0) | raw }} 8 | {% endfor %} 9 | 10 | 11 | -------------------------------------------------------------------------------- /templates/user/edit-submit.twig: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | 7 | 8 | 9 | 12 | 13 | 14 | 15 | 18 | 19 | 20 | 21 | 24 | 25 |
                    4 | Submit 5 |
                    Paste user stats: 10 | 11 |
                    Reason: 16 | 17 |
                      22 | 23 |
                    26 | -------------------------------------------------------------------------------- /templates/user/edit-title.twig: -------------------------------------------------------------------------------- 1 | 2 | Custom title: 3 | 4 | 5 | -------------------------------------------------------------------------------- /templates/user/profile/invites.twig: -------------------------------------------------------------------------------- 1 | {% extends "base.twig" %} 2 | 3 | {% block content %} 4 | 5 |

                    Invites for {{ user.core.username }}

                    6 | 7 | {# admonition #} 8 |
                    9 | 10 |

                    11 | Do not trade or sell invites under any circumstances. 12 | Do not send an invite to anyone who has previously had a {{ env.siteName }} account. 13 | Please direct them to #disabled on Slack if they wish to reactivate their account. 14 |

                    15 | 16 |

                    17 | You may invite anyone so long as you and they both lack malicious intent, but keep in mind that you are responsible for anyone you invite. 18 | If you invite someone you don't know well and they surprise you by breaking the rules or being a generally poor user, you will likely end up punished for it. 19 | For that reason, we stongly recommend you only invite people you personally know and trust. 20 |

                    21 | 22 |

                    23 | Do not send an invite if you haven't read or don't understand this information. 24 |

                    25 | 26 |
                    27 | 28 | {% endblock %} -------------------------------------------------------------------------------- /templates/user/recent.twig: -------------------------------------------------------------------------------- 1 | {% if recent %} 2 | 3 | 4 | 5 | 6 | 7 | {% for r in recent %} 8 | 13 | {% endfor %} 14 | 15 |
                    Recent {{ title }}
                    9 | 10 | {{ r.Name|raw }} 11 | 12 |
                    16 | {% endif %} 17 | -------------------------------------------------------------------------------- /templates/user/reset-avatar.twig: -------------------------------------------------------------------------------- 1 | {{ constant('siteName') }} has the following requirements for {{ type }}s: 2 | 3 | [b]{{ type|capitalize }}s must not exceed {{ size_kb }} kB nor be taller than {{ height }}px.[/b] 4 | 5 | Your {{ type }} at {{ url }} has been found to exceed these rules. As such, it has been automatically reset. You are welcome to reinstate your {{ type }} once it has been reduced to an acceptable size. 6 | -------------------------------------------------------------------------------- /templates/user/sidebar.twig: -------------------------------------------------------------------------------- 1 | {## 2 | # generic user sidebar 3 | #} 4 | 5 |
                    6 |

                    Actions

                    7 | 8 |
                    9 | 10 | {# edit settings #} 11 | edit settings 12 | 13 | {# preview as other #} 14 | view profile 15 | 16 |
                    17 |
                    18 | -------------------------------------------------------------------------------- /templates/user/staff.twig: -------------------------------------------------------------------------------- 1 | {% extends "base.twig" %} 2 | 3 | {% block content %} 4 | 5 |

                    {{ env.siteName }} Staff

                    6 | 7 |

                    8 | If you're looking for help with a general question, 9 | we appreciate it if you'd only message through the staff inbox, 10 | where we can all help you. 11 |

                    12 | 13 |

                    14 | send a staff pm 15 |

                    16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | {% for item in staff %} 27 | 28 | 29 | 30 | 31 | 32 | 33 | {% endfor %} 34 | 35 |
                    UsernameClassLast loginActions
                    {{ item.core.username }}{{ item.role.attributes.friendlyName }}{{ item.core.last_login|relativeTime }}view profile
                    36 | 37 | {% endblock %} 38 | -------------------------------------------------------------------------------- /templates/user/tag-snatch.twig: -------------------------------------------------------------------------------- 1 |
                    2 |
                    Snatched tags
                    3 |
                      4 | {% for tag in list %} 5 |
                    • {{ tag.name }} 6 | ({{ tag.n }})
                    • 7 | {% endfor %} 8 |
                    9 |
                    10 | -------------------------------------------------------------------------------- /templates/user/thread-history.twig: -------------------------------------------------------------------------------- 1 |
                    2 |
                    3 |

                    {{ user.username }} › Threads created

                    4 |
                    5 | {% if not page %} 6 |
                    7 | {{ user.username }} has not created any threads. 8 |
                    9 | {% else %} 10 | {{ paginator.linkbox|raw }} 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | {% for t in page %} 19 | 20 | 21 | 22 | 23 | 24 | 25 | {% endfor %} 26 |
                    ForumThreadCreatedMost recent post
                    {{ t.forum_title }}{{ t.thread_title }}{{ t.created_time|time_diff }}{{ t.last_post_time|time_diff }}
                    27 | {{ paginator.linkbox|raw }} 28 | {% endif %} 29 |
                    30 | -------------------------------------------------------------------------------- /templates/wiki/article.twig: -------------------------------------------------------------------------------- 1 | {% extends "base.twig" %} 2 | 3 | 4 | {% block content %} 5 | 6 |
                    7 | {% if can({"wiki": "update"}) and user.extra.PermissionID >= article.attributes.minimumEditClass %} 8 |

                    9 | 10 |

                    11 | {% else %} 12 |

                    {{ article.attributes.title }}

                    13 | {% endif %} 14 | 15 | {% set vars = { "id": article.id, "content": article.attributes.body } %} 16 | {% include "_base/starboardNotebook.twig" with vars %} 17 |
                    18 | 19 | {% if enableConversation and conversation %} 20 | {% set variables = { "conversation": conversation } %} 21 | {% include "_base/conversation.twig" with variables %} 22 | {% endif %} 23 | 24 | {% endblock %} 25 | 26 | 27 | {% block sidebar %} 28 | 29 | {{ include("wiki/sidebar.twig") }} 30 | 31 | {% endblock %} 32 | -------------------------------------------------------------------------------- /tests/app/AppTest.php: -------------------------------------------------------------------------------- 1 | assertSame( 20 | \Gazelle\App::go(), 21 | $app 22 | ); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /tests/go.php: -------------------------------------------------------------------------------- 1 | > /var/www/log/gazelle/every.log 2>&1 2 | 0 * * * * php /var/www/html/gazelle/utilities/crontab hourly cronToken >> /var/www/log/gazelle/hourly.log 2>&1 3 | 0 0 * * * php /var/www/html/gazelle/utilities/crontab daily cronToken >> /var/www/log/gazelle/daily.log 2>&1 4 | 0 0 * * 0 php /var/www/html/gazelle/utilities/crontab weekly cronToken >> /var/www/log/gazelle/weekly.log 2>&1 5 | 0 0 1 * * php /var/www/html/gazelle/utilities/crontab monthly cronToken >> /var/www/log/gazelle/monthly.log 2>&1 6 | 0 0 1 1 * php /var/www/html/gazelle/utilities/crontab yearly cronToken >> /var/www/log/gazelle/yearly.log 2>&1 7 | -------------------------------------------------------------------------------- /utilities/crontab/daily/jwtKeyPair.php: -------------------------------------------------------------------------------- 1 | env->webRoot}/jwtKeyPair.txt", $keyPair); 17 | -------------------------------------------------------------------------------- /utilities/crontab/daily/resolveStaffPMs.php: -------------------------------------------------------------------------------- 1 | dbNew->do($query, ["resolved", 0, "open"]); 19 | -------------------------------------------------------------------------------- /utilities/crontab/every/bonusPointFreeleeches.php: -------------------------------------------------------------------------------- 1 | dbNew->column($query, []); 16 | 17 | \Gazelle\Torrents::freeleech_torrents($torrentIds, 0, 0); 18 | 19 | $query = "delete from shop_freeleeches where expiryTime < now()"; 20 | $app->dbNew->do($query, []); 21 | 22 | # also clear the misc table for expired freeleeches 23 | $query = "delete from misc where second = ? and cast(first as unsigned integer) < ?"; 24 | $app->dbNew->do($query, ["freeleech", time()]); 25 | -------------------------------------------------------------------------------- /utilities/crontab/every/expireFreeleechTokens.php: -------------------------------------------------------------------------------- 1 | dbNew->multi($query, []); 20 | 21 | foreach ($ref as $row) { 22 | \TrackerOld::update_tracker("remove_token", [ 23 | "info_hash" => substr("%" . chunk_split($row["info_hash"], 2, "%"), 0, -1), 24 | "userid" => $row["userId"] 25 | ]); 26 | } 27 | 28 | $query = " 29 | update users_freeleeches set expired = true 30 | where time < now() - interval 3 day and expired = false 31 | "; 32 | $app->dbNew->do($query, []); 33 | -------------------------------------------------------------------------------- /utilities/crontab/every/lastCommit.php: -------------------------------------------------------------------------------- 1 | env->dev) { 15 | return; 16 | } 17 | 18 | # this is stupid but it doesn't work from twig 19 | chdir($app->env->serverRoot); 20 | $gitInfo = json_encode(Gazelle\Debug::gitInfo()); 21 | file_put_contents("{$app->env->webRoot}/gitInfo.json", $gitInfo); 22 | -------------------------------------------------------------------------------- /utilities/crontab/every/sixHourFreeleeches.php: -------------------------------------------------------------------------------- 1 | dbNew->do($query, [ 0, 0, 1, 4, time_minus(3600 * 7) ]); 22 | -------------------------------------------------------------------------------- /utilities/crontab/hourly/deleteDeadPeers.php: -------------------------------------------------------------------------------- 1 | dbNew->do($query, []); 16 | -------------------------------------------------------------------------------- /utilities/crontab/hourly/deleteDeadSessions.php: -------------------------------------------------------------------------------- 1 | dbNew->do($query, []); 16 | -------------------------------------------------------------------------------- /utilities/crontab/hourly/deleteExpiredInvites.php: -------------------------------------------------------------------------------- 1 | dbNew->do($query, []); 16 | -------------------------------------------------------------------------------- /utilities/crontab/hourly/deleteExpiredWarnings.php: -------------------------------------------------------------------------------- 1 | toDateTimeString(); 15 | 16 | $query = "select userId from users_info where warned < ?"; 17 | $ref = $app->dbNew->multi($query, [$now]); 18 | 19 | foreach ($ref as $row) { 20 | $query = "update users_info set warned = null where userId = ?"; 21 | $app->dbNew->prepared_query($query, [ $row["userId"] ]); 22 | } 23 | -------------------------------------------------------------------------------- /utilities/crontab/hourly/siteApiSecret.php: -------------------------------------------------------------------------------- 1 | env->webRoot}/siteApiSecret.txt", $siteApiSecret); 16 | -------------------------------------------------------------------------------- /utilities/crontab/hourly/updateSeedTimes.php: -------------------------------------------------------------------------------- 1 | dbNew->do($query, []); 20 | -------------------------------------------------------------------------------- /utilities/crontab/monthly/auctionBadge.php: -------------------------------------------------------------------------------- 1 | dbNew->row($query, ["auctionBadge"]); 16 | 17 | if (!$row) { 18 | return; 19 | } 20 | 21 | # award the badge and send a PM 22 | Gazelle\Badges::awardBadge($row["userId"], $app->env->auctionBadgeId); 23 | Misc::send_pm($row["userId"], 0, "You won the auction badge", "Congratulations! You won this month's badge auction."); 24 | 25 | # clean up 26 | $query = "delete from bonus_point_purchases where `key` = ?"; 27 | $app->dbNew->do($query, ["auctionBadge"]); 28 | -------------------------------------------------------------------------------- /utilities/crontab/monthly/remoteCreatorData.php: -------------------------------------------------------------------------------- 1 | dbNew->column($query, [$app->env->failCount, $app->env->degreesOfSeparation]); 21 | 22 | foreach ($ref as $row) { 23 | try { 24 | ~d("processing creator id {$row}"); 25 | $creator = new Gazelle\Creators($row); 26 | $data = $creator->hydrateFromOpenAlex(); 27 | !d($data); 28 | } catch (Exception $e) { 29 | ~d("{$e->getMessage()} for creator id {$row}"); 30 | continue; 31 | } 32 | 33 | # don't get rate limited 34 | echo "\n\n sleeping 5s \n\n"; 35 | sleep(5); 36 | } 37 | -------------------------------------------------------------------------------- /utilities/crontab/monthly/updateTopSnatchers.php: -------------------------------------------------------------------------------- 1 | dbNew->do($query, []); 16 | 17 | $query = " 18 | insert into top_snatchers (userId) 19 | select uid from xbt_snatched group by uid 20 | order by count(uid) desc limit 100 21 | "; 22 | $app->dbNew->do($query, []); 23 | -------------------------------------------------------------------------------- /utilities/crontab/weekly/grantInvites.php: -------------------------------------------------------------------------------- 1 | dbNew->multi($userQuery, [User::NORMAL, 2, POWER]); 23 | foreach ($ref as $row) { 24 | $app->dbNew->do($inviteQuery, [ $row["id"] ]); 25 | } 26 | 27 | # elites 28 | $ref = $app->dbNew->multi($userQuery, [User::NORMAL, 3, ELITE]); 29 | foreach ($ref as $row) { 30 | $app->dbNew->do($inviteQuery, [ $row["id"] ]); 31 | } 32 | 33 | # torrent masters 34 | $ref = $app->dbNew->multi($userQuery, [User::NORMAL, 4, TORRENT_MASTER]); 35 | foreach ($ref as $row) { 36 | $app->dbNew->do($inviteQuery, [ $row["id"] ]); 37 | } 38 | -------------------------------------------------------------------------------- /utilities/docker/manticore/Dockerfile: -------------------------------------------------------------------------------- 1 | ## 2 | # https://docs.docker.com/build/building/best-practices/ 3 | # 4 | 5 | # https://hub.docker.com/r/manticoresearch/manticore 6 | FROM manticoresearch/manticore 7 | 8 | # install php for config parsing 9 | RUN apt-get update \ 10 | && apt-get install -y php-cli \ 11 | && rm -rf /var/lib/apt/lists/* 12 | 13 | # parse the manticore config 14 | COPY entrypoint.sh /entrypoint.sh 15 | ENTRYPOINT ["/entrypoint.sh"] 16 | -------------------------------------------------------------------------------- /utilities/docker/manticore/entrypoint.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # exit on a non-zero status 4 | set -e 5 | 6 | # generate config from php 7 | php /etc/manticoresearch/manticore.conf.sh > /etc/manticoresearch/manticore.conf 8 | 9 | # start manticore 10 | exec /entrypoint.sh "$@" 11 | -------------------------------------------------------------------------------- /utilities/docker/manticore/manticore.conf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/biotorrents/gazelle/29e89642f3b2da8901643d1db1f36566007f0f96/utilities/docker/manticore/manticore.conf -------------------------------------------------------------------------------- /utilities/docker/php/snuffleupagus/detect_dangerous_extensions.rules: -------------------------------------------------------------------------------- 1 | ## This example rules file shows how to detect and disable certain potentially 2 | ## dangerous or unwanted extensions. 3 | 4 | @condition extension_loaded("runkit7"); 5 | @error "The runkit7 extension can be used to rename classes and functions, thereby circumventing any filters set by Snuffleupagus. Please disable runkit7."; 6 | 7 | @condition extension_loaded("FFI"); 8 | @warning "FFI extension is loaded. Disabling via 'ffi.enable=false'"; 9 | sp.ini_protection.enable(); 10 | sp.ini.key("ffi.enable").set("false").ro(); 11 | @end_condition; 12 | -------------------------------------------------------------------------------- /utilities/rootkit/aptEverything: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | apt update \ 4 | && apt upgrade \ 5 | && apt autoremove \ 6 | && apt purge \ 7 | && apt autoclean 8 | -------------------------------------------------------------------------------- /utilities/schema/slackManifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "display_information": { 3 | "name": "ebooks", 4 | "description": "BioTorrents.de announce bot", 5 | "background_color": "#2c2d30" 6 | }, 7 | "features": { 8 | "bot_user": { 9 | "display_name": "ebooks", 10 | "always_online": false 11 | } 12 | }, 13 | "oauth_config": { 14 | "scopes": { 15 | "bot": [ 16 | "incoming-webhook" 17 | ] 18 | } 19 | }, 20 | "settings": { 21 | "org_deploy_enabled": false, 22 | "socket_mode_enabled": false, 23 | "token_rotation_enabled": false 24 | } 25 | } -------------------------------------------------------------------------------- /utilities/vault/eloquentModels/Collages.php: -------------------------------------------------------------------------------- 1 | hasMany(TorrentGroup::class, "GroupID", "id"); 34 | } 35 | 36 | 37 | /** methods */ 38 | 39 | 40 | /** 41 | * toJsonApi 42 | * 43 | * @return array 44 | */ 45 | public function toJsonApi(): array 46 | { 47 | # todo 48 | } 49 | } # class 50 | -------------------------------------------------------------------------------- /utilities/vault/eloquentModels/Requests.php: -------------------------------------------------------------------------------- 1 | hasMany(TorrentGroup::class, "GroupID", "id"); 34 | } 35 | 36 | 37 | /** methods */ 38 | 39 | 40 | /** 41 | * toJsonApi 42 | * 43 | * @return array 44 | */ 45 | public function toJsonApi(): array 46 | { 47 | # todo 48 | } 49 | } # class 50 | --------------------------------------------------------------------------------