diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index 60ecbc25..9bbd3435 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -33,7 +33,7 @@ jobs: # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL - uses: github/codeql-action/init@v3 + uses: github/codeql-action/init@v4 with: languages: ${{ matrix.language }} # If you wish to specify custom queries, you can do so here or in a config file. @@ -46,7 +46,7 @@ jobs: # Autobuild attempts to build any compiled languages (C/C++, C#, Go, or Java). # If this step fails, then you should remove it and run the build manually (see below) - name: Autobuild - uses: github/codeql-action/autobuild@v3 + uses: github/codeql-action/autobuild@v4 # ℹ️ Command-line programs to run using the OS shell. # 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun @@ -59,6 +59,6 @@ jobs: # ./location_of_script_within_repo/buildscript.sh - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@v3 + uses: github/codeql-action/analyze@v4 with: category: '/language:${{matrix.language}}' \ No newline at end of file diff --git a/Dockerfile b/Dockerfile index b1b195bb..a6d78a01 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,22 +1,35 @@ FROM ruby:3.3.0-slim -RUN apt-get update \ - && apt-get install -y --no-install-recommends \ +# Set environment variables early +ENV DEBIAN_FRONTEND=noninteractive \ + app_path=/usr/app \ + RAILS_SERVE_STATIC_FILES=true \ + RAILS_LOG_TO_STDOUT=true \ + LD_PRELOAD=/usr/lib/x86_64-linux-gnu/libjemalloc.so.2 \ + RAILS_ENV="production" + +RUN apt-get update && apt-get install -y --no-install-recommends \ libjemalloc-dev \ curl \ gnupg \ build-essential \ - software-properties-common + ca-certificates \ + && mkdir -p /etc/apt/keyrings + +# 1. Install Node.js 20 (LTS) - Modern Method +RUN curl -fsSL https://deb.nodesource.com/gpgkey/nodesource-repo.gpg.key | gpg --dearmor -o /etc/apt/keyrings/nodesource.gpg \ + && echo "deb [signed-by=/etc/apt/keyrings/nodesource.gpg] https://deb.nodesource.com/node_20.x nodistro main" | tee /etc/apt/sources.list.d/nodesource.list -RUN curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | apt-key add - \ - && echo "deb https://dl.yarnpkg.com/debian/ stable main" | tee /etc/apt/sources.list.d/yarn.list \ - && curl -sL https://deb.nodesource.com/setup_14.x | bash - +# 2. Install Node.js and enable Yarn via corepack (more reliable than yarn apt package) +RUN apt-get update && apt-get install -y --no-install-recommends nodejs \ + && corepack enable \ + && corepack prepare yarn@stable --activate -RUN apt-get install -y --no-install-recommends \ +# 3. Install all dependencies in one layer +RUN apt-get update && apt-get install -y --no-install-recommends \ bzip2 \ git \ shared-mime-info \ - ca-certificates \ libffi-dev \ libpq-dev \ libgdbm-dev \ @@ -34,8 +47,6 @@ RUN apt-get install -y --no-install-recommends \ file \ imagemagick \ iproute2 \ - nodejs \ - yarn \ ffmpeg \ supervisor \ libvips42 \ @@ -45,13 +56,6 @@ RUN apt-get install -y --no-install-recommends \ vim \ && rm -rf /var/lib/apt/lists/* -ENV DEBIAN_FRONTEND=noninteractive -ENV app_path=/usr/app -ENV RAILS_SERVE_STATIC_FILES=true -ENV RAILS_LOG_TO_STDOUT=true -ENV LD_PRELOAD=/usr/lib/x86_64-linux-gnu/libjemalloc.so.2 -ENV RAILS_ENV="production" - WORKDIR $app_path # Install Bundler @@ -59,23 +63,21 @@ RUN gem install bundler -v 2.6.6 # Copy Gemfile first for better caching COPY Gemfile* ./ -RUN bundle config set --local deployment 'true' -RUN bundle config set --local without 'development test' -RUN bundle install --jobs 4 +RUN bundle config set --local deployment 'true' \ + && bundle config set --local without 'development test' \ + && bundle install --jobs 4 # Copy the rest of the application -ADD . $app_path +COPY . $app_path -# Precompile Assets with a dummy SECRET_KEY_BASE (only used during build) -RUN SECRET_KEY_BASE_DUMMY=1 bundle exec rake assets:clean -RUN SECRET_KEY_BASE_DUMMY=1 bundle exec rake assets:precompile +# Precompile Assets +RUN SECRET_KEY_BASE_DUMMY=1 bundle exec rake assets:clean \ + && SECRET_KEY_BASE_DUMMY=1 bundle exec rake assets:precompile # Set Executable Permission for Entrypoint RUN chmod +x /usr/app/docker-entrypoint.sh ENTRYPOINT ["/usr/app/docker-entrypoint.sh"] -# Copy supervisord configuration COPY ./supervisord.conf /etc/supervisord.conf -# Start supervisord CMD ["supervisord", "-c", "/etc/supervisord.conf"] \ No newline at end of file diff --git a/Dockerfile.backup b/Dockerfile.backup index bc974482..b1b195bb 100644 --- a/Dockerfile.backup +++ b/Dockerfile.backup @@ -1,7 +1,7 @@ -FROM ruby:3.1.2-slim +FROM ruby:3.3.0-slim RUN apt-get update \ - && apt-get install -y --no-install-recommends \ + && apt-get install -y --no-install-recommends \ libjemalloc-dev \ curl \ gnupg \ @@ -30,12 +30,11 @@ RUN apt-get install -y --no-install-recommends \ default-mysql-client \ default-libmysqlclient-dev \ openssl \ - file \ tzdata \ + file \ imagemagick \ iproute2 \ nodejs \ - libpq-dev\ yarn \ ffmpeg \ supervisor \ @@ -46,30 +45,37 @@ RUN apt-get install -y --no-install-recommends \ vim \ && rm -rf /var/lib/apt/lists/* -ENV DEBIAN_FRONTEND noninteractive -ENV app_path /usr/app -ENV RAILS_SERVE_STATIC_FILES true -ENV RAILS_LOG_TO_STDOUT true - -ENV LD_PRELOAD=/usr/lib/x86_64-linux-gnu/libjemalloc.so +ENV DEBIAN_FRONTEND=noninteractive +ENV app_path=/usr/app +ENV RAILS_SERVE_STATIC_FILES=true +ENV RAILS_LOG_TO_STDOUT=true +ENV LD_PRELOAD=/usr/lib/x86_64-linux-gnu/libjemalloc.so.2 +ENV RAILS_ENV="production" WORKDIR $app_path -RUN echo "install: --no-document" > $HOME/.gemrc && echo "update: --no-document" >> $HOME/.gemrc +# Install Bundler +RUN gem install bundler -v 2.6.6 + +# Copy Gemfile first for better caching COPY Gemfile* ./ -RUN gem install bundler RUN bundle config set --local deployment 'true' RUN bundle config set --local without 'development test' RUN bundle install --jobs 4 +# Copy the rest of the application ADD . $app_path -RUN bundle exec rake assets:clean -RUN bundle exec rake assets:precompile - +# Precompile Assets with a dummy SECRET_KEY_BASE (only used during build) +RUN SECRET_KEY_BASE_DUMMY=1 bundle exec rake assets:clean +RUN SECRET_KEY_BASE_DUMMY=1 bundle exec rake assets:precompile -RUN ["chmod", "+x", "/usr/app/docker-entrypoint.sh"] +# Set Executable Permission for Entrypoint +RUN chmod +x /usr/app/docker-entrypoint.sh ENTRYPOINT ["/usr/app/docker-entrypoint.sh"] +# Copy supervisord configuration COPY ./supervisord.conf /etc/supervisord.conf + +# Start supervisord CMD ["supervisord", "-c", "/etc/supervisord.conf"] \ No newline at end of file diff --git a/README.md b/README.md index 600ac032..a51ccbab 100644 --- a/README.md +++ b/README.md @@ -4,8 +4,6 @@ Welcome to the Patchwork. Developed and maintained by The Newsmast Foundation. Patchwork is a plugin dashboard designed to enhance your Mastodon server with advanced features and a streamlined admin experience, making stewardship of a Mastodon server easier, safer and more fun. - - ## Features #### Opt users in to search @@ -23,12 +21,24 @@ Block spam posts arriving on your server from the federated network. Filters ide #### Content filters Block harmful content arriving on your server from the federated network. Filters identify keywords or phrases in lists of words for specific harms eg. NSFW, Hate speech etc. Each list can be toggled on or off. Create your own list for customised filters. +#### Channel Management + +Channel Types: Support for multiple channel types including Channels, Channel Feeds, Hubs, and Newsmast channels. +Content Types: Configure channels as hashtag-based, contributor-based, group channels, or custom channels with flexible content rules. +Community Rules: Define and display community guidelines and rules for each channel. +Additional Information: Add custom headings and text blocks to provide context for channel visitors. +Social & General Links: Configure sidebar links to external resources, social media profiles, and related content. +#### Channel Content Curation + +Hashtag-Based Content: Populate channels with content from specific hashtags across the Fediverse. +Contributor Management: Add, search, and manage contributors who can post to channels. +Mute Contributors: Mute specific accounts from appearing in channel feeds. +Relay Integration: Connect to relay services like relay.fedi.buzz for hashtag content distribution. +Post Boosting: Automatic boosting of posts through designated boost bot accounts. #### Customise email branding Replace the Mastodon logo in automatic emails with your own. This feature allows you to add your own header image, footer image and accent colour. - - ## Installing Patchwork Find full instructions on how to install Patchwork on your Mastodon server [here](https://github.com/patchwork-hub/patchwork_dashboard/wiki/Installation-guide). @@ -39,7 +49,47 @@ Before running Patchwork, please ensure you have set up a Mastodon server and it You can find the instructions to set up a Mastodon server [here](https://docs.joinmastodon.org/admin/install/). +## Development + +### Prerequisites +- Ruby (check `.ruby-version` for required version) +- PostgreSQL +- Redis + +### Setup + +1. Clone the repository and install dependencies: +```bash +git clone https://github.com/patchwork-hub/patchwork_dashboard.git +cd patchwork_dashboard +bin/setup +``` + +2. Configure environment variables: +```bash +cp .env.sample .env +# Edit .env with your configuration +``` + +3. Set up the database: +```bash +bundle exec rails db:create +bundle exec rails db:migrate +bundle exec rails db:seed +``` + +4. Start the development server: +```bash +bundle exec rails server +``` + +### Code Quality Tools +The project includes several development tools: +- **Bullet**: N+1 query detection +- **Rack Mini Profiler**: Request profiling +- **RuboCop**: Ruby style guide enforcement +- **AnnotateRB**: Schema annotation for models ## The Newsmast Foundation @@ -51,10 +101,14 @@ Visit our website to learn [more](https://www.newsmastfoundation.org/). For support in installing Patchwork, or for more information on our partnerships, please contact us at support@newsmastfoundation.org +## Contributing +Bug reports and pull requests are welcome on GitHub at https://github.com/patchwork-hub/patchwork_dashboard. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the code of conduct. ## Licenses Patchwork is an open source project, licensed under AGPL-3.0. Have fun! +## Code of Conduct +Everyone interacting in the Patchwork Dashboard project's codebases, issue trackers, chat rooms and mailing lists is expected to follow the code of conduct. diff --git a/app/controllers/api/v1/channels_controller.rb b/app/controllers/api/v1/channels_controller.rb index 8733f3ca..662f7915 100644 --- a/app/controllers/api/v1/channels_controller.rb +++ b/app/controllers/api/v1/channels_controller.rb @@ -55,15 +55,27 @@ class ChannelsController < ApiController ].freeze DEFAULT_FIND_OUT_CHANNELS = [ - { slug: 'us-politics', channel_type: Community.channel_types[:newsmast] }, + { slug: 'us-politics', channel_type: Community.channel_types[:newsmast] }, + { slug: 'newyork', channel_type: Community.channel_types[:channel_feed] }, { slug: 'activism-civil-rights', channel_type: Community.channel_types[:newsmast] }, + { slug: 'privacy', channel_type: Community.channel_types[:channel_feed] }, { slug: 'climate-change', channel_type: Community.channel_types[:newsmast]}, - { slug: 'democracy-human-rights', channel_type: Community.channel_types[:newsmast]}, - { slug: 'news-comment-data', channel_type: Community.channel_types[:newsmast] }, { slug: 'lgbtq', channel_type: Community.channel_types[:newsmast] }, { slug: 'us-sport', channel_type: Community.channel_types[:newsmast]} ].freeze + DEFAULT_LEICESTER_CHANNELS = [ + { slug: 'Leicester', channel_type: Community.channel_types[:channel_feed] }, + { slug: 'activism-civil-rights', channel_type: Community.channel_types[:newsmast] }, + { slug: 'climate-change', channel_type: Community.channel_types[:newsmast]}, + { slug: 'trees', channel_type: Community.channel_types[:channel_feed] }, + { slug: 'podcasting', channel_type: Community.channel_types[:channel_feed] }, + { slug: 'greens', channel_type: Community.channel_types[:channel]}, + { slug: 'fedibookclub', channel_type: Community.channel_types[:channel_feed]}, + { slug: 'NoticiasBrasil', channel_type: Community.channel_types[:channel_feed]}, + { slug: 'RenewedResistance', channel_type: Community.channel_types[:channel]} + ] + def recommend_channels @recommended_channels = Community.recommended.exclude_array_ids render json: Api::V1::ChannelSerializer.new(@recommended_channels).serializable_hash.to_json @@ -155,6 +167,10 @@ def find_out_channels render_custom_channels(DEFAULT_FIND_OUT_CHANNELS) end + def leicester_channels + render_custom_channels(DEFAULT_LEICESTER_CHANNELS) + end + def starter_packs_channels starter_packs_channels = load_json_data(starter_pack_data_path('starter_pack_list.json')) diff --git a/app/controllers/server_settings_controller.rb b/app/controllers/server_settings_controller.rb index 60a4c4cc..5888f6e3 100644 --- a/app/controllers/server_settings_controller.rb +++ b/app/controllers/server_settings_controller.rb @@ -79,7 +79,7 @@ def prepare_server_setting desired_order = ['Local Features', 'User Management', 'Content filters', 'Spam filters', 'Federation', 'Plug-ins', 'Bluesky Bridge'] base_features = [ - 'Automatic Search Opt-in', 'Long posts', + 'Automatic Search Opt-out', 'Long posts', 'Automatic Bluesky bridging for new users', 'Spam filters', 'Content filters' ] dashboard_extras = ['Custom theme', 'Guest accounts', 'Analytics', 'Live blocklist', 'Sign up challenge'] diff --git a/app/controllers/wait_lists_controller.rb b/app/controllers/wait_lists_controller.rb index c5f85456..c5db66b4 100644 --- a/app/controllers/wait_lists_controller.rb +++ b/app/controllers/wait_lists_controller.rb @@ -5,7 +5,7 @@ class WaitListsController < ApplicationController PER_PAGE = 10 def index - @search = WaitList.where(channel_type: WaitList.channel_types[:hub]).ransack(params[:q]) + @search = WaitList.ransack(params[:q]) @wait_lists = @search.result.order(used: :asc, created_at: :desc).page(params[:page]).per(PER_PAGE) end diff --git a/app/jobs/create_community_instance_data_job.rb b/app/jobs/create_community_instance_data_job.rb index bc67e1a0..1f866124 100644 --- a/app/jobs/create_community_instance_data_job.rb +++ b/app/jobs/create_community_instance_data_job.rb @@ -91,7 +91,7 @@ def build_payload(community_id, community_slug) sidekiq: calculate_sidekiq_port(community_id), upstream_web: "#{community_id}_#{community_slug}_web", upstream_stream: "#{community_id}_#{community_slug}_stream", - REDIS_NAMESPACE: community_slug, + COMMUNITY_SLUG: community_slug, WEB_DOMAIN: @domain, STREAMING_API_BASE_URL: "wss://#{@domain}", LOCAL_DOMAIN: @domain, diff --git a/app/jobs/scheduler/follow_bluesky_bot_scheduler.rb b/app/jobs/scheduler/follow_bluesky_bot_scheduler.rb index cf9c2b8d..e4954cf4 100644 --- a/app/jobs/scheduler/follow_bluesky_bot_scheduler.rb +++ b/app/jobs/scheduler/follow_bluesky_bot_scheduler.rb @@ -6,13 +6,13 @@ class FollowBlueskyBotScheduler sidekiq_options retry: 0, lock: :until_executed, lock_ttl: 15.minutes.to_i, queue: :scheduler def perform - # return unless ServerSetting.find_by(name: 'Automatic Bluesky bridging for new users')&.value + return unless ServerSetting.find_by(name: 'Automatic Bluesky bridging for new users')&.value - # if is_channel_instance? - # ChannelBlueskyBridgeService.new.process_communities - # else - # NonChannelBlueskyBridgeService.new.process_users - # end + if is_channel_instance? + ChannelBlueskyBridgeService.new.process_communities + else + NonChannelBlueskyBridgeService.new.process_users + end end diff --git a/app/models/account.rb b/app/models/account.rb index 5b7cd788..b6e37cf1 100644 --- a/app/models/account.rb +++ b/app/models/account.rb @@ -150,6 +150,10 @@ def following_ids(account_id = nil) (follow_ids + follow_request_ids).uniq end + # Configures user searchability and discoverability based on the Dashboard's 'search-opt' ServerSetting. + # + # Enabled search-opt: The user becomes hidden from search results. + # Disabled search-opt: The user remains visible and discoverable. def self.update_all_discoverability(value = false) update_all( discoverable: !value, diff --git a/app/models/server_setting.rb b/app/models/server_setting.rb index 8c6ece65..e1f87373 100644 --- a/app/models/server_setting.rb +++ b/app/models/server_setting.rb @@ -51,7 +51,7 @@ def sync_setting end def search_opt_out_filter? - name == "Automatic Search Opt-in" + name == "Automatic Search Opt-out" end def bluesky_bridge_enabled? diff --git a/app/models/user.rb b/app/models/user.rb index 22889fc0..abb93572 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -99,6 +99,10 @@ def primary_community end end + # Configures user searchability and discoverability based on the Dashboard's 'search-opt' ServerSetting. + # + # Enabled search-opt: The user becomes hidden from search results (noindex: true). + # Disabled search-opt: The user remains visible and discoverable (noindex: false). def self.update_all_discoverability(value = false) find_each(batch_size: 1000) do |user| settings_hash = user.settings.present? ? JSON.parse(user.settings) : {} diff --git a/app/views/server_settings/index.html.haml b/app/views/server_settings/index.html.haml index a0d23d4d..957746d8 100644 --- a/app/views/server_settings/index.html.haml +++ b/app/views/server_settings/index.html.haml @@ -120,7 +120,7 @@ = render 'shared/tooltip_custom', tooltip_text: 'Block posts from the microblogging platform Threads, owned by Meta & Instagram.', tooltip_position: 'top' - when 'Custom theme' = render 'shared/tooltip_custom', tooltip_text: 'Browse a variety of themes for your server’s Web interface to give it the flavour you want.', tooltip_position: 'top' - - when 'Automatic Search Opt-in' + - when 'Automatic Search Opt-out' = render 'shared/tooltip_custom', tooltip_text: 'Make all text within the server, including user’s posts and bios, visible to search. Users are able to opt-out if they choose.', tooltip_position: 'top' - when 'Local only posts' = render 'shared/tooltip_custom', tooltip_text: 'Allow users to publish posts just to your server, fostering a greater sense of channel.', tooltip_position: 'top' diff --git a/app/views/wait_lists/index.html.haml b/app/views/wait_lists/index.html.haml index 2a42893f..04e62b28 100644 --- a/app/views/wait_lists/index.html.haml +++ b/app/views/wait_lists/index.html.haml @@ -51,9 +51,9 @@ .row.mt-4 .col-8.d-flex.justify-content-center %div.btn-group - -# %button.btn.btn-danger.ml-3{ id: "create-channel-code-btn" } - -# Generate channel code - -# = image_tag("icons/circle-plus.svg", class: "ml-2", width: "16", height: "16") + %button.btn.btn-danger.ml-3{ id: "create-channel-code-btn" } + Generate channel code + = image_tag("icons/circle-plus.svg", class: "ml-2", width: "16", height: "16") %button.btn.btn-danger.ml-3{ id: "create-hub-code-btn" } Generate hub code = image_tag("icons/circle-plus.svg", class: "ml-2", width: "16", height: "16") diff --git a/config/data/findout/starter_pack_list.json b/config/data/findout/starter_pack_list.json index 4cb97319..d360db29 100644 --- a/config/data/findout/starter_pack_list.json +++ b/config/data/findout/starter_pack_list.json @@ -1,66 +1,4 @@ [ - { - "id": "1", - "title": "Fun, Funny, and Fantastic", - "description": "Add some humour and joy to your feed.", - "collected_by": { - "id": "109429324912042582", - "username": "teamtoot", - "acct": "teamtoot", - "display_name": "Tîm Tŵt Staff", - "locked": false, - "bot": false, - "discoverable": true, - "indexable": true, - "group": false, - "created_at": "2022-11-29T00:00:00.000Z", - "note": "\u003cp\u003eThis account is used by the :twt: community team \u0026amp; we encourage all our members to follow this account for service updates and community announcements.\u003c/p\u003e\u003cp\u003eStarter Packs\u003cbr /\u003e - Staff: \u003ca href=\"https://fedidevs.com/s/NTc5/\" target=\"_blank\" rel=\"nofollow noopener\" translate=\"no\"\u003e\u003cspan class=\"invisible\"\u003ehttps://\u003c/span\u003e\u003cspan class=\"\"\u003efedidevs.com/s/NTc5/\u003c/span\u003e\u003cspan class=\"invisible\"\u003e\u003c/span\u003e\u003c/a\u003e\u003cbr /\u003e - Dysgu Cymraeg: \u003ca href=\"https://fedidevs.com/s/NTgw/\" target=\"_blank\" rel=\"nofollow noopener\" translate=\"no\"\u003e\u003cspan class=\"invisible\"\u003ehttps://\u003c/span\u003e\u003cspan class=\"\"\u003efedidevs.com/s/NTgw/\u003c/span\u003e\u003cspan class=\"invisible\"\u003e\u003c/span\u003e\u003c/a\u003e\u003cbr /\u003e - News/Weather: \u003ca href=\"https://fedidevs.com/s/NTgx/\" target=\"_blank\" rel=\"nofollow noopener\" translate=\"no\"\u003e\u003cspan class=\"invisible\"\u003ehttps://\u003c/span\u003e\u003cspan class=\"\"\u003efedidevs.com/s/NTgx/\u003c/span\u003e\u003cspan class=\"invisible\"\u003e\u003c/span\u003e\u003c/a\u003e\u003cbr /\u003e - Newyddion/Tywydd: \u003ca href=\"https://fedidevs.com/s/NTgy/\" target=\"_blank\" rel=\"nofollow noopener\" translate=\"no\"\u003e\u003cspan class=\"invisible\"\u003ehttps://\u003c/span\u003e\u003cspan class=\"\"\u003efedidevs.com/s/NTgy/\u003c/span\u003e\u003cspan class=\"invisible\"\u003e\u003c/span\u003e\u003c/a\u003e\u003c/p\u003e\u003cp\u003eService Status: \u003ca href=\"https://stats.uptimerobot.com/VNZKPi6YQ\" target=\"_blank\" rel=\"nofollow noopener\" translate=\"no\"\u003e\u003cspan class=\"invisible\"\u003ehttps://\u003c/span\u003e\u003cspan class=\"\"\u003estats.uptimerobot.com/VNZKPi6YQ\u003c/span\u003e\u003cspan class=\"invisible\"\u003e\u003c/span\u003e\u003c/a\u003e\u003c/p\u003e\u003cp\u003eTechnical support: help@toot.wales\u003c/p\u003e", - "url": "https://toot.wales/@teamtoot", - "uri": "https://toot.wales/users/teamtoot", - "avatar": "https://toot.wales/system/accounts/avatars/109/429/324/912/042/582/original/c42386648f059c6c.png", - "avatar_static": "https://toot.wales/system/accounts/avatars/109/429/324/912/042/582/original/c42386648f059c6c.png", - "header": "https://toot.wales/system/accounts/headers/109/429/324/912/042/582/original/c3f87547251a5204.jpg", - "header_static": "https://toot.wales/system/accounts/headers/109/429/324/912/042/582/original/c3f87547251a5204.jpg", - "followers_count": 353, - "following_count": 29, - "statuses_count": 245, - "last_status_at": "2025-12-11", - "hide_collections": false, - "noindex": false, - "emojis": [ - { - "shortcode": "twt", - "url": "https://toot.wales/system/custom_emojis/images/000/075/894/original/7ff84d510813db7d.png", - "static_url": "https://toot.wales/system/custom_emojis/images/000/075/894/static/7ff84d510813db7d.png", - "visible_in_picker": true - } - ], - "roles": [], - "fields": [ - { - "name": "Technical Support", - "value": "\u003ca href=\"https://croeso.toot.wales/en/help/\" target=\"_blank\" rel=\"nofollow noopener me\" translate=\"no\"\u003e\u003cspan class=\"invisible\"\u003ehttps://\u003c/span\u003e\u003cspan class=\"\"\u003ecroeso.toot.wales/en/help/\u003c/span\u003e\u003cspan class=\"invisible\"\u003e\u003c/span\u003e\u003c/a\u003e", - "verified_at": "2025-06-03T12:51:27.213+00:00" - }, - { - "name": "Blog", - "value": "\u003ca href=\"https://croeso.toot.wales/en/blog/\" target=\"_blank\" rel=\"nofollow noopener me\" translate=\"no\"\u003e\u003cspan class=\"invisible\"\u003ehttps://\u003c/span\u003e\u003cspan class=\"\"\u003ecroeso.toot.wales/en/blog/\u003c/span\u003e\u003cspan class=\"invisible\"\u003e\u003c/span\u003e\u003c/a\u003e", - "verified_at": "2025-06-03T12:51:27.512+00:00" - }, - { - "name": "Donations", - "value": "\u003ca href=\"https://opencollective.com/twt-cymru\" target=\"_blank\" rel=\"nofollow noopener me\" translate=\"no\"\u003e\u003cspan class=\"invisible\"\u003ehttps://\u003c/span\u003e\u003cspan class=\"\"\u003eopencollective.com/twt-cymru\u003c/span\u003e\u003cspan class=\"invisible\"\u003e\u003c/span\u003e\u003c/a\u003e", - "verified_at": "2025-01-30T20:43:41.808+00:00" - }, - { - "name": "Service Status", - "value": "Service Status: \u003ca href=\"https://stats.uptimerobot.com/VNZKPi6YQ\" target=\"_blank\" rel=\"nofollow noopener me\" translate=\"no\"\u003e\u003cspan class=\"invisible\"\u003ehttps://\u003c/span\u003e\u003cspan class=\"\"\u003estats.uptimerobot.com/VNZKPi6YQ\u003c/span\u003e\u003cspan class=\"invisible\"\u003e\u003c/span\u003e\u003c/a\u003e", - "verified_at": null - } - ] - }, - "total_accounts": 24 - }, { "id": "2", "title": "Shitposters of the Fediverse", diff --git a/config/initializers/rack_attack.rb b/config/initializers/rack_attack.rb index 38f96133..c582bc77 100644 --- a/config/initializers/rack_attack.rb +++ b/config/initializers/rack_attack.rb @@ -31,7 +31,7 @@ class Rack::Attack /api/v1/channels/channel_feeds ].freeze - throttle('req/ip/protected-endpoints', limit: 20, period: 1.minute) do |req| + throttle('req/ip/protected-endpoints', limit: 300, period: 1.minute) do |req| req.ip if PROTECTED_ENDPOINT_PATHS.include?(req.path) end @@ -47,7 +47,7 @@ class Rack::Attack end # Exponential backoff for repeat offenders using Allow2Ban - PROTECTED_ENDPOINT_BAN_PREFIX = 'rack::attack:ban:protected-endpoints'.freeze + PROTECTED_ENDPOINT_BAN_PREFIX = 'ban:protected-endpoints'.freeze blocklist('ban-protected-endpoint-offenders') do |req| next unless PROTECTED_ENDPOINT_PATHS.include?(req.path) @@ -103,4 +103,9 @@ class Rack::Attack "IP: #{req.ip}, Path: #{req.path}, Matched: #{req.env['rack.attack.matched']}" end end + + safelist('allow-trusted-ip') do |req| + trusted_ips = ['18.134.76.246', '13.41.103.254', '51.24.10.124'] + trusted_ips.include?(req.ip) + end end \ No newline at end of file diff --git a/config/routes/api_v1.rb b/config/routes/api_v1.rb index 8aba0499..f4215f5f 100644 --- a/config/routes/api_v1.rb +++ b/config/routes/api_v1.rb @@ -46,6 +46,7 @@ get :bristol_cable_channels get :starter_packs_channels get :find_out_channels + get :leicester_channels end member do get :starter_packs_detail diff --git a/db/seeds/01_server_setttings.rb b/db/seeds/01_server_setttings.rb index 9346b44e..69933ea1 100644 --- a/db/seeds/01_server_setttings.rb +++ b/db/seeds/01_server_setttings.rb @@ -15,7 +15,7 @@ }, { name: 'Local Features', - options: ['Custom theme', 'Automatic Search Opt-in', 'Local only posts', 'Long posts', 'Local quote posts'] + options: ['Custom theme', 'Automatic Search Opt-out', 'Local only posts', 'Long posts', 'Local quote posts'] }, { name: 'User Management', diff --git a/docker-compose.yml b/docker-compose.yml index 7198da3b..618c5e67 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,10 +1,9 @@ version: '3.8' services: - # Patchwork Dashboard - MVP Version app: image: newsmast/patchwork_dashboard:latest - container_name: patchwork-mvp-dashboard + container_name: patchwork-dashboard restart: unless-stopped env_file: .env environment: @@ -13,11 +12,11 @@ services: ports: - "${EXTERNAL_PORT}:3001" volumes: - - patchwork_mvp_storage:/usr/app/storage - - patchwork_mvp_public:/usr/app/public/system - - patchwork_mvp_logs:/usr/app/log + - patchwork_storage:/usr/app/storage + - patchwork_public:/usr/app/public/system + - patchwork_logs:/usr/app/log networks: - - patchwork_mvp_network + - patchwork_network healthcheck: test: ["CMD-SHELL", "curl -f http://localhost:${EXTERNAL_PORT}/health_check || exit 1"] interval: 30s @@ -26,13 +25,13 @@ services: start_period: 60s volumes: - patchwork_mvp_storage: + patchwork_storage: driver: local - patchwork_mvp_public: + patchwork_public: driver: local - patchwork_mvp_logs: + patchwork_logs: driver: local networks: - patchwork_mvp_network: + patchwork_network: driver: bridge \ No newline at end of file diff --git a/lib/tasks/insert_server_setting_data.rake b/lib/tasks/insert_server_setting_data.rake index 7fda8215..2cf3502f 100644 --- a/lib/tasks/insert_server_setting_data.rake +++ b/lib/tasks/insert_server_setting_data.rake @@ -50,7 +50,7 @@ namespace :db do ], "Local Features" => [ { name: "Custom theme", value: false }, - { name: "Automatic Search Opt-in", value: false }, + { name: "Automatic Search Opt-out", value: false }, { name: "Local only posts", value: false }, { name: "Long posts", value: false }, { name: "Local quote posts", value: false }, diff --git a/lib/tasks/server_setting_update_search_opt_out.rake b/lib/tasks/server_setting_update_search_opt_out.rake new file mode 100644 index 00000000..05d76a41 --- /dev/null +++ b/lib/tasks/server_setting_update_search_opt_out.rake @@ -0,0 +1,27 @@ +namespace :server_setting do + desc "Update ServerSetting names" + task update_search_opt_out: :environment do + puts "Starting update ServerSetting names.." + + updates = { + "Automatic Search Opt-in" => "Automatic Search Opt-out" + } + + updates.each do |old_name, new_name| + update_setting_name(old_name, new_name) + end + + puts "End update ServerSetting names!" + end + + def update_setting_name(old_name, new_name) + setting = ServerSetting.find_by(name: old_name) + + if setting.present? + setting.update!(name: new_name) + puts "Updated ServerSetting: '#{old_name}' -> '#{new_name}'" + else + puts "No ServerSetting found with name '#{old_name}'" + end + end +end