diff --git a/.decidim-version b/.decidim-version index ad2b8d01c6f7c..1027842b9f261 100644 --- a/.decidim-version +++ b/.decidim-version @@ -1 +1 @@ -0.31.4 \ No newline at end of file +0.31.7 \ No newline at end of file diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile index bde812b3c811a..26fed7c35198e 100644 --- a/.devcontainer/Dockerfile +++ b/.devcontainer/Dockerfile @@ -1,8 +1,11 @@ -FROM decidim/decidim:0.22.0-dev +ARG RUBY_VERSION=3.3.4 +FROM ghcr.io/rails/devcontainer/images/ruby:$RUBY_VERSION -RUN apt-get update && apt-get install -y \ - vim +RUN wget -q -O /tmp/google-chrome-key.pub https://dl-ssl.google.com/linux/linux_signing_key.pub \ + && sudo gpg --dearmor -o /usr/share/keyrings/google-chrome-keyring.gpg /tmp/google-chrome-key.pub \ + && echo "deb [arch=amd64 signed-by=/usr/share/keyrings/google-chrome-keyring.gpg] http://dl.google.com/linux/chrome/deb/ stable main" | sudo tee /etc/apt/sources.list.d/google-chrome.list \ + && sudo apt-get update \ + && sudo apt-get install -y google-chrome-stable libicu-dev imagemagick \ + && sudo rm -rf /var/lib/apt/lists/* /tmp/google-chrome-key.pub -ENV EDITOR=vim - -RUN sh -c "$(wget -O- https://github.com/deluan/zsh-in-docker/releases/download/v1.1.1/zsh-in-docker.sh)" +ENV BINDING="0.0.0.0" diff --git a/.devcontainer/compose.yaml b/.devcontainer/compose.yaml new file mode 100644 index 0000000000000..d3c19801cafbd --- /dev/null +++ b/.devcontainer/compose.yaml @@ -0,0 +1,40 @@ +name: "decidim" + +services: + rails-app: + build: + context: .. + dockerfile: .devcontainer/Dockerfile + volumes: + - ../:/workspaces/decidim:cached + ports: + - "${DEVCONTAINER_APP_PORT:-3000}:3000" + env_file: + - path: ../.env + required: false + command: sleep infinity + depends_on: + - redis + - postgres + + redis: + image: redis:7.2 + restart: unless-stopped + volumes: + - redis-data:/data + + postgres: + image: postgres:16.1 + restart: unless-stopped + networks: + - default + volumes: + - postgres-data:/var/lib/postgresql/data + environment: + POSTGRES_USER: postgres + POSTGRES_PASSWORD: postgres + +volumes: + redis-data: + postgres-data: + diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index 4544c22e09232..cf25a3b547aa2 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -1,21 +1,34 @@ -// For format details, see https://aka.ms/devcontainer.json. For config options, see the README at: -// https://github.com/microsoft/vscode-dev-containers/tree/v0.140.1/containers/ruby-rails { - "name": "Ruby on Rails", - "workspaceFolder": "/workspace", - "service": "rails", - "dockerComposeFile": [ - "docker-compose.yml" - ], - "settings": { - "terminal.integrated.shell.linux": "/bin/zsh" - }, - "extensions": [ - "rebornix.Ruby", - "wingrunr21.vscode-ruby", - "misogi.ruby-rubocop" - ], - "forwardPorts": [ - 3000 - ], -} \ No newline at end of file + "name": "decidim", + "dockerComposeFile": "compose.yaml", + "service": "rails-app", + "workspaceFolder": "/workspaces/decidim", + "features": { + "ghcr.io/devcontainers/features/github-cli:1": {}, + // Do not use bundler cache, to not generate conflicts with develop bundler cache + // "ghcr.io/rails/devcontainer/features/bundler-cache:1.0.1": {}, + "ghcr.io/devcontainers/features/docker-outside-of-docker:1": { + "moby": false + }, + "ghcr.io/devcontainers/features/node:1": { + "version": "22.14.0" + }, + "ghcr.io/rails/devcontainer/features/activestorage": {}, + "ghcr.io/rails/devcontainer/features/postgres-client": {} + }, + "containerEnv": { + "REDIS_URL": "redis://redis:6379/1", + "DECIDIM_SPAM_DETECTION_BACKEND_RESOURCE_URL": "redis://redis:6379/2", + "DECIDIM_SPAM_DETECTION_BACKEND_USER_REDIS_URL": "redis://redis:6379/3", + "DATABASE_HOST": "postgres", + "DATABASE_USERNAME": "postgres", + "DATABASE_PASSWORD": "postgres" + }, + "appPort": ["3000:3000"], + "forwardPorts": [ + 3000, + 5432, + 6379 + ], + "postCreateCommand": "bin/setup --skip-server" +} diff --git a/.devcontainer/docker-compose.yml b/.devcontainer/docker-compose.yml deleted file mode 100644 index d2ad07c963e28..0000000000000 --- a/.devcontainer/docker-compose.yml +++ /dev/null @@ -1,27 +0,0 @@ - -version: "3" - -services: - rails: - build: - context: . - dockerfile: Dockerfile - depends_on: - - db - command: /bin/sh -c "while sleep 1000; do :; done" - environment: - DATABASE_HOST: db - DATABASE_USERNAME: postgres - DATABASE_PASSWORD: postgres - db: - image: postgres:9.6 - environment: - POSTGRES_USER: postgres - POSTGRES_PASSWORD: postgres - PGDATA: /var/lib/postgresql/data/pgdata - restart: always - volumes: - - db:/var/lib/postgresql/data - -volumes: - db: \ No newline at end of file diff --git a/.eslintrc.json b/.eslintrc.json index 08de8c7f32172..143dcb4eec859 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -1,3 +1,45 @@ { - "extends": "@decidim" + "extends": "@decidim", + "settings": { + "react": { + "version": "detect" + }, + "import/resolver": { + "node": { + "extensions": [".js"], + "moduleDirectory": [ + "decidim-accountability/app/packs/", + "decidim-admin/app/packs/", + "decidim-ai/app/packs/", + "decidim-api/app/packs/", + "decidim-assemblies/app/packs/", + "decidim-blogs/app/packs/", + "decidim-budgets/app/packs/", + "decidim-collaborative_texts/app/packs/", + "decidim-comments/app/packs/", + "decidim-conferences/app/packs/", + "decidim-core/app/packs/", + "decidim-debates/app/packs/", + "decidim-demographics/app/packs/", + "decidim-design/app/packs/", + "decidim-dev/app/packs/", + "decidim-elections/app/packs/", + "decidim-forms/app/packs/", + "decidim-initiatives/app/packs/", + "decidim-meetings/app/packs/", + "decidim-pages/app/packs/", + "decidim-participatory_processes/app/packs/", + "decidim-proposals/app/packs/", + "decidim-surveys/app/packs/", + "decidim-sortitions/app/packs/", + "decidim-system/app/packs/", + "decidim-templates/app/packs/", + "decidim-verifications/app/packs/", + "packages/core/node_modules/", + "packages/webpacker/node_modules/", + "node_modules/" + ] + } + } + } } diff --git a/.github/actions/spelling/README.md b/.github/actions/spelling/README.md deleted file mode 100644 index da6f2e9d9b52a..0000000000000 --- a/.github/actions/spelling/README.md +++ /dev/null @@ -1,18 +0,0 @@ -# check-spelling/check-spelling configuration - -File | Purpose | Format | Info --|-|-|- -[dictionary.txt](dictionary.txt) | Replacement dictionary (creating this file will override the default dictionary) | one word per line | [dictionary](https://github.com/check-spelling/check-spelling/wiki/Configuration#dictionary) -[allow.txt](allow.txt) | Add words to the dictionary | one word per line (only letters and `'`s allowed) | [allow](https://github.com/check-spelling/check-spelling/wiki/Configuration#allow) -[reject.txt](reject.txt) | Remove words from the dictionary (after allow) | grep pattern matching whole dictionary words | [reject](https://github.com/check-spelling/check-spelling/wiki/Configuration-Examples%3A-reject) -[excludes.txt](excludes.txt) | Files to ignore entirely | perl regular expression | [excludes](https://github.com/check-spelling/check-spelling/wiki/Configuration-Examples%3A-excludes) -[only.txt](only.txt) | Only check matching files (applied after excludes) | perl regular expression | [only](https://github.com/check-spelling/check-spelling/wiki/Configuration-Examples%3A-only) -[patterns.txt](patterns.txt) | Patterns to ignore from checked lines | perl regular expression (order matters, first match wins) | [patterns](https://github.com/check-spelling/check-spelling/wiki/Configuration-Examples%3A-patterns) -[candidate.patterns](candidate.patterns) | Patterns that might be worth adding to [patterns.txt](patterns.txt) | perl regular expression with optional comment block introductions (all matches will be suggested) | [candidates](https://github.com/check-spelling/check-spelling/wiki/Feature:-Suggest-patterns) -[line_forbidden.patterns](line_forbidden.patterns) | Patterns to flag in checked lines | perl regular expression (order matters, first match wins) | [patterns](https://github.com/check-spelling/check-spelling/wiki/Configuration-Examples%3A-patterns) -[expect.txt](expect.txt) | Expected words that aren't in the dictionary | one word per line (sorted, alphabetically) | [expect](https://github.com/check-spelling/check-spelling/wiki/Configuration#expect) -[advice.md](advice.md) | Supplement for GitHub comment when unrecognized words are found | GitHub Markdown | [advice](https://github.com/check-spelling/check-spelling/wiki/Configuration-Examples%3A-advice) -[block-delimiters.list](block-delimiters.list) | Define block begin/end markers to ignore lines of text | line with _literal string_ for **start** followed by line with _literal string_ for **end** | [block ignore](https://github.com/check-spelling/check-spelling/wiki/Feature%3A-Block-Ignore#status) - -Note: you can replace any of these files with a directory by the same name (minus the suffix) -and then include multiple files inside that directory (with that suffix) to merge multiple files together. diff --git a/.github/actions/spelling/advice.md b/.github/actions/spelling/advice.md deleted file mode 100644 index a32d1090aafe1..0000000000000 --- a/.github/actions/spelling/advice.md +++ /dev/null @@ -1,31 +0,0 @@ - -
If the flagged items are :exploding_head: false positives - -If items relate to a ... -* binary file (or some other file you wouldn't want to check at all). - - Please add a file path to the `excludes.txt` file matching the containing file. - - File paths are Perl 5 Regular Expressions - you can [test]( -https://www.regexplanet.com/advanced/perl/) yours before committing to verify it will match your files. - - `^` refers to the file's path from the root of the repository, so `^README\.md$` would exclude [README.md]( -../tree/HEAD/README.md) (on whichever branch you're using). - -* well-formed pattern. - - If you can write a [pattern]( -https://github.com/check-spelling/check-spelling/wiki/Configuration-Examples:-patterns -) that would match it, - try adding it to the `patterns.txt` file. - - Patterns are Perl 5 Regular Expressions - you can [test]( -https://www.regexplanet.com/advanced/perl/) yours before committing to verify it will match your lines. - - Note that patterns can't match multiline strings. - -
- - -:steam_locomotive: If you're seeing this message and your PR is from a branch that doesn't have check-spelling, -please merge to your PR's base branch to get the version configured for your repository. diff --git a/.github/actions/spelling/allow.txt b/.github/actions/spelling/allow.txt deleted file mode 100644 index 2cea09386f672..0000000000000 --- a/.github/actions/spelling/allow.txt +++ /dev/null @@ -1,13 +0,0 @@ -autolabeler -github -https -ssh -ubuntu -workarounds -tokendispatcher -pkce -HTTPOK -iat -jti -JWA -tlh diff --git a/.github/actions/spelling/block-delimiters.list b/.github/actions/spelling/block-delimiters.list deleted file mode 100644 index 4f21922b366f2..0000000000000 --- a/.github/actions/spelling/block-delimiters.list +++ /dev/null @@ -1,15 +0,0 @@ -# Public Keys ------BEGIN PUBLIC KEY----- ------END PUBLIC KEY----- - -# RSA Private Key ------BEGIN RSA PRIVATE KEY----- ------END RSA PRIVATE KEY----- - -# GPG Public Key ------BEGIN PGP PUBLIC KEY BLOCK----- ------END PGP PUBLIC KEY BLOCK----- - -# Certificates ------BEGIN CERTIFICATE----- ------END CERTIFICATE----- diff --git a/.github/actions/spelling/candidate.patterns b/.github/actions/spelling/candidate.patterns deleted file mode 100644 index 922e699dd920e..0000000000000 --- a/.github/actions/spelling/candidate.patterns +++ /dev/null @@ -1,660 +0,0 @@ -# marker to ignore all code on line -^.*/\* #no-spell-check-line \*/.*$ -# marker to ignore all code on line -^.*\bno-spell-check(?:-line|)(?:\s.*|)$ - -# https://cspell.org/configuration/document-settings/ -# cspell inline -^.*\b[Cc][Ss][Pp][Ee][Ll]{2}:\s*[Dd][Ii][Ss][Aa][Bb][Ll][Ee]-[Ll][Ii][Nn][Ee]\b - -# patch hunk comments -^\@\@ -\d+(?:,\d+|) \+\d+(?:,\d+|) \@\@ .* -# git index header -index (?:[0-9a-z]{7,40},|)[0-9a-z]{7,40}\.\.[0-9a-z]{7,40} - -# file permissions -['"`\s][-bcdLlpsw](?:[-r][-w][-Ssx]){2}[-r][-w][-SsTtx]\+?['"`\s] - -# css url wrappings -\burl\([^)]+\) - -# cid urls -(['"])cid:.*?\g{-1} - -# data url in parens -\(data:(?:[^) ][^)]*?|)(?:[A-Z]{3,}|[A-Z][a-z]{2,}|[a-z]{3,})[^)]*\) -# data url in quotes -([`'"])data:(?:[^ `'"].*?|)(?:[A-Z]{3,}|[A-Z][a-z]{2,}|[a-z]{3,}).*\g{-1} -# data url -\bdata:[-a-zA-Z=;:/0-9+]*,\S* - -# https/http/file urls -(?:\b(?:https?|ftp|file)://)[-A-Za-z0-9+&@#/%?=~_|!:,.;]+[-A-Za-z0-9+&@#/%=~_|] - -# mailto urls -#mailto:[-a-zA-Z=;:/?%&0-9+@._]{3,} - -# magnet urls -magnet:[?=:\w]+ - -# magnet urls -"magnet:[^"]+" - -# obs: -"obs:[^"]*" - -# The `\b` here means a break, it's the fancy way to handle urls, but it makes things harder to read -# In this examples content, I'm using a number of different ways to match things to show various approaches -# asciinema -\basciinema\.org/a/[0-9a-zA-Z]+ - -# asciinema v2 -^\[\d+\.\d+, "[io]", ".*"\]$ - -# apple -\bdeveloper\.apple\.com/[-\w?=/]+ -# Apple music -\bembed\.music\.apple\.com/fr/playlist/usr-share/[-\w.]+ - -# appveyor api -\bci\.appveyor\.com/api/projects/status/[0-9a-z]+ -# appveyor project -\bci\.appveyor\.com/project/(?:[^/\s"]*/){2}builds?/\d+/job/[0-9a-z]+ - -# Amazon - -# Amazon -\bamazon\.com/[-\w]+/(?:dp/[0-9A-Z]+|) -# AWS S3 -\b\w*\.s3[^.]*\.amazonaws\.com/[-\w/&#%_?:=]* -# AWS execute-api -\b[0-9a-z]{10}\.execute-api\.[-0-9a-z]+\.amazonaws\.com\b -# AWS ELB -\b\w+\.[-0-9a-z]+\.elb\.amazonaws\.com\b -# AWS SNS -\bsns\.[-0-9a-z]+.amazonaws\.com/[-\w/&#%_?:=]* -# AWS VPC -vpc-\w+ - -# While you could try to match `http://` and `https://` by using `s?` in `https?://`, sometimes there -# YouTube url -\b(?:(?:www\.|)youtube\.com|youtu.be)/(?:channel/|embed/|user/|playlist\?list=|watch\?v=|v/|)[-a-zA-Z0-9?&=_%]* -# YouTube music -\bmusic\.youtube\.com/youtubei/v1/browse(?:[?&]\w+=[-a-zA-Z0-9?&=_]*) -# YouTube tag -<\s*youtube\s+id=['"][-a-zA-Z0-9?_]*['"] -# YouTube image -\bimg\.youtube\.com/vi/[-a-zA-Z0-9?&=_]* -# Google Accounts -\baccounts.google.com/[-_/?=.:;+%&0-9a-zA-Z]* -# Google Analytics -\bgoogle-analytics\.com/collect.[-0-9a-zA-Z?%=&_.~]* -# Google APIs -\bgoogleapis\.(?:com|dev)/[a-z]+/(?:v\d+/|)[a-z]+/[-@:./?=\w+|&]+ -# Google Storage -\b[-a-zA-Z0-9.]*\bstorage\d*\.googleapis\.com(?:/\S*|) -# Google Calendar -\bcalendar\.google\.com/calendar(?:/u/\d+|)/embed\?src=[@./?=\w&%]+ -\w+\@group\.calendar\.google\.com\b -# Google DataStudio -\bdatastudio\.google\.com/(?:(?:c/|)u/\d+/|)(?:embed/|)(?:open|reporting|datasources|s)/[-0-9a-zA-Z]+(?:/page/[-0-9a-zA-Z]+|) -# The leading `/` here is as opposed to the `\b` above -# ... a short way to match `https://` or `http://` since most urls have one of those prefixes -# Google Docs -/docs\.google\.com/[a-z]+/(?:ccc\?key=\w+|(?:u/\d+|d/(?:e/|)[0-9a-zA-Z_-]+/)?(?:edit\?[-\w=#.]*|/\?[\w=&]*|)) -# Google Drive -\bdrive\.google\.com/(?:file/d/|open)[-0-9a-zA-Z_?=]* -# Google Groups -\bgroups\.google\.com(?:/[a-z]+/(?:#!|)[^/\s"]+)* -# Google Maps -\bmaps\.google\.com/maps\?[\w&;=]* -# Google themes -themes\.googleusercontent\.com/static/fonts/[^/\s"]+/v\d+/[^.]+. -# Google CDN -\bclients2\.google(?:usercontent|)\.com[-0-9a-zA-Z/.]* -# Goo.gl -/goo\.gl/[a-zA-Z0-9]+ -# Google Chrome Store -\bchrome\.google\.com/webstore/detail/[-\w]*(?:/\w*|) -# Google Books -\bgoogle\.(?:\w{2,4})/books(?:/\w+)*\?[-\w\d=&#.]* -# Google Fonts -\bfonts\.(?:googleapis|gstatic)\.com/[-/?=:;+&0-9a-zA-Z]* -# Google Forms -\bforms\.gle/\w+ -# Google Scholar -\bscholar\.google\.com/citations\?user=[A-Za-z0-9_]+ -# Google Colab Research Drive -\bcolab\.research\.google\.com/drive/[-0-9a-zA-Z_?=]* - -# GitHub SHAs (api) -\bapi.github\.com/repos(?:/[^/\s"]+){3}/[0-9a-f]+\b -# GitHub SHAs (markdown) -(?:\[`?[0-9a-f]+`?\]\(https:/|)/(?:www\.|)github\.com(?:/[^/\s"]+){2,}(?:/[^/\s")]+)(?:[0-9a-f]+(?:[-0-9a-zA-Z/#.]*|)\b|) -# GitHub SHAs -\bgithub\.com(?:/[^/\s"]+){2}[@#][0-9a-f]+\b -# GitHub SHA refs -\[([0-9a-f]+)\]\(https://(?:www\.|)github.com/[-\w]+/[-\w]+/commit/\g{-1}[0-9a-f]* -# GitHub wiki -\bgithub\.com/(?:[^/]+/){2}wiki/(?:(?:[^/]+/|)_history|[^/]+(?:/_compare|)/[0-9a-f.]{40,})\b -# githubusercontent -/[-a-z0-9]+\.githubusercontent\.com/[-a-zA-Z0-9?&=_\/.]* -# githubassets -\bgithubassets.com/[0-9a-f]+(?:[-/\w.]+) -# gist github -\bgist\.github\.com/[^/\s"]+/[0-9a-f]+ -# git.io -\bgit\.io/[0-9a-zA-Z]+ -# GitHub JSON -"node_id": "[-a-zA-Z=;:/0-9+_]*" -# Contributor -\[[^\]]+\]\(https://github\.com/[^/\s"]+/?\) -# GHSA -GHSA(?:-[0-9a-z]{4}){3} - -# GitHub actions -\buses:\s+[-\w.]+/[-\w./]+@[-\w.]+ - -# GitLab commit -\bgitlab\.[^/\s"]*/\S+/\S+/commit/[0-9a-f]{7,16}#[0-9a-f]{40}\b -# GitLab merge requests -\bgitlab\.[^/\s"]*/\S+/\S+/-/merge_requests/\d+/diffs#[0-9a-f]{40}\b -# GitLab uploads -\bgitlab\.[^/\s"]*/uploads/[-a-zA-Z=;:/0-9+]* -# GitLab commits -\bgitlab\.[^/\s"]*/(?:[^/\s"]+/){2}commits?/[0-9a-f]+\b - -# binance -accounts\.binance\.com/[a-z/]*oauth/authorize\?[-0-9a-zA-Z&%]* - -# bitbucket diff -\bapi\.bitbucket\.org/\d+\.\d+/repositories/(?:[^/\s"]+/){2}diff(?:stat|)(?:/[^/\s"]+){2}:[0-9a-f]+ -# bitbucket repositories commits -\bapi\.bitbucket\.org/\d+\.\d+/repositories/(?:[^/\s"]+/){2}commits?/[0-9a-f]+ -# bitbucket commits -\bbitbucket\.org/(?:[^/\s"]+/){2}commits?/[0-9a-f]+ - -# bit.ly -\bbit\.ly/\w+ - -# bitrise -\bapp\.bitrise\.io/app/[0-9a-f]*/[\w.?=&]* - -# bootstrapcdn.com -\bbootstrapcdn\.com/[-./\w]+ - -# cdn.cloudflare.com -\bcdnjs\.cloudflare\.com/[./\w]+ - -# circleci -\bcircleci\.com/gh(?:/[^/\s"]+){1,5}.[a-z]+\?[-0-9a-zA-Z=&]+ - -# gitter -\bgitter\.im(?:/[^/\s"]+){2}\?at=[0-9a-f]+ - -# gravatar -\bgravatar\.com/avatar/[0-9a-f]+ - -# ibm -[a-z.]*ibm\.com/[-_#=:%!?~.\\/\d\w]* - -# imgur -\bimgur\.com/[^.]+ - -# Internet Archive -\barchive\.org/web/\d+/(?:[-\w.?,'/\\+&%$#_:]*) - -# discord -/discord(?:app\.com|\.gg)/(?:invite/)?[a-zA-Z0-9]{7,} - -# Disqus -\bdisqus\.com/[-\w/%.()!?&=_]* - -# medium link -\blink\.medium\.com/[a-zA-Z0-9]+ -# medium -\bmedium\.com/\@?[^/\s"]+/[-\w]+ - -# microsoft -\b(?:https?://|)(?:(?:download\.visualstudio|docs|msdn2?|research)\.microsoft|blogs\.msdn)\.com/[-_a-zA-Z0-9()=./%]* -# powerbi -\bapp\.powerbi\.com/reportEmbed/[^"' ]* -# vs devops -\bvisualstudio.com(?::443|)/[-\w/?=%&.]* -# microsoft store -\bmicrosoft\.com/store/apps/\w+ - -# mvnrepository.com -\bmvnrepository\.com/[-0-9a-z./]+ - -# now.sh -/[0-9a-z-.]+\.now\.sh\b - -# oracle -\bdocs\.oracle\.com/[-0-9a-zA-Z./_?#&=]* - -# chromatic.com -/\S+.chromatic.com\S*[")] - -# codacy -\bapi\.codacy\.com/project/badge/Grade/[0-9a-f]+ - -# compai -\bcompai\.pub/v1/png/[0-9a-f]+ - -# mailgun api -\.api\.mailgun\.net/v3/domains/[0-9a-z]+\.mailgun.org/messages/[0-9a-zA-Z=@]* -# mailgun -\b[0-9a-z]+.mailgun.org - -# /message-id/ -/message-id/[-\w@./%]+ - -# Reddit -\breddit\.com/r/[/\w_]* - -# requestb.in -\brequestb\.in/[0-9a-z]+ - -# sched -\b[a-z0-9]+\.sched\.com\b - -# Slack url -slack://[a-zA-Z0-9?&=]+ -# Slack -\bslack\.com/[-0-9a-zA-Z/_~?&=.]* -# Slack edge -\bslack-edge\.com/[-a-zA-Z0-9?&=%./]+ -# Slack images -\bslack-imgs\.com/[-a-zA-Z0-9?&=%.]+ - -# shields.io -\bshields\.io/[-\w/%?=&.:+;,]* - -# stackexchange -- https://stackexchange.com/feeds/sites -\b(?:askubuntu|serverfault|stack(?:exchange|overflow)|superuser).com/(?:questions/\w+/[-\w]+|a/) - -# Sentry -[0-9a-f]{32}\@o\d+\.ingest\.sentry\.io\b - -# Twitter markdown -\[\@[^[/\]:]*?\]\(https://twitter.com/[^/\s"')]*(?:/status/\d+(?:\?[-_0-9a-zA-Z&=]*|)|)\) -# Twitter hashtag -\btwitter\.com/hashtag/[\w?_=&]* -# Twitter status -\btwitter\.com/[^/\s"')]*(?:/status/\d+(?:\?[-_0-9a-zA-Z&=]*|)|) -# Twitter profile images -\btwimg\.com/profile_images/[_\w./]* -# Twitter media -\btwimg\.com/media/[-_\w./?=]* -# Twitter link shortened -\bt\.co/\w+ - -# facebook -\bfburl\.com/[0-9a-z_]+ -# facebook CDN -\bfbcdn\.net/[\w/.,]* -# facebook watch -\bfb\.watch/[0-9A-Za-z]+ - -# dropbox -\bdropbox\.com/sh?/[^/\s"]+/[-0-9A-Za-z_.%?=&;]+ - -# ipfs protocol -ipfs://[0-9a-zA-Z]{3,} -# ipfs url -/ipfs/[0-9a-zA-Z]{3,} - -# w3 -\bw3\.org/[-0-9a-zA-Z/#.]+ - -# loom -\bloom\.com/embed/[0-9a-f]+ - -# regex101 -\bregex101\.com/r/[^/\s"]+/\d+ - -# figma -\bfigma\.com/file(?:/[0-9a-zA-Z]+/)+ - -# freecodecamp.org -\bfreecodecamp\.org/[-\w/.]+ - -# image.tmdb.org -\bimage\.tmdb\.org/[/\w.]+ - -# mermaid -\bmermaid\.ink/img/[-\w]+|\bmermaid-js\.github\.io/mermaid-live-editor/#/edit/[-\w]+ - -# Wikipedia -\ben\.wikipedia\.org/wiki/[-\w%.#]+ - -# gitweb -[^"\s]+/gitweb/\S+;h=[0-9a-f]+ - -# HyperKitty lists -/archives/list/[^@/]+\@[^/\s"]*/message/[^/\s"]*/ - -# lists -/thread\.html/[^"\s]+ - -# list-management -\blist-manage\.com/subscribe(?:[?&](?:u|id)=[0-9a-f]+)+ - -# kubectl.kubernetes.io/last-applied-configuration -"kubectl.kubernetes.io/last-applied-configuration": ".*" - -# pgp -\bgnupg\.net/pks/lookup[?&=0-9a-zA-Z]* - -# Spotify -\bopen\.spotify\.com/embed/playlist/\w+ - -# Mastodon -\bmastodon\.[-a-z.]*/(?:media/|\@)[?&=0-9a-zA-Z_]* - -# scastie -\bscastie\.scala-lang\.org/[^/]+/\w+ - -# images.unsplash.com -\bimages\.unsplash\.com/(?:(?:flagged|reserve)/|)[-\w./%?=%&.;]+ - -# pastebin -\bpastebin\.com/[\w/]+ - -# heroku -\b\w+\.heroku\.com/source/archive/\w+ - -# quip -\b\w+\.quip\.com/\w+(?:(?:#|/issues/)\w+)? - -# badgen.net -\bbadgen\.net/badge/[^")\]'\s]+ - -# statuspage.io -\w+\.statuspage\.io\b - -# media.giphy.com -\bmedia\.giphy\.com/media/[^/]+/[\w.?&=]+ - -# tinyurl -\btinyurl\.com/\w+ - -# codepen -\bcodepen\.io/[\w/]+ - -# registry.npmjs.org -\bregistry\.npmjs\.org/(?:@[^/"']+/|)[^/"']+/-/[-\w@.]+ - -# getopts -\bgetopts\s+(?:"[^"]+"|'[^']+') - -# ANSI color codes -(?:\\(?:u00|x)1[Bb]|\x1b|\\u\{1[Bb]\})\[\d+(?:;\d+|)m - -# URL escaped characters -%[0-9A-F][A-F](?=[A-Za-z]) -# lower URL escaped characters -%[0-9a-f][a-f](?=[a-z]{2,}) -# IPv6 -\b(?:[0-9a-fA-F]{0,4}:){3,7}[0-9a-fA-F]{0,4}\b -# c99 hex digits (not the full format, just one I've seen) -0x[0-9a-fA-F](?:\.[0-9a-fA-F]*|)[pP] -# Punycode -\bxn--[-0-9a-z]+ -# sha -sha\d+:[0-9]*[a-f]{3,}[0-9a-f]* -# sha-... -- uses a fancy capture -(\\?['"]|")[0-9a-f]{40,}\g{-1} -# hex runs -\b[0-9a-fA-F]{16,}\b -# hex in url queries -=[0-9a-fA-F]*?(?:[A-F]{3,}|[a-f]{3,})[0-9a-fA-F]*?& -# ssh -(?:ssh-\S+|-nistp256) [-a-zA-Z=;:/0-9+]{12,} - -# PGP -\b(?:[0-9A-F]{4} ){9}[0-9A-F]{4}\b -# GPG keys -\b(?:[0-9A-F]{4} ){5}(?: [0-9A-F]{4}){5}\b -# Well known gpg keys -.well-known/openpgpkey/[\w./]+ - -# pki ------BEGIN.*-----END - -# uuid: -\b[0-9a-fA-F]{8}-(?:[0-9a-fA-F]{4}-){3}[0-9a-fA-F]{12}\b -# hex digits including css/html color classes: -(?:[\\0][xX]|\\u|[uU]\+|#x?|%23)[0-9_a-fA-FgGrR]*?[a-fA-FgGrR]{2,}[0-9_a-fA-FgGrR]*(?:[uUlL]{0,3}|[iu]\d+)\b -# integrity -integrity=(['"])(?:\s*sha\d+-[-a-zA-Z=;:/0-9+]{40,})+\g{-1} - -# https://www.gnu.org/software/groff/manual/groff.html -# man troff content -\\f[BCIPR] -# '/" -\\\([ad]q - -# .desktop mime types -^MimeTypes?=.*$ -# .desktop localized entries -^[A-Z][a-z]+\[[a-z]+\]=.*$ -# Localized .desktop content -Name\[[^\]]+\]=.* - -# IServiceProvider / isAThing -\b(?:I|isA)(?=(?:[A-Z][a-z]{2,})+(?:[A-Z]|\b)) - -# crypt -(['"])\$2[ayb]\$.{56}\g{-1} - -# scrypt / argon -\$(?:scrypt|argon\d+[di]*)\$\S+ - -# go.sum -\bh1:\S+ - -# scala modules -("[^"]+"\s*%%?\s*){2,3}"[^"]+" - -# Input to GitHub JSON -content: (['"])[-a-zA-Z=;:/0-9+]*=\g{-1} - -# This does not cover multiline strings, if your repository has them, -# you'll want to remove the `(?=.*?")` suffix. -# The `(?=.*?")` suffix should limit the false positives rate -# printf -%(?:(?:(?:hh?|ll?|[jzt])?[diuoxn]|l?[cs]|L?[fega]|p)(?=[a-z]{2,})|(?:X|L?[FEGA]|p)(?=[a-zA-Z]{2,}))(?!%)(?=[_a-zA-Z]+(?!%)\b)(?=.*?['"]) - -# Alternative printf -# %s -%(?:s(?=[a-z]{2,}))(?!%)(?=[_a-zA-Z]+(?!%)\b)(?=.*?['"]) - -# Python string prefix / binary prefix -# Note that there's a high false positive rate, remove the `?=` and search for the regex to see if the matches seem like reasonable strings -(?|m([|!/@#,;']).*?\g{-1}) - -# perl qr regex -(?|\(.*?\)|([|!/@#,;']).*?\g{-1}) - -# perl run -perl(?:\s+-[a-zA-Z]\w*)+ - -# C network byte conversions -#(?:\d|\bh)to(?!ken)(?=[a-z])|to(?=[adhiklpun]\() - -# Go regular expressions -regexp?\.MustCompile\(`[^`]*`\) - -# regex choice -\(\?:[^)]+\|[^)]+\) - -# proto -^\s*(\w+)\s\g{-1} = - -# sed regular expressions -sed 's/(?:[^/]*?[a-zA-Z]{3,}[^/]*?/){2} - -# node packages -(["'])\@[^/'" ]+/[^/'" ]+\g{-1} - -# go install -go install(?:\s+[a-z]+\.[-@\w/.]+)+ - -# jetbrains schema https://youtrack.jetbrains.com/issue/RSRP-489571 -urn:shemas-jetbrains-com - -# kubernetes pod status lists -# https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle/#pod-phase -\w+(?:-\w+)+\s+\d+/\d+\s+(?:Running|Pending|Succeeded|Failed|Unknown)\s+ - -# kubectl - pods in CrashLoopBackOff -\w+-[0-9a-f]+-\w+\s+\d+/\d+\s+CrashLoopBackOff\s+ - -# kubernetes object suffix --[0-9a-f]{10}-\w{5}\s - -# posthog secrets -([`'"])phc_[^"',]+\g{-1} - -# xcode - -# xcodeproject scenes -(?:Controller|destination|ID|id)="\w{3}-\w{2}-\w{3}" - -# xcode api botches -customObjectInstantitationMethod - -# configure flags -.* \| --\w{2,}.*?(?=\w+\s\w+) - -# font awesome classes -\.fa-[-a-z0-9]+ - -# bearer auth -(['"])Bear[e][r] .*?\g{-1} - -# bearer auth -Bear[e][r]:? [-a-zA-Z=;:/0-9+.]+ - -# basic auth -(['"])Basic [-a-zA-Z=;:/0-9+]{3,}\g{-1} - -# base64 encoded content -([`'"])[-a-zA-Z=;:/0-9+]{3,}=\g{-1} -# base64 encoded content in xml/sgml ->[-a-zA-Z=;:/0-9+]{3,}== 0.0.22) -\\\w{2,}\{ - -# eslint -"varsIgnorePattern": ".+" - -# Windows short paths -[/\\][^/\\]{5,6}~\d{1,2}[/\\] - -# cygwin paths -/cygdrive/[a-zA-Z]/(?:Program Files(?: \(.*?\)| ?)(?:/[-+.~\\/()\w ]+)*|[-+.~\\/()\w])+ - -# in check-spelling@v0.0.22+, printf markers aren't automatically consumed -# printf markers -(?v# -(?:(?<=[A-Z]{2})V|(?<=[a-z]{2}|[A-Z]{2})v)\d+(?:\b|(?=[a-zA-Z_])) - -# Compiler flags (Unix, Java/Scala) -# Use if you have things like `-Pdocker` and want to treat them as `docker` -#(?:^|[\t ,>"'`=(])-(?:(?:J-|)[DPWXY]|[Llf])(?=[A-Z]{2,}|[A-Z][a-z]|[a-z]{2,}) - -# Compiler flags (Windows / PowerShell) -# This is a subset of the more general compiler flags pattern. -# It avoids matching `-Path` to prevent it from being treated as `ath` -#(?:^|[\t ,"'`=(])-(?:[DPL](?=[A-Z]{2,})|[WXYlf](?=[A-Z]{2,}|[A-Z][a-z]|[a-z]{2,})) - -# Compiler flags (linker) -,-B - -# curl arguments -\b(?:\\n|)curl(?:\.exe|)(?:\s+-[a-zA-Z]{1,2}\b)*(?:\s+-[a-zA-Z]{3,})(?:\s+-[a-zA-Z]+)* -# set arguments -\b(?:bash|sh|set)(?:\s+-[abefimouxE]{1,2})*\s+-[abefimouxE]{3,}(?:\s+-[abefimouxE]+)* -# tar arguments -\b(?:\\n|)g?tar(?:\.exe|)(?:(?:\s+--[-a-zA-Z]+|\s+-[a-zA-Z]+|\s[ABGJMOPRSUWZacdfh-pr-xz]+\b)(?:=[^ ]*|))+ -# tput arguments -- https://man7.org/linux/man-pages/man5/terminfo.5.html -- technically they can be more than 5 chars long... -\btput\s+(?:(?:-[SV]|-T\s*\w+)\s+)*\w{3,5}\b -# macOS temp folders -/var/folders/\w\w/[+\w]+/(?:T|-Caches-)/ -# github runner temp folders -/home/runner/work/_temp/[-_/a-z0-9]+ diff --git a/.github/actions/spelling/excludes.txt b/.github/actions/spelling/excludes.txt deleted file mode 100644 index cb7f1f58cd5bc..0000000000000 --- a/.github/actions/spelling/excludes.txt +++ /dev/null @@ -1,120 +0,0 @@ -# See https://github.com/check-spelling/check-spelling/wiki/Configuration-Examples:-excludes -(?:^|/)(?i)COPYRIGHT -(?:^|/)(?i)LICEN[CS]E -(?:^|/)3rdparty/ -(?:^|/)\.keep$ -(?:^|/)go\.sum$ -(?:^|/)package(?:-lock|)\.json$ -(?:^|/)Pipfile$ -(?:^|/)pyproject.toml -(?:^|/)requirements(?:-dev|-doc|-test|)\.txt$ -(?:^|/)vendor/ -[^/]\.jwk$ -[^/]\.odt$ -\.a$ -\.ai$ -\.all-contributorsrc$ -\.avi$ -\.bmp$ -\.bz2$ -\.cer$ -\.class$ -\.coveragerc$ -\.crl$ -\.crt$ -\.csr$ -\.dll$ -\.docx?$ -\.drawio$ -\.DS_Store$ -\.eot$ -\.eps$ -\.exe$ -\.gif$ -\.git-blame-ignore-revs$ -\.gitattributes$ -\.gitkeep$ -\.graffle$ -\.gz$ -\.icns$ -\.ico$ -\.ipynb$ -\.jar$ -\.jks$ -\.jpe?g$ -\.key$ -\.lib$ -\.lock$ -\.map$ -\.min\.. -\.mo$ -\.mod$ -\.mp[34]$ -\.o$ -\.ocf$ -\.otf$ -\.p12$ -\.parquet$ -\.pdf$ -\.pem$ -\.pfx$ -\.png$ -\.psd$ -\.pyc$ -\.pylintrc$ -\.qm$ -\.s$ -\.sig$ -\.so$ -\.svgz?$ -\.sys$ -\.tar$ -\.tgz$ -\.tiff?$ -\.ttf$ -\.wav$ -\.webm$ -\.webp$ -\.woff2?$ -\.xcf$ -\.xlsx?$ -\.xpm$ -\.xz$ -\.zip$ -^\.github/actions/spelling/ -^\Q.github/workflows/spelling.yml\E$ -/db/migrate/ -/locales/ -^\Q.erb-lint.yml\E$ -^\Q.erb_lint.yml\E$ -^\Q.spelling.yml\E$ -^\QCHANGELOG.md\E$ -^\Qpubliccode.yml\E$ -^\Qdecidim-accountability/spec/fixtures/valid_result.csv\E$ -^\Qdecidim-assemblies/app/packs/src/decidim/assemblies/orgchart.js\E$ -^\Qdecidim-core/app/cells/decidim/amendable/amenders_list/show.erb\E$ -^\Qdecidim-core/app/cells/decidim/card_l/extra_data.erb\E$ -^\Qdecidim-core/app/cells/decidim/content_blocks/base/content.erb\E$ -^\Qdecidim-core/app/packs/src/decidim/decidim_application.js\E$ -^\Qdecidim-core/app/views/decidim/account/_user_groups.html.erb\E$ -^\Qdecidim-core/app/views/decidim/shared/_comments.html.erb\E$ -^\Qdecidim-core/app/views/layouts/decidim/_edit_link.html.erb\E$ -^\Qdecidim-core/lib/decidim/db/common-passwords.txt\E$ -^\Qdecidim-core/spec/mailers/decidim_devise_mailer_spec.rb\E$ -^\Qdecidim-core/spec/db/data/add_short_name_to_organizations_spec.rb\E$ -^\Qdecidim-dev/lib/decidim/dev/assets/assemblies.json\E$ -^\Qdecidim-dev/lib/decidim/dev/assets/base64_content.html\E$ -^\Qdecidim-dev/lib/decidim/dev/assets/import_proposals.csv\E$ -^\Qdecidim-dev/lib/decidim/dev/assets/import_proposals.json\E$ -^\Qdecidim-dev/lib/decidim/dev/assets/import_proposals_broken.csv\E$ -^\Qdecidim-dev/lib/decidim/dev/assets/participatory_processes.json\E$ -^\Qdecidim-initiatives/app/views/decidim/initiatives/initiatives/_linked_initiatives.html.erb\E$ -^\Qdecidim-meetings/app/views/decidim/meetings/admin/agenda/show.html.erb\E$ -^\Qdecidim-participatory_processes/app/views/decidim/participatory_processes/participatory_processes/_statistics.html.erb\E$ -^\Qdecidim-ai/data/blocked_accounts.csv\E$ -^\Qdecidim-ai/data/sms-spam.csv\E$ -^\Qdecidim-ai/data/spam_comments.csv\E$ -^\Qdecidim-ai/spec/support/test.csv\E$ -^\Qdocs/modules/develop/assets/attachments/grafana/metadecidim-graphql.json\E$ -^\Qdocs/modules/develop/assets/attachments/grafana/metadecidim-csv.json\E$ -ignore$ diff --git a/.github/actions/spelling/expect.txt b/.github/actions/spelling/expect.txt deleted file mode 100644 index c14bc9e1abe17..0000000000000 --- a/.github/actions/spelling/expect.txt +++ /dev/null @@ -1,989 +0,0 @@ -Aaaa -Aabb -abans -abcd -abcert -abcloktpes -acceptada -accesslist -acentos -acro -activejob -activelog -activemodel -activerecord -activestorage -actualitzar -actualizado -addlabel -Adeu -adjunt -admins -adoc -AFFERO -AGPL -aitools -Ajuntament -Ajuntamentde -alabs -alecslupu -Alexandru -amagat -amd -amendables -AMR -andreslucena -ANOT -antora -Anunci -apiauth -apikey -aproximadamente -aquesta -ARBITRARYREF -arel -Arquitectura -Arrakis -Artagnan -arxiu -associacio -atcat -atiger -Atlassian -attachables -attachablesform -authlogic -authorable -auths -autocorrection -autocorrects -automatisms -autosort -autotranslated -autowidth -AXXXXXXXX -backported -backporter -backticks -barcat -Basecamp -Basecontroller -Batchloader -bayes -bbb -Bbbb -BCN -beforeinput -beforeinstallprompt -belighted -bem -bgset -Biblioteca -bindir -binread -binstub -binwrite -blabla -blockless -blockquotes -blogpost -blogs -bmbm -boundingbox -Brakus -breadcrumb -browserstack -bugfixing -byebug -bytesize -cacatua -Calafell -Calibri -callouts -CALSCALE -Cambios -camelization -cami -Capfile -carolromero -Carrer -carryforward -catala -Catalunya -categorizable -cattr -cbracket -CCORP -ccv -cdn -cdp -cellphone -changeme -chartkick -cherrypicking -childs -chromedriver -cityhall -clickable -clickbait -cmax -cmin -coauthorable -coauthorabledummy -cobertura -codecov -codefor -CODEOWNERS -codeql -coditramuntana -commentables -commentaire -commenters -commentvotes -conferenceinvites -conferenceregistrations -confirmada -confirmado -confirmat -Consolas -constantized -contingut -continuar -contrasenya -coopdevs -correu -Cov -Cprojects -crdownload -crear -createcluster -createuser -crowdin -crt -cryptor -CSPs -csrf -csslintrc -CSSs -cta -cuenta -Cugat -customise -Customising -cweek -cyclomatic -danline -dasherize -dataconsent -dataselect -dataviz -Daunou -dayjs -DDG -ddmm -deauthorizes -debante -debian -decidiamo -decidim -decidimcommandscreateresource -decidimcommandsdestroyresource -decidimcommandsupdateresource -deconstantize -Defg -deivid -demodulize -demodulized -Denesik -denunciat -detalles -devcontainer -dfd -Dfyv -DIBA -diffable -diffing -diffs -diffy -digidemlab -dilema -Disableable -displaycondition -django -dni -dockerflow -Doctum -doesnot -doggotrainer -Dokku -Dota -douban -downvoted -downvotes -downvoting -draggables -dragula -drinkform -dropcluster -dsl -dtend -dtgt -dtgteq -dtlt -dtlteq -dtstart -dvh -editlabel -editorlabel -edu -eeny -elina -emoji -emojiable -emojidata -Emph -encryptable -encryptor -endo -endr -enduml -enquestes -ent -Entra -entrypath -entrypoints -enviado -envrc -EOCONTENT -EOEXPECTED -EOLIST -EOPARAGRAPH -EORESULT -EOTASK -eql -equalcat -equales -equalto -erabaki -erblint -Errbit -Esa -espa -estar -estat -etherpad -evanfuture -evt -Exampledocument -Existente -EXISTINGCITY -exitstatus -faketoken -Fal -fcell -fcm -FEDER -felipe -fhtagn -fieldsets -Fillmurray -filn -finaltype -fingerprintable -Firefox -flaggable -flamegraph -flexbugs -Flickr -flt -focusguard -fontawesome -Fonticons -foobardoe -foobaz -foocat -foodform -fooes -fooo -foos -formattings -formelements -formfield -forminvalid -formreset -formvalid -formvalidator -Fpb -freetext -Fritsch -Froilan -gadgetmodel -gamification -gamified -GCell -gcs -Gcv -gemfile -genereation -genis -geocodable -geocoded -geocodes -geocoordinate -geolocalizable -geolocated -getobj -GFM -GHSA -gia -Girona -gitpod -googleoff -googleon -gotchas -gpg -gpu -gql -grafana -Graphi -graphiql -groupless -Gruhier -grup -gsutil -gteq -Gual -GVzd -Gyver -hadolint -haml -Hammes -hashdiff -hashtaggable -hashtags -heighta -heightb -hereapi -Heroku -hexapdf -hideable -highlightjs -hll -HMi -hmr -hmtl -Hnwif -Hodor -Holas -honeypots -hooli -hotwired -housenumber -hsh -hsts -httpdate -httpfoobar -httpsfoobar -huedelta -iaa -iban -ical -icalendar -icondata -ics -idx -iframes -iife -Ijkl -ilike -illgotten -impersonatable -inbox -includeurl -Indicacions -infoa -infob -informables -Inici -iniciar -inodes -inputdialog -inputname -Inscriu -interf -inviteduser -isbn -iseq -isready -Italiano -ivan -Jaskolski -Jaume -javascripts -jdoe -Jeet -Jenae -Jfcm -jfif -jkl -JKR -joannadoe -joedoe -joh -johndoe -johnohara -jon -josepjaume -jpe -jschmoe -jslib -jsperezg -julia -justme -kathline -Kerrigan -keyfile -keyout -keypart -keyserver -kramdoc -kramdown -kwbegin -laguardia -Lalalilo -latlng -Layouter -LCell -legacysupport -Lesch -lfo -libicu -libpq -libreadline -libreoffice -libu -libyaml -Liddel -lighthouserc -likeables -linebreak -linkbubble -linkedin -linthtml -linthtmlrc -linting -listid -litem -llarg -Llaurador -Llobregat -lng -Localret -localvars -loggable -lon -LOPD -los -Lovecraft -lsclusters -lte -lteq -LTREE -Lupu -lvh -magick -mainio -Malgrat -Mandaliya -maptiles -markercluster -marydoe -Massot -matrixmultiple -matutes -maxtimeout -mcdoggo -mcell -medios -meeny -meh -mensaje -mentionables -mergeable -meses -metadatas -metadecidim -metaprogrammed -metaprogramming -metatags -mic -mickdoe -mikedoe -Milhouse -millor -Millora -mintimeout -minuscat -misogi -mlat -mlon -Mobi -modals -modernizrrc -modestbranding -modificado -modifs -modqule -mongoid -morphdom -Mostrar -mozilla -mpassid -mrc -mri -mso -msword -multichoice -multifield -multitenant -mycity -myengine -mypass -myprovider -mytesturl -myuser -neighbourhoods -Neue -newadmin -NEWCODE -newsletterable -newusermanager -newwindow -ngrams -nicknamenicknamenick -nicknamenicknamenickname -nicknamizable -nicknamize -nie -nikola -nlevel -nocaps -nocookie -NOCREATEROLE -nodoc -nok -nombre -nominatim -noresults -normalcase -notif -notselected -nric -nto -nuqmnw -NVDA -objecte -oblidat -Occaecati -ocultat -odf -odnoklassniki -odt -officedocument -officializating -officializations -officializes -ofthe -Okuneva -oldman -Oma -Omnia -OMNIATH -omniauth -omniauthable -oneline -Onmi -Ooo -opencollective -opendocument -openstreetmap -openxmlformats -OPR -optin -orga -Oriol -oriolgual -ORMs -osallistu -osm -oss -osv -osx -otf -otg -otheradmin -otherpath -ots -ott -outdenting -outdents -outdir -outro -owib -Paa -paddable -pageload -paginable -palotes -pamplona -pandoc -paramxx -partcipatory -participatoryspaceprivateusers -patrimonigracia -Peguera -pepito -Percebe -perfil -Peroy -persistor -personalitzat -pgdata -pgp -PGVERSION -Phargo -phoe -pinterest -Placeholdit -plantuml -plataforma -platoniq -pluscat -plusplus -Poblenou -Podemos -Poemes -pokecode -Pollich -polygonpoints -popupclose -popupopen -posmatch -postgre -postgresql -ppx -prebuilds -precache -preheader -premailer -Preproc -presenceness -previewurl -privatable -Procesos -processess -procfile -PRODID -progname -progressbox -promotal -promotors -proposta -Propostes -Propuesta -prosemirror -protonmail -publicable -Pujol -pwa -QLiterals -qlty -queda -qux -raf -railtie -railties -randomable -ransackable -Ratke -Raymundo -rbngzlv -reallowed -rebornix -rebutjada -recapitated -reconfirmable -redcarpet -reddit -refactorings -regexes -regexps -registrado -registrat -reivindicate -relogin -remindable -remittant -remixicon -renderized -Renetta -reofficialize -reorderer -Repelle -reportables -reportat -resourcable -resourceable -Returs -Riera -Rigoberto -riseup -roadmap -Rojman -routable -rowdata -rowi -RQR -rqrcode -rroe -rsefa -rsimplecov -Rubo -rubycw -rumany -ruybgems -rvm -Ryanair -Sangtrait -sanitizers -scannables -SCell -scheleton -Schoen -scopable -screenreader -screenshots -searchables -sectorials -selectables -selectednode -selfxss -separador -sereneinserenade -serializeds -setseed -sgid -shakapacker -sharedapp -shellcheckrc -shs -sidekiq -signedby -siguientes -similars -Simonis -singlechoice -slugization -slugizes -smartbreak -Smileys -Snowlvhme -Snoworg -softdeleteable -somecapitalguy -somedatabase -Sorbier -sortings -sortitions -sortupdate -sourced -spammer -spos -spreadsheetml -sqbracket -sss -Stabby -stackprof -Stadi -standarized -startuml -stftime -Stylelinter -stylelintrc -subattributes -subelements -subforms -subgems -subkeys -submodel -subpage -subquery -subrecord -subresult -subscope -subsubscope -subtemplate -subtpl -subu -subvalue -suomifi -Superkalifragilistic -superklass -superprocess -sustainability -swc -tableize -tailwindcss -tarekraafat -taxonomizable -taxonomization -technopolitical -templatable -templateable -Terica -Terrassa -terrats -territorials -testid -testsecret -teva -texta -Textareas -textb -texto -thant -thelma -thepassword -THH -thi -Tiene -tilelayer -timedout -timelapse -timeoutable -timeouter -timestamped -tiptap -TLDR -Tmpname -todos -Tomorrowland -tomselect -tooshort -topbar -tophat -traceabilty -traducido -Tramuntana -trashable -traslatable -trgm -trobada -tsearch -turbolinks -Twilio -tzid -ucw -udev -ueee -ugc -ujs -ukmany -unassigning -unassigns -uncollapsing -uncommentable -undefines -unfollow -unhides -Uninstalls -unmark -unofficializating -unofficialization -unofficialize -unofficialized -unofficializing -unperformant -Unpublicable -unpublishes -unpublishing -unpublshed -unregisters -unreport -unresolveable -unsigning -unsigns -unsubscribes -untrains -unvotes -upcomingfoobar -UPDREF -uploaders -upvoted -upvotes -upvoting -usecase -usename -usuarias -Uth -utm -Uusimaa -Valero -validable -valids -Valuetypes -VCALENDAR -veeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeery -verificator -verylongnicknamethatcreatesanerror -VEVENT -vfield -Vilanova -vimeo -VJHT -vkontakte -vnd -voner -vostre -votar -votings -VPAGQ -vrojman -wadus -WAI -wcag -webcam -webpacker -webpage -webpush -websites -wechat -whatislove -whatsapp -widtha -widthb -wifi -wingrunr -winutils -wip -wisper -withdrawability -WYSWYG -XForwarded -xing -xobject -Xvfb -XXXXXXXXY -XXXXXXXY -yardopts -ydd -yieldparam -yieldreturn -yoda -youruser -youtu -youtube -yuyuyukie -Zbd -Zupper -zzz diff --git a/.github/actions/spelling/line_forbidden.patterns b/.github/actions/spelling/line_forbidden.patterns deleted file mode 100644 index bcc1b36625c73..0000000000000 --- a/.github/actions/spelling/line_forbidden.patterns +++ /dev/null @@ -1,151 +0,0 @@ -# reject `m_data` as VxWorks defined it and that breaks things if it's used elsewhere -# see [fprime](https://github.com/nasa/fprime/commit/d589f0a25c59ea9a800d851ea84c2f5df02fb529) -# and [Qt](https://github.com/qtproject/qt-solutions/blame/fb7bc42bfcc578ff3fa3b9ca21a41e96eb37c1c7/qtscriptclassic/src/qscriptbuffer_p.h#L46) -#\bm_data\b - -# Were you debugging using a framework with `fit()`? -# If you have a framework that uses `it()` for testing and `fit()` for debugging a specific test, -# you might not want to check in code where you skip all the other tests. -#\bfit\( - -# Should be `anymore` -\bany more[,.] - -# Should be `cannot` (or `can't`) -# See https://www.grammarly.com/blog/cannot-or-can-not/ -# > Don't use `can not` when you mean `cannot`. The only time you're likely to see `can not` written as separate words is when the word `can` happens to precede some other phrase that happens to start with `not`. -# > `Can't` is a contraction of `cannot`, and it's best suited for informal writing. -# > In formal writing and where contractions are frowned upon, use `cannot`. -# > It is possible to write `can not`, but you generally find it only as part of some other construction, such as `not only . . . but also.` -# - if you encounter such a case, add a pattern for that case to patterns.txt. -\b[Cc]an not\b - -# Should be `GitHub` -(?v# -(?:(?<=[A-Z]{2})V|(?<=[a-z]{2}|[A-Z]{2})v)\d+(?:\b|(?=[a-zA-Z_])) - -# hit-count: 8 file-count: 6 -# GitHub actions -\buses:\s+[-\w.]+/[-\w./]+@[-\w.]+ - -# hit-count: 5 file-count: 2 -# assign regex -= /[^*]*?(?:[a-z]{3,}|[A-Z]{3,}|[A-Z][a-z]{2,}).*/ - -# hit-count: 4 file-count: 4 -# javascript match regex -\.match\(/[^/\s"]{3,}/[gim]*\s* - -# hit-count: 4 file-count: 4 -# perl regex test -[!=]~ (?:/.*/|m\{.*?\}|m<.*?>|m([|!/@#,;']).*?\g{-1}) - -# hit-count: 4 file-count: 2 -# lower URL escaped characters -%[0-9a-f][a-f](?=[a-z]{2,}) - -# hit-count: 3 file-count: 3 -# javascript replace regex -\.replace\(/[^/\s"]{3,}/[gim]*\s*, - -# hit-count: 3 file-count: 2 -# data url in quotes -([`'"])data:(?:[^ `'"].*?|)(?:[A-Z]{3,}|[A-Z][a-z]{2,}|[a-z]{3,}).*\g{-1} - -# hit-count: 3 file-count: 2 -# regex choice -\(\?:[^)]+\|[^)]+\) - -# hit-count: 2 file-count: 2 -# uuid: -\b[0-9a-fA-F]{8}-(?:[0-9a-fA-F]{4}-){3}[0-9a-fA-F]{12}\b - -# hit-count: 2 file-count: 2 -# base64 encoded content -([`'"])[-a-zA-Z=;:/0-9+]{3,}=\g{-1} - -# hit-count: 2 file-count: 2 -# curl arguments -\b(?:\\n|)curl(?:\.exe|)(?:\s+-[a-zA-Z]{1,2}\b)*(?:\s+-[a-zA-Z]{3,})(?:\s+-[a-zA-Z]+)* - -/redirect/[^/]+ - -(\b|")(?:ar|ca|cs|cy|da|de|de-CH|e[lsu]|es-MX|f[ari]|ga|he|hi|id|it|nl|no|pt|pl|pt-BR|ru|si|sv|th|tr|uk|ur|vi|zh)\g{-1}(?: =>|:) ".*?" - -sgid=[-%\w]+ -(?:href|name|value)=".*?" - -\\A(?=[A-Za-z]{2}) - -IDENTIFICATION_PRIVATE_KEY: '.*' -password(?:: | = )".*" -let\(:password\) \{ ".*" -value="[-\w]{16,} -_key: "[\w]{10,}= - -let\(:\w+\) \{ "[a-z]+[A-Z0-9][a-zA-Z0-9]+" - -W3C - -^.*# intentionally misspelled - -# Foreign names -- check-spelling doesn't handle these well -\b[a-zO]'[a-z]{3,}\b - -%250a - -@rails/\w+ - -organization_name[):{ ]*"?(?:\w+\s)+\w+[",} ]*$ -expect\(.*\)\.to eq\(".*" -gem ".*?" -".*?typo\b.*?" - -# Questionably acceptable forms of `in to` -# Personally, I prefer `log into`, but people object -# https://www.tprteaching.com/log-into-log-in-to-login/ -\b(?:[Ll]og|[Ss]ign) in to\b - -# to opt in -\bto opt in\b - -# acceptable duplicates -# ls directory listings -[-bcdlpsw](?:[-r][-w][-SsTtx]){3}[\.+*]?\s+\d+\s+\S+\s+\S+\s+\d+\s+ -# mount -\bmount\s+-t\s+(\w+)\s+\g{-1}\b -# C types and repeated CSS values -\s(auto|center|div|inherit|long|LONG|none|normal|solid|thin|text|think|transparent|very)(?: \g{-1})+\s -# C struct -\bstruct\s+(\w+)\s+\g{-1}\b -# go templates -\s(\w+)\s+\g{-1}\s+\`(?:graphql|inject|json|yaml): -# doxygen / javadoc / .net -(?:[\\@](?:brief|groupname|t?param|return|retval)|(?:public|private|\[Parameter(?:\(.+\)|)\])(?:\s+static|\s+override|\s+readonly)*)(?:\s+\{\w+\}|)\s+(\w+)\s+\g{-1}\s - -# Commit message -- Signed-off-by and friends -^\s*(?:(?:Based-on-patch|Co-authored|Helped|Mentored|Reported|Reviewed|Signed-off)-by|Thanks-to): (?:[^<]*<[^>]*>|[^<]*)\s*$ - -# Autogenerated revert commit message -^This reverts commit [0-9a-f]{40}\.$ - -# ignore long runs of a single character: -\b([A-Za-z])\g{-1}{3,}\b diff --git a/.github/actions/spelling/reject.txt b/.github/actions/spelling/reject.txt deleted file mode 100644 index e5e4c3eef82e4..0000000000000 --- a/.github/actions/spelling/reject.txt +++ /dev/null @@ -1,11 +0,0 @@ -^attache$ -^bellow$ -benefitting -occurences? -^dependan.* -^oer$ -Sorce -^[Ss]pae.* -^untill$ -^untilling$ -^wether.* diff --git a/.github/workflows/check_locale_completeness.yml b/.github/workflows/check_locale_completeness.yml index ef6da9d03599c..aa0e6eb83dc99 100644 --- a/.github/workflows/check_locale_completeness.yml +++ b/.github/workflows/check_locale_completeness.yml @@ -15,7 +15,7 @@ concurrency: jobs: check-locale: name: Check locale completeness - runs-on: ubuntu-22.04 + runs-on: ubuntu-24.04 steps: - uses: actions/checkout@v6 diff --git a/.github/workflows/ci_backporter.yml b/.github/workflows/ci_backporter.yml index ea00977417fff..3029a9a320d2a 100644 --- a/.github/workflows/ci_backporter.yml +++ b/.github/workflows/ci_backporter.yml @@ -14,7 +14,7 @@ env: jobs: backport: name: "Backporter" - runs-on: ubuntu-22.04 + runs-on: ubuntu-24.04 timeout-minutes: 60 # the below IF structure checks: # - PR repository must be the official Decidim repository ( decidim/decidim ) diff --git a/.github/workflows/ci_generators.yml b/.github/workflows/ci_generators.yml index 02028669d5824..6b7d88e3f9bfc 100644 --- a/.github/workflows/ci_generators.yml +++ b/.github/workflows/ci_generators.yml @@ -56,7 +56,7 @@ jobs: - command: bundle exec parallel_test --type rspec --pattern spec/lib/ name: Lib name: ${{ matrix.test.name }} - runs-on: ubuntu-22.04 + runs-on: ubuntu-24.04 if: "!startsWith(github.head_ref, 'chore/l10n')" timeout-minutes: 90 services: diff --git a/.github/workflows/ci_initiatives.yml b/.github/workflows/ci_initiatives.yml index 2dd5b83241e4b..9c19f7fa432d0 100644 --- a/.github/workflows/ci_initiatives.yml +++ b/.github/workflows/ci_initiatives.yml @@ -16,6 +16,7 @@ on: - "decidim-core/**" - "decidim-dev/**" - "decidim-initiatives/**" + - "decidim-meetings/**" - "decidim-verifications/**" permissions: diff --git a/.github/workflows/ci_javascript.yml b/.github/workflows/ci_javascript.yml index ee6d704ae79d0..85890d9be0eb9 100644 --- a/.github/workflows/ci_javascript.yml +++ b/.github/workflows/ci_javascript.yml @@ -33,7 +33,7 @@ concurrency: jobs: main: name: Tests - runs-on: ubuntu-22.04 + runs-on: ubuntu-24.04 if: "!startsWith(github.head_ref, 'chore/l10n')" timeout-minutes: 60 steps: diff --git a/.github/workflows/ci_main.yml b/.github/workflows/ci_main.yml index 83cbb40e11148..f276fc16af470 100644 --- a/.github/workflows/ci_main.yml +++ b/.github/workflows/ci_main.yml @@ -26,7 +26,7 @@ concurrency: jobs: main: name: Tests - runs-on: ubuntu-22.04 + runs-on: ubuntu-24.04 timeout-minutes: 60 steps: - uses: actions/checkout@v4 diff --git a/.github/workflows/ci_performance_metrics_monitoring.yml b/.github/workflows/ci_performance_metrics_monitoring.yml index 77e95a5752253..7cca7520b8b68 100644 --- a/.github/workflows/ci_performance_metrics_monitoring.yml +++ b/.github/workflows/ci_performance_metrics_monitoring.yml @@ -34,7 +34,7 @@ concurrency: jobs: main: name: Tests - runs-on: ubuntu-22.04 + runs-on: ubuntu-24.04 if: "!startsWith(github.head_ref, 'chore/l10n')" timeout-minutes: 60 services: @@ -64,6 +64,10 @@ jobs: - uses: actions/checkout@v4 with: fetch-depth: 1 + - run: | + sudo apt-get update && sudo apt-get install imagemagick + name: Install libvips + shell: "bash" - uses: ruby/setup-ruby@v1 with: ruby-version: ${{ env.RUBY_VERSION }} diff --git a/.github/workflows/ci_production_check.yml b/.github/workflows/ci_production_check.yml index c2d810b51b646..863d856572d78 100644 --- a/.github/workflows/ci_production_check.yml +++ b/.github/workflows/ci_production_check.yml @@ -30,7 +30,7 @@ concurrency: jobs: main: name: Tests - runs-on: ubuntu-22.04 + runs-on: ubuntu-24.04 if: "!startsWith(github.head_ref, 'chore/l10n')" timeout-minutes: 60 services: diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index c0a1c8774c489..062b8723a2a2b 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -23,7 +23,7 @@ on: jobs: analyze: name: Analyze (${{ matrix.language }}) - runs-on: ubuntu-22.04 + runs-on: ubuntu-24.04 timeout-minutes: 60 concurrency: group: ${{ github.workflow }}-${{ github.head_ref || github.ref }}-${{ matrix.language }} diff --git a/.github/workflows/lint_code.yml b/.github/workflows/lint_code.yml index 5e23627de491f..e2f79f31dfd67 100644 --- a/.github/workflows/lint_code.yml +++ b/.github/workflows/lint_code.yml @@ -37,7 +37,7 @@ jobs: - ./.github/run_spelling_check.sh - npm run linthtml name: Lint code - runs-on: ubuntu-22.04 + runs-on: ubuntu-24.04 if: "!startsWith(github.head_ref, 'chore/l10n')" timeout-minutes: 60 steps: diff --git a/.github/workflows/lint_pr_format.yml b/.github/workflows/lint_pr_format.yml index 499a5ffe5f538..6717998478d0b 100644 --- a/.github/workflows/lint_pr_format.yml +++ b/.github/workflows/lint_pr_format.yml @@ -23,7 +23,7 @@ permissions: jobs: check_title: name: Check PR title - runs-on: ubuntu-22.04 + runs-on: ubuntu-24.04 steps: - uses: deepakputhraya/action-pr-title@master with: @@ -38,7 +38,7 @@ jobs: permissions: contents: read pull-requests: write - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 steps: - uses: actions/checkout@v4 - uses: actions/labeler@v5 @@ -48,7 +48,7 @@ jobs: check_label: needs: labeler name: Check PR labels - runs-on: ubuntu-22.04 + runs-on: ubuntu-24.04 steps: - uses: jesusvasquez333/verify-pr-label-action@v1.4.0 with: diff --git a/.github/workflows/on_docs_update.yml b/.github/workflows/on_docs_update.yml index 2bf96cbc4fdbb..e094e6f6ac9af 100644 --- a/.github/workflows/on_docs_update.yml +++ b/.github/workflows/on_docs_update.yml @@ -10,7 +10,7 @@ on: jobs: trigger_documentation_build: name: Trigger decidim/documentation build - runs-on: ubuntu-22.04 + runs-on: ubuntu-24.04 timeout-minutes: 60 steps: - name: Send dispatch for trigger_build workflow diff --git a/.github/workflows/on_release.yml b/.github/workflows/on_release.yml index 22c0ffc754d2f..040aa26d38bb0 100644 --- a/.github/workflows/on_release.yml +++ b/.github/workflows/on_release.yml @@ -6,7 +6,7 @@ on: jobs: trigger_docker_build: name: Trigger decidim/docker build - runs-on: ubuntu-22.04 + runs-on: ubuntu-24.04 timeout-minutes: 60 steps: - name: Send dispatch for Docker Hub build diff --git a/.github/workflows/spelling.yml b/.github/workflows/spelling.yml deleted file mode 100644 index 249efd1b3801d..0000000000000 --- a/.github/workflows/spelling.yml +++ /dev/null @@ -1,150 +0,0 @@ -name: Check Spelling - -# Comment management is handled through a secondary job, for details see: -# https://github.com/check-spelling/check-spelling/wiki/Feature%3A-Restricted-Permissions -# -# `jobs.comment-push` runs when a push is made to a repository and the `jobs.spelling` job needs to make a comment -# (in odd cases, it might actually run just to collapse a comment, but that's fairly rare) -# it needs `contents: write` in order to add a comment. -# -# `jobs.comment-pr` runs when a pull_request is made to a repository and the `jobs.spelling` job needs to make a comment -# or collapse a comment (in the case where it had previously made a comment and now no longer needs to show a comment) -# it needs `pull-requests: write` in order to manipulate those comments. - -# Updating pull request branches is managed via comment handling. -# For details, see: https://github.com/check-spelling/check-spelling/wiki/Feature:-Update-expect-list -# -# These elements work together to make it happen: -# -# `on.issue_comment` -# This event listens to comments by users asking to update the metadata. -# -# `jobs.update` -# This job runs in response to an issue_comment and will push a new commit -# to update the spelling metadata. -# -# `with.experimental_apply_changes_via_bot` -# Tells the action to support and generate messages that enable it -# to make a commit to update the spelling metadata. -# -# `with.ssh_key` -# In order to trigger workflows when the commit is made, you can provide a -# secret (typically, a write-enabled github deploy key). -# -# For background, see: https://github.com/check-spelling/check-spelling/wiki/Feature:-Update-with-deploy-key - -# Sarif reporting -# -# Access to Sarif reports is generally restricted (by GitHub) to members of the repository. -# -# Requires enabling `security-events: write` -# and configuring the action with `use_sarif: 1` -# -# For information on the feature, see: https://github.com/check-spelling/check-spelling/wiki/Feature:-Sarif-output - -# Minimal workflow structure: -# -# on: -# push: -# ... -# pull_request_target: -# ... -# jobs: -# # you only want the spelling job, all others should be omitted -# spelling: -# # remove `security-events: write` and `use_sarif: 1` -# # remove `experimental_apply_changes_via_bot: 1` -# ... otherwise adjust the `with:` as you wish - -on: - push: - branches: - - "**" - tags-ignore: - - "**" - pull_request_target: - branches: - - "**" - types: - - 'opened' - - 'reopened' - - 'synchronize' - issue_comment: - types: - - 'created' - -jobs: - spelling: - name: Check Spelling - permissions: - contents: read - pull-requests: read - actions: read - security-events: write - outputs: - followup: ${{ steps.spelling.outputs.followup }} - runs-on: ubuntu-22.04 - if: ${{ contains(github.event_name, 'pull_request') || github.event_name == 'push' }} - concurrency: - group: spelling-${{ github.event.pull_request.number || github.ref }} - # note: If you use only_check_changed_files, you do not want cancel-in-progress - cancel-in-progress: true - steps: - - name: check-spelling - id: spelling - uses: check-spelling/check-spelling@v0.0.24 - with: - suppress_push_for_open_pull_request: ${{ github.actor != 'dependabot[bot]' && 1 }} - checkout: true - check_file_names: 1 - spell_check_this: check-spelling/spell-check-this@prerelease - post_comment: 0 - use_magic_file: 1 - report-timing: 1 - warnings: bad-regex,binary-file,deprecated-feature,ignored-expect-variant,large-file,limited-references,no-newline-at-eof,noisy-file,non-alpha-in-dictionary,token-is-substring,unexpected-line-ending,whitespace-in-dictionary,minified-file,unsupported-configuration,no-files-to-check - experimental_apply_changes_via_bot: ${{ github.repository_owner != 'decidim' && 1 }} - use_sarif: ${{ (!github.event.pull_request || (github.event.pull_request.head.repo.full_name == github.repository)) && 1 }} - check_extra_dictionaries: '' - extra_dictionaries: - cspell:software-terms/dict/softwareTerms.txt - cspell:lorem-ipsum/dictionary.txt - cspell:fullstack/dict/fullstack.txt - cspell:typescript/dict/typescript.txt - cspell:aws/aws.txt - cspell:php/dict/php.txt - cspell:python/src/python/python-lib.txt - cspell:html/dict/html.txt - cspell:ruby/dict/ruby.txt - cspell:filetypes/filetypes.txt - cspell:java/src/java.txt - cspell:node/dict/node.txt - cspell:npm/dict/npm.txt - cspell:css/dict/css.txt - cspell:shell/dict/shell-all-words.txt - cspell:k8s/dict/k8s.txt - cspell:python/src/common/extra.txt - cspell:dotnet/dict/dotnet.txt - - update: - name: Update PR - permissions: - contents: write - pull-requests: write - actions: read - runs-on: ubuntu-22.04 - if: ${{ - github.repository_owner != 'decidim' && - github.event_name == 'issue_comment' && - github.event.issue.pull_request && - contains(github.event.comment.body, '@check-spelling-bot apply') - }} - concurrency: - group: spelling-update-${{ github.event.issue.number }} - cancel-in-progress: false - steps: - - name: apply spelling updates - uses: check-spelling/check-spelling@v0.0.24 - with: - experimental_apply_changes_via_bot: 1 - checkout: true - ssh_key: "${{ secrets.CHECK_SPELLING }}" diff --git a/.github/workflows/test_app.yml b/.github/workflows/test_app.yml index e2634f0edb61e..b74bc2e77aad3 100644 --- a/.github/workflows/test_app.yml +++ b/.github/workflows/test_app.yml @@ -42,7 +42,7 @@ on: jobs: build_app: name: Test - runs-on: ubuntu-22.04 + runs-on: ubuntu-24.04 if: "!startsWith(github.head_ref, 'chore/l10n')" timeout-minutes: 60 env: @@ -54,7 +54,7 @@ jobs: PARALLEL_TEST_PROCESSORS: 3 services: validator: - image: ghcr.io/validator/validator:latest + image: ${{ vars.ACTION_ACCESSIBILITY_VALIDATOR_VERSION || 'ghcr.io/validator/validator:latest' }} ports: ["8888:8888"] postgres: image: postgres:14 @@ -70,6 +70,10 @@ jobs: - uses: actions/checkout@v4 with: fetch-depth: 1 + - run: | + sudo apt-get update && sudo apt-get install imagemagick + name: Install libvips + shell: "bash" - uses: ruby/setup-ruby@v1 with: ruby-version: ${{ inputs.ruby_version }} diff --git a/.gitignore b/.gitignore index c3bd03e19df05..cc1d4ed7569ed 100644 --- a/.gitignore +++ b/.gitignore @@ -36,3 +36,4 @@ decidim-packs packages/**/package-lock.json temporary_changelog.md +.devcontainer/devcontainer.local.* diff --git a/CHANGELOG.md b/CHANGELOG.md index ac9291add22e0..5549d6582ee37 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,194 @@ # Changelog +## [0.31.7](https://github.com/decidim/decidim/tree/0.31.7) + +### Added + +Nothing. + +### Changed + +Nothing. + +### Fixed + +- **decidim-dev**: Backport 'Add ARIA role for the accessibility report button' to v0.31 [\#17260](https://github.com/decidim/decidim/pull/17260) +- **decidim-comments**, **decidim-core**, **decidim-debates**, **decidim-initiatives**, **decidim-proposals**: Backport 'Remove user's nickname from notifications and emails' to v0.31 [\#17225](https://github.com/decidim/decidim/pull/17225) +- **decidim-collaborative_texts**, **decidim-dev**: Backport 'Fix flaky spec at admin publishes and unpublishes document' to v0.31 [\#17264](https://github.com/decidim/decidim/pull/17264) +- **decidim-assemblies**, **decidim-conferences**, **decidim-core**, **decidim-initiatives**, **decidim-meetings**, **decidim-participatory processes**: Backport 'Fix double-escaping of component names in participatory space nav links and card' to v0.31 [\#16965](https://github.com/decidim/decidim/pull/16965) +- **decidim-core**: Backport 'Fix ENV var for setting inactive users deletion period' to v0.31 [\#17276](https://github.com/decidim/decidim/pull/17276) +- **decidim-comments**, **decidim-core**: Backport 'Fix comments `loginModal` for non-logged in users' to v0.31 [\#17285](https://github.com/decidim/decidim/pull/17285) +- **decidim-core**, **decidim-meetings**: Backport 'Fix meeting social share image preview not displaying description image' to v0.31 [\#17297](https://github.com/decidim/decidim/pull/17297) +- **decidim-surveys**: Backport 'Fix inverted survey response pagination' to v0.31 [\#17300](https://github.com/decidim/decidim/pull/17300) +- **decidim-meetings**: Backport 'Exclude removed items from total agenda duration calculation' to v0.31 [\#17312](https://github.com/decidim/decidim/pull/17312) +- **decidim-comments**: Backport 'Fix focus when changing the "Sort by" in comments' to v0.31 [\#17327](https://github.com/decidim/decidim/pull/17327) +- **decidim-proposals**: Backport 'Make the proposal official when importing' to v0.31 [\#17303](https://github.com/decidim/decidim/pull/17303) +- **decidim-core**: Backport 'Convert to a proper table the cookies information' to v0.31 [\#17324](https://github.com/decidim/decidim/pull/17324) +- **decidim-assemblies**, **decidim-core**, **decidim-participatory processes**: Backport 'Fix space visibility announcement' to v0.31 [\#17320](https://github.com/decidim/decidim/pull/17320) +- **decidim-core**: Backport 'Fix responsiveness in "Related documents" content block' to v0.31 [\#17334](https://github.com/decidim/decidim/pull/17334) +- **decidim-core**, **decidim-system**: Backport 'Make idempotent the "show password" toggle' to v0.31 [\#17336](https://github.com/decidim/decidim/pull/17336) +- **decidim-system**: Backport 'Add validation for password confirmation mismatch in admin system form' to v0.31 [\#17341](https://github.com/decidim/decidim/pull/17341) +- **decidim-api**, **decidim-core**: Backport 'Ensure JWT secret exists for `devise-jwt`' to v0.31 [\#17346](https://github.com/decidim/decidim/pull/17346) +- **decidim-proposals**: Backport 'Add address in proposals' answer page' to v0.31 [\#17356](https://github.com/decidim/decidim/pull/17356) +- **decidim-core**, **decidim-meetings**: Backport 'Fix the focus guard in the "QR code" modal' to v0.31 [\#17366](https://github.com/decidim/decidim/pull/17366) +- **decidim-core**: Backport 'Fix email update order for converting groups to user' to v0.31 [\#17368](https://github.com/decidim/decidim/pull/17368) +- **decidim-core**, **decidim-participatory processes**: Backport 'Show elements on footer with accordion on mobile viewports ' to v0.31 [\#17381](https://github.com/decidim/decidim/pull/17381) +- **decidim-core**, **decidim-generators**: Backport 'Pin rack-proxy to a version compatible with shakapacker' to v0.31 [\#17375](https://github.com/decidim/decidim/pull/17375) +- **decidim-core**: Backport 'Add the `aria-expanded="false"` attribute when loading the Dropdowns' to v0.31 [\#17378](https://github.com/decidim/decidim/pull/17378) +- **decidim-core**: Backport 'Add maps controls ('Zoom in/Zoom out') to i18n' to v0.31 [\#17377](https://github.com/decidim/decidim/pull/17377) +- **decidim-budgets**, **decidim-core**, **decidim-elections**, **decidim-initiatives**, **decidim-proposals**: Backport 'Fix flaky specs on edit attachments examples' to v0.31 [\#17318](https://github.com/decidim/decidim/pull/17318) +- **decidim-core**: Backport 'Fix translation issue in maps' to v0.31 [\#17392](https://github.com/decidim/decidim/pull/17392) + +### Removed + +Nothing. + +### Developer improvements + +Nothing. + +### Internal + +- **decidim-core**: Backport 'Fix translation issue in maps' to v0.31 [\#17392](https://github.com/decidim/decidim/pull/17392) + +## [0.31.6](https://github.com/decidim/decidim/tree/0.31.6) + +### Added + +- **decidim-verifications**: Backport 'Execute authorization revocation in the background' to v0.31 [\#16806](https://github.com/decidim/decidim/pull/16806) +- **decidim-system**: Backport 'Fix system organization form (short name update and only one locale)' to v0.31 [\#17144](https://github.com/decidim/decidim/pull/17144) + +### Changed + +Nothing. + +### Fixed + +- **decidim-admin**, **decidim-core**: Backport 'Fix spacing in content block settings forms' to v0.31 [\#16780](https://github.com/decidim/decidim/pull/16780) +- **decidim-verifications**: Backport 'Execute authorization revocation in the background' to v0.31 [\#16806](https://github.com/decidim/decidim/pull/16806) +- **decidim-core**: Backport 'Fix browser freeze when editing filters with many taxonomy items' to v0.31 [\#16804](https://github.com/decidim/decidim/pull/16804) +- **decidim-admin**: Backport 'Fix flaky admin manages newsletters specs' to v0.31 [\#16815](https://github.com/decidim/decidim/pull/16815) +- **decidim-forms**, **decidim-surveys**: Backport 'Fix modify responses on survey' to v0.31 [\#16809](https://github.com/decidim/decidim/pull/16809) +- **decidim-core**: Backport 'Add default order to UserEntityList API function' to v0.31 [\#16839](https://github.com/decidim/decidim/pull/16839) +- **decidim-core**: Backport 'Fix image upload HTML validation errors' to v0.31 [\#16849](https://github.com/decidim/decidim/pull/16849) +- **decidim-elections**: Backport 'Display description richtext in elections questions' body' to v0.31 [\#16866](https://github.com/decidim/decidim/pull/16866) +- **decidim-core**: Backport 'Fix floating help with the access modes alert on mobile' to v0.31 [\#16871](https://github.com/decidim/decidim/pull/16871) +- **decidim-assemblies**, **decidim-conferences**, **decidim-core**, **decidim-dev**, **decidim-participatory processes**, **decidim-system**: Backport 'Fix `ActiveStorage::FileNotFoundError` in specs' to v0.31 [\#16863](https://github.com/decidim/decidim/pull/16863) +- **decidim-budgets**: Backport 'Vote button shows budget projects when user is logged out' to v0.31 [\#16870](https://github.com/decidim/decidim/pull/16870) +- **decidim-budgets**, **decidim-proposals**: Backport 'Fix blank state select import on budgets & proposal component' to v0.31 [\#16874](https://github.com/decidim/decidim/pull/16874) +- **decidim-blogs**, **decidim-collaborative_texts**, **decidim-core**, **decidim-debates**, **decidim-meetings**, **decidim-proposals**: Backport 'Fix role menu/presentation on action buttons' to v0.31 [\#16878](https://github.com/decidim/decidim/pull/16878) +- **decidim-comments**, **decidim-core**, **decidim-forms**, **decidim-meetings**, **decidim-templates**: Backport 'Fix Toggle Stimulus controller usage' to v0.31 [\#16868](https://github.com/decidim/decidim/pull/16868) +- **decidim-admin**: Backport 'Check for existing user in "block user" form' to v0.31 [\#16901](https://github.com/decidim/decidim/pull/16901) +- **decidim-admin**: Backport 'Check for existing user in "show email" form' to v0.31 [\#16905](https://github.com/decidim/decidim/pull/16905) +- Backport 'Parametrize accessibility validator version' to v0.31 [\#16915](https://github.com/decidim/decidim/pull/16915) +- **decidim-pages**: Backport 'Fix the pages component duplicate/copy hook name' to v0.31 [\#16921](https://github.com/decidim/decidim/pull/16921) +- **decidim-blogs**: Backport 'Fix blogs `:comments_count` stat returning post count' to v0.31 [\#16923](https://github.com/decidim/decidim/pull/16923) +- **decidim-assemblies**, **decidim-pages**, **decidim-participatory processes**: Backport 'Drop the "Duplicate landing page content blocks" from Duplicate Spaces forms' to v0.31 [\#16939](https://github.com/decidim/decidim/pull/16939) +- **decidim-accountability**, **decidim-blogs**, **decidim-budgets**, **decidim-comments**, **decidim-core**, **decidim-debates**: Backport 'Fix comments count in statistics' to v0.31 [\#16945](https://github.com/decidim/decidim/pull/16945) +- **decidim-accountability**, **decidim-admin**, **decidim-assemblies**, **decidim-blogs**, **decidim-budgets**, **decidim-collaborative_texts**, **decidim-conferences**, **decidim-debates**, **decidim-elections**, **decidim-initiatives**, **decidim-meetings**, **decidim-participatory processes**, **decidim-proposals**, **decidim-verifications**: Backport 'Open the actions' disabled button tooltip to the left' to v0.31 [\#16950](https://github.com/decidim/decidim/pull/16950) +- **decidim-core**: Backport 'Fix unconditionally service workers inclusion in development' to v0.31 [\#16956](https://github.com/decidim/decidim/pull/16956) +- **decidim-admin**, **decidim-assemblies**, **decidim-conferences**, **decidim-core**, **decidim-design**, **decidim-elections**, **decidim-initiatives**, **decidim-meetings**, **decidim-participatory processes**, **decidim-system**: Backport 'Fix add missing landmark roles for accessibility' to v0.31 [\#16963](https://github.com/decidim/decidim/pull/16963) +- **decidim-proposals**: Backport 'Show number of votes in transparent space' to v0.31 [\#16975](https://github.com/decidim/decidim/pull/16975) +- **decidim-meetings**: Backport 'Fix exception when user is already invited in meetings' to v0.31 [\#16987](https://github.com/decidim/decidim/pull/16987) +- **decidim-elections**: Backport 'Prevent start date validation on manual start when editing published elections' to v0.31 [\#16998](https://github.com/decidim/decidim/pull/16998) +- **decidim-core**: Backport 'Fix content renderers with DOM-aware replacement to respect HTML context' to v0.31 [\#16996](https://github.com/decidim/decidim/pull/16996) +- **decidim-admin**, **decidim-core**, **decidim-meetings**, **decidim-proposals**: Backport 'Fix column sorting in admin tables' to v0.31 [\#16979](https://github.com/decidim/decidim/pull/16979) +- **decidim-core**: Backport 'Fix locale setup in devise controllers' to v0.31 [\#16973](https://github.com/decidim/decidim/pull/16973) +- **decidim-proposals**: Backport 'Fix eslint plugin import usage' to v0.31 [\#16967](https://github.com/decidim/decidim/pull/16967) +- **decidim-core**: Backport 'Fix double-escaping on mobile menu navigation links' to v0.31 [\#17008](https://github.com/decidim/decidim/pull/17008) +- **decidim-assemblies**, **decidim-participatory processes**: Backport 'Make import of assemblies/processes attachments more robust' to v0.31 [\#17015](https://github.com/decidim/decidim/pull/17015) +- **decidim-assemblies**, **decidim-conferences**, **decidim-participatory processes**: Backport 'Fix unique constraint in space commands caused by deleted spaces' to v0.31 [\#17006](https://github.com/decidim/decidim/pull/17006) +- **decidim-admin**, **decidim-comments**, **decidim-core**: Backport 'Replace tribute javascript with resource mention UI' to v0.31 [\#17021](https://github.com/decidim/decidim/pull/17021) +- **decidim-admin**: Backport 'Check for existing user in new officialization form' to v0.31 [\#17030](https://github.com/decidim/decidim/pull/17030) +- **decidim-core**: Backport 'Fix crash on login/logout with unsupported image file extensions' to v0.31 [\#17037](https://github.com/decidim/decidim/pull/17037) +- **decidim-generators**: Backport 'Fix flaky on generators bundler (multijson)' to v0.31 [\#17039](https://github.com/decidim/decidim/pull/17039) +- **decidim-core**: Backport 'Fix search indexing for unexisting locales' to v0.31 [\#17046](https://github.com/decidim/decidim/pull/17046) +- **decidim-surveys**: Backport 'Fix census permissions in surveys' to v0.31 [\#17053](https://github.com/decidim/decidim/pull/17053) +- **decidim-blogs**: Backport 'Fix exception on post new page as a visitor' to v0.31 [\#17059](https://github.com/decidim/decidim/pull/17059) +- **decidim-initiatives**: Backport 'Fix exception in intiatives when `has_authorship?` receives a nil argument for u' to v0.31 [\#17067](https://github.com/decidim/decidim/pull/17067) +- **decidim-blogs**, **decidim-debates**, **decidim-initiatives**, **decidim-meetings**, **decidim-proposals**: Backport 'Fix create meeting display button' to v0.31 [\#17056](https://github.com/decidim/decidim/pull/17056) +- **decidim-core**: Backport 'Fix conversations multiple mentions UI' to v0.31 [\#17079](https://github.com/decidim/decidim/pull/17079) +- **decidim-core**: Backport 'Fix performance when sending digest notitfications' to v0.31 [\#17076](https://github.com/decidim/decidim/pull/17076) +- **decidim-core**: Backport 'Show errors in new conversation' to v0.31 [\#17086](https://github.com/decidim/decidim/pull/17086) +- **decidim-admin**: Backport 'Improve taxonomy filter update performance' to v0.31 [\#17083](https://github.com/decidim/decidim/pull/17083) +- **decidim-proposals**: Backport 'Fix rendering mentions for Proposals' answer page' to v0.31 [\#17092](https://github.com/decidim/decidim/pull/17092) +- **decidim-templates**: Backport 'Fix flaky spec at admin adds display condition on template' to v0.31 [\#17097](https://github.com/decidim/decidim/pull/17097) +- **decidim-accountability**, **decidim-admin**, **decidim-blogs**, **decidim-budgets**, **decidim-core**, **decidim-debates**, **decidim-meetings**, **decidim-proposals**: Backport 'Change setting "comments max length" for "max characters per comment"' to v0.31 [\#17103](https://github.com/decidim/decidim/pull/17103) +- **decidim-accountability**: Backport 'Do not show the status select in the result form if no statuses' to v0.31 [\#17129](https://github.com/decidim/decidim/pull/17129) +- **decidim-accountability**: Backport 'Add validation in status' progress field' to v0.31 [\#17127](https://github.com/decidim/decidim/pull/17127) +- **decidim-forms**: Backport 'Fix data migration for answers to responses change' to v0.31 [\#17141](https://github.com/decidim/decidim/pull/17141) +- **decidim-system**: Backport 'Fix system organization form (short name update and only one locale)' to v0.31 [\#17144](https://github.com/decidim/decidim/pull/17144) +- Backport 'Remove check-spelling github workflow' to v0.31 [\#17152](https://github.com/decidim/decidim/pull/17152) +- **decidim-core**: Backport 'Fix cache invalidation bug in highlighted spaces content blocks' to v0.31 [\#17171](https://github.com/decidim/decidim/pull/17171) +- **decidim-verifications**: Backport 'Fix flaky spec at `authorizations_spec.rb`' to v0.31 [\#17179](https://github.com/decidim/decidim/pull/17179) +- **decidim-core**, **decidim-proposals**: Backport 'Add visual feedback for the "Use my current location" feature' to v0.31 [\#17165](https://github.com/decidim/decidim/pull/17165) +- **decidim-admin**, **decidim-ai**, **decidim-blogs**, **decidim-budgets**, **decidim-core**, **decidim-debates**, **decidim-dev**, **decidim-elections**, **decidim-forms**, **decidim-initiatives**, **decidim-meetings**, **decidim-proposals**, **decidim-surveys**: Backport 'Fix editing components with attachments' to v0.31 [\#17146](https://github.com/decidim/decidim/pull/17146) +- **decidim-admin**, **decidim-core**, **decidim-dev**, **decidim-participatory processes**: Backport 'Fix file size validator in content block settings' to v0.31 [\#16970](https://github.com/decidim/decidim/pull/16970) +- **decidim-admin**, **decidim-core**, **decidim-dev**: Backport 'Make the fields at the "highlighted content banner" content block required' to v0.31 [\#17125](https://github.com/decidim/decidim/pull/17125) +- **decidim-admin**, **decidim-debates**: Backport 'Show debates' comments visualization locked on the form' to v0.31 [\#17174](https://github.com/decidim/decidim/pull/17174) +- Backport 'Bump ruby from 3.3.0 to 3.3.4 in manual.adoc' to v0.31 [\#17200](https://github.com/decidim/decidim/pull/17200) +- **decidim-accountability**, **decidim-admin**, **decidim-blogs**, **decidim-budgets**, **decidim-collaborative_texts**, **decidim-core**, **decidim-debates**, **decidim-meetings**, **decidim-pages**, **decidim-proposals**, **decidim-surveys**: Backport 'Fix flaky spec at `admin_manages_participatory_process_components_spec.rb`' to v0.31 [\#17183](https://github.com/decidim/decidim/pull/17183) +- Backport 'Fix typos in docs' to v0.31 [\#17224](https://github.com/decidim/decidim/pull/17224) +- **decidim-core**: Backport 'Fix delete user email notification' to v0.31 [\#17226](https://github.com/decidim/decidim/pull/17226) +- **decidim-core**: Backport 'Fix flaky specs on `authentication_spec.rb`' to v0.31 [\#17227](https://github.com/decidim/decidim/pull/17227) + +### Removed + +Nothing. + +### Developer improvements + +Nothing. + +### Internal + +- Add devcontainer configuration and scripts for v0.31 [\#16743](https://github.com/decidim/decidim/pull/16743) +- **decidim-admin**, **decidim-comments**, **decidim-core**: Backport 'Replace tribute javascript with resource mention UI' to v0.31 [\#17021](https://github.com/decidim/decidim/pull/17021) +- Add missing imagemagick dependency to devcontainer (v0.31) [\#17123](https://github.com/decidim/decidim/pull/17123) +- Backport 'Remove check-spelling github workflow' to v0.31 [\#17152](https://github.com/decidim/decidim/pull/17152) + +## [0.31.5](https://github.com/decidim/decidim/tree/0.31.5) + +### Added + +Nothing. + +### Changed + +Nothing. + +### Fixed + +- **decidim-system**: Backport 'Fix one word hostnames for development' to v0.31 [\#16684](https://github.com/decidim/decidim/pull/16684) +- **decidim-core**: Backport 'Fix flaky spec on `category.erb`' to v0.31 [\#16707](https://github.com/decidim/decidim/pull/16707) +- **decidim-verifications**: Backport 'Enforce permission check on admins' CSV census' to v0.31 [\#16692](https://github.com/decidim/decidim/pull/16692) +- **decidim-verifications**: Backport 'Fix multitenant access bug on ID documents verification' to v0.31 [\#16694](https://github.com/decidim/decidim/pull/16694) +- **decidim-demographics**, **decidim-elections**, **decidim-forms**, **decidim-meetings**, **decidim-surveys**: Backport 'Improve permissions checks in demographics' questionnaire' to v0.31 [\#16682](https://github.com/decidim/decidim/pull/16682) +- **decidim-admin**, **decidim-conferences**, **decidim-meetings**: Backport 'Refactor autocomplete to use the GraphQL API endpoint' to v0.31 [\#16705](https://github.com/decidim/decidim/pull/16705) +- **decidim-core**: Backport 'Fix push notifications configuration and registration' to v0.31 [\#16711](https://github.com/decidim/decidim/pull/16711) +- **decidim-core**: Backport 'Sanitize "static page" content blocks and HTML content block' to v0.31 [\#16715](https://github.com/decidim/decidim/pull/16715) +- Backport 'Pin workbox-webpack-plugin to v7.3' to v0.31 [\#16745](https://github.com/decidim/decidim/pull/16745) +- **decidim-generators**: Backport 'Fix spec for full app generator spec' to v0.31 [\#16749](https://github.com/decidim/decidim/pull/16749) +- **decidim-api**: Backport 'Prevent using JWT against other organizations' to v0.31 [\#16723](https://github.com/decidim/decidim/pull/16723) +- **decidim-core**: Backport 'Check that the endpoint is supported on Web Push notifications' to v0.31 [\#16747](https://github.com/decidim/decidim/pull/16747) +- **decidim-assemblies**, **decidim-core**, **decidim-participatory processes**, **decidim-verifications**: Backport 'Introduce PrivateDownload logic for some downloads' to v0.31 [\#16751](https://github.com/decidim/decidim/pull/16751) +- Fix spellchecker in `release/0.31-stable` [\#16709](https://github.com/decidim/decidim/pull/16709) +- **decidim-verifications**: Backport 'Enforce permission check on admins' CSV census records' to v0.31 [\#16758](https://github.com/decidim/decidim/pull/16758) +- **decidim-api**: Backport 'Fix organization access check for logged in API user' to v0.31 [\#16760](https://github.com/decidim/decidim/pull/16760) + +### Removed + +Nothing. + +### Developer improvements + +Nothing. + +### Internal + +- Clean-up the releases notes after v0.31.4 publication [\#16647](https://github.com/decidim/decidim/pull/16647) +- Backport 'Pin workbox-webpack-plugin to v7.3' to v0.31 [\#16745](https://github.com/decidim/decidim/pull/16745) + ## [0.31.4](https://github.com/decidim/decidim/tree/0.31.4) ### Added diff --git a/Gemfile.lock b/Gemfile.lock index ffc2c02b88804..30123973339ac 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1,62 +1,62 @@ PATH remote: . specs: - decidim (0.31.4) - decidim-accountability (= 0.31.4) - decidim-admin (= 0.31.4) - decidim-api (= 0.31.4) - decidim-assemblies (= 0.31.4) - decidim-blogs (= 0.31.4) - decidim-budgets (= 0.31.4) - decidim-comments (= 0.31.4) - decidim-core (= 0.31.4) - decidim-debates (= 0.31.4) - decidim-forms (= 0.31.4) - decidim-generators (= 0.31.4) - decidim-meetings (= 0.31.4) - decidim-pages (= 0.31.4) - decidim-participatory_processes (= 0.31.4) - decidim-proposals (= 0.31.4) - decidim-sortitions (= 0.31.4) - decidim-surveys (= 0.31.4) - decidim-system (= 0.31.4) - decidim-verifications (= 0.31.4) - decidim-accountability (0.31.4) - decidim-comments (= 0.31.4) - decidim-core (= 0.31.4) - decidim-admin (0.31.4) + decidim (0.31.7) + decidim-accountability (= 0.31.7) + decidim-admin (= 0.31.7) + decidim-api (= 0.31.7) + decidim-assemblies (= 0.31.7) + decidim-blogs (= 0.31.7) + decidim-budgets (= 0.31.7) + decidim-comments (= 0.31.7) + decidim-core (= 0.31.7) + decidim-debates (= 0.31.7) + decidim-forms (= 0.31.7) + decidim-generators (= 0.31.7) + decidim-meetings (= 0.31.7) + decidim-pages (= 0.31.7) + decidim-participatory_processes (= 0.31.7) + decidim-proposals (= 0.31.7) + decidim-sortitions (= 0.31.7) + decidim-surveys (= 0.31.7) + decidim-system (= 0.31.7) + decidim-verifications (= 0.31.7) + decidim-accountability (0.31.7) + decidim-comments (= 0.31.7) + decidim-core (= 0.31.7) + decidim-admin (0.31.7) active_link_to (~> 1.0) - decidim-core (= 0.31.4) + decidim-core (= 0.31.7) devise (~> 4.7) devise-i18n (~> 1.2) devise_invitable (~> 2.0, >= 2.0.9) - decidim-ai (0.31.4) + decidim-ai (0.31.7) classifier-reborn (~> 2.3.0) - decidim-core (= 0.31.4) - decidim-api (0.31.4) - decidim-core (= 0.31.4) + decidim-core (= 0.31.7) + decidim-api (0.31.7) + decidim-core (= 0.31.7) devise-jwt (~> 0.12.1) graphql (~> 2.4.0, >= 2.4.17) graphql-docs (~> 5.0) rack-cors (~> 1.0) - decidim-assemblies (0.31.4) - decidim-core (= 0.31.4) - decidim-blogs (0.31.4) - decidim-admin (= 0.31.4) - decidim-comments (= 0.31.4) - decidim-core (= 0.31.4) - decidim-budgets (0.31.4) - decidim-comments (= 0.31.4) - decidim-core (= 0.31.4) - decidim-collaborative_texts (0.31.4) - decidim-core (= 0.31.4) - decidim-comments (0.31.4) - decidim-core (= 0.31.4) + decidim-assemblies (0.31.7) + decidim-core (= 0.31.7) + decidim-blogs (0.31.7) + decidim-admin (= 0.31.7) + decidim-comments (= 0.31.7) + decidim-core (= 0.31.7) + decidim-budgets (0.31.7) + decidim-comments (= 0.31.7) + decidim-core (= 0.31.7) + decidim-collaborative_texts (0.31.7) + decidim-core (= 0.31.7) + decidim-comments (0.31.7) + decidim-core (= 0.31.7) redcarpet (~> 3.5, >= 3.5.1) - decidim-conferences (0.31.4) - decidim-core (= 0.31.4) - decidim-meetings (= 0.31.4) - decidim-core (0.31.4) + decidim-conferences (0.31.7) + decidim-core (= 0.31.7) + decidim-meetings (= 0.31.7) + decidim-core (0.31.7) active_link_to (~> 1.0) acts_as_list (~> 1.0) batch-loader (~> 2.0) @@ -99,6 +99,7 @@ PATH premailer-rails (~> 1.10) rack (~> 2.2, >= 2.2.8.1) rack-attack (~> 6.0) + rack-proxy (~> 0.8.3, < 1.0) rails (~> 7.2.0, >= 7.2.2.2) rails-i18n (~> 7.0) ransack (~> 4.2.0) @@ -111,24 +112,24 @@ PATH valid_email2 (~> 7.0) web-push (~> 3.0) wisper (~> 3.0) - decidim-debates (0.31.4) - decidim-comments (= 0.31.4) - decidim-core (= 0.31.4) - decidim-demographics (0.31.4) - decidim-core (= 0.31.4) - decidim-forms (= 0.31.4) - decidim-design (0.31.4) - decidim-core (= 0.31.4) - decidim-dev (0.31.4) + decidim-debates (0.31.7) + decidim-comments (= 0.31.7) + decidim-core (= 0.31.7) + decidim-demographics (0.31.7) + decidim-core (= 0.31.7) + decidim-forms (= 0.31.7) + decidim-design (0.31.7) + decidim-core (= 0.31.7) + decidim-dev (0.31.7) bullet (~> 8.0.0) byebug (~> 11.0) capybara (~> 3.39) - decidim-admin (= 0.31.4) - decidim-api (= 0.31.4) - decidim-comments (= 0.31.4) - decidim-core (= 0.31.4) - decidim-generators (= 0.31.4) - decidim-verifications (= 0.31.4) + decidim-admin (= 0.31.7) + decidim-api (= 0.31.7) + decidim-comments (= 0.31.7) + decidim-core (= 0.31.7) + decidim-generators (= 0.31.7) + decidim-verifications (= 0.31.7) erb_lint (~> 0.8.0) factory_bot_rails (~> 6.2) faker (~> 3.2) @@ -161,118 +162,120 @@ PATH w3c_rspec_validators (~> 0.3.0) webmock (~> 3.18) wisper-rspec (~> 1.0) - decidim-elections (0.31.4) - decidim-admin (= 0.31.4) - decidim-core (= 0.31.4) - decidim-forms (= 0.31.4) - decidim-forms (0.31.4) - decidim-core (= 0.31.4) - decidim-generators (0.31.4) - decidim-core (= 0.31.4) - decidim-initiatives (0.31.4) - decidim-admin (= 0.31.4) - decidim-comments (= 0.31.4) - decidim-core (= 0.31.4) - decidim-verifications (= 0.31.4) - decidim-meetings (0.31.4) - decidim-core (= 0.31.4) - decidim-forms (= 0.31.4) + decidim-elections (0.31.7) + decidim-admin (= 0.31.7) + decidim-core (= 0.31.7) + decidim-forms (= 0.31.7) + decidim-forms (0.31.7) + decidim-core (= 0.31.7) + decidim-generators (0.31.7) + decidim-core (= 0.31.7) + decidim-initiatives (0.31.7) + decidim-admin (= 0.31.7) + decidim-comments (= 0.31.7) + decidim-core (= 0.31.7) + decidim-verifications (= 0.31.7) + decidim-meetings (0.31.7) + decidim-core (= 0.31.7) + decidim-forms (= 0.31.7) icalendar (~> 2.5) - decidim-pages (0.31.4) - decidim-core (= 0.31.4) - decidim-participatory_processes (0.31.4) - decidim-core (= 0.31.4) - decidim-proposals (0.31.4) - decidim-comments (= 0.31.4) - decidim-core (= 0.31.4) + decidim-pages (0.31.7) + decidim-core (= 0.31.7) + decidim-participatory_processes (0.31.7) + decidim-core (= 0.31.7) + decidim-proposals (0.31.7) + decidim-comments (= 0.31.7) + decidim-core (= 0.31.7) doc2text (~> 0.4.0, >= 0.4.8) redcarpet (~> 3.5, >= 3.5.1) - decidim-sortitions (0.31.4) - decidim-admin (= 0.31.4) - decidim-comments (= 0.31.4) - decidim-core (= 0.31.4) - decidim-proposals (= 0.31.4) - decidim-surveys (0.31.4) - decidim-core (= 0.31.4) - decidim-forms (= 0.31.4) - decidim-system (0.31.4) + decidim-sortitions (0.31.7) + decidim-admin (= 0.31.7) + decidim-comments (= 0.31.7) + decidim-core (= 0.31.7) + decidim-proposals (= 0.31.7) + decidim-surveys (0.31.7) + decidim-core (= 0.31.7) + decidim-forms (= 0.31.7) + decidim-system (0.31.7) active_link_to (~> 1.0) - decidim-core (= 0.31.4) + decidim-core (= 0.31.7) devise (~> 4.7) devise-i18n (~> 1.2) devise_invitable (~> 2.0, >= 2.0.9) - decidim-templates (0.31.4) - decidim-core (= 0.31.4) - decidim-forms (= 0.31.4) - decidim-verifications (0.31.4) - decidim-core (= 0.31.4) + decidim-templates (0.31.7) + decidim-core (= 0.31.7) + decidim-forms (= 0.31.7) + decidim-verifications (0.31.7) + decidim-core (= 0.31.7) GEM remote: https://rubygems.org/ specs: - actioncable (7.2.2.2) - actionpack (= 7.2.2.2) - activesupport (= 7.2.2.2) + actioncable (7.2.3) + actionpack (= 7.2.3) + activesupport (= 7.2.3) nio4r (~> 2.0) websocket-driver (>= 0.6.1) zeitwerk (~> 2.6) - actionmailbox (7.2.2.2) - actionpack (= 7.2.2.2) - activejob (= 7.2.2.2) - activerecord (= 7.2.2.2) - activestorage (= 7.2.2.2) - activesupport (= 7.2.2.2) + actionmailbox (7.2.3) + actionpack (= 7.2.3) + activejob (= 7.2.3) + activerecord (= 7.2.3) + activestorage (= 7.2.3) + activesupport (= 7.2.3) mail (>= 2.8.0) - actionmailer (7.2.2.2) - actionpack (= 7.2.2.2) - actionview (= 7.2.2.2) - activejob (= 7.2.2.2) - activesupport (= 7.2.2.2) + actionmailer (7.2.3) + actionpack (= 7.2.3) + actionview (= 7.2.3) + activejob (= 7.2.3) + activesupport (= 7.2.3) mail (>= 2.8.0) rails-dom-testing (~> 2.2) - actionpack (7.2.2.2) - actionview (= 7.2.2.2) - activesupport (= 7.2.2.2) + actionpack (7.2.3) + actionview (= 7.2.3) + activesupport (= 7.2.3) + cgi nokogiri (>= 1.8.5) racc - rack (>= 2.2.4, < 3.2) + rack (>= 2.2.4, < 3.3) rack-session (>= 1.0.1) rack-test (>= 0.6.3) rails-dom-testing (~> 2.2) rails-html-sanitizer (~> 1.6) useragent (~> 0.16) - actiontext (7.2.2.2) - actionpack (= 7.2.2.2) - activerecord (= 7.2.2.2) - activestorage (= 7.2.2.2) - activesupport (= 7.2.2.2) + actiontext (7.2.3) + actionpack (= 7.2.3) + activerecord (= 7.2.3) + activestorage (= 7.2.3) + activesupport (= 7.2.3) globalid (>= 0.6.0) nokogiri (>= 1.8.5) - actionview (7.2.2.2) - activesupport (= 7.2.2.2) + actionview (7.2.3) + activesupport (= 7.2.3) builder (~> 3.1) + cgi erubi (~> 1.11) rails-dom-testing (~> 2.2) rails-html-sanitizer (~> 1.6) active_link_to (1.0.5) actionpack addressable - activejob (7.2.2.2) - activesupport (= 7.2.2.2) + activejob (7.2.3) + activesupport (= 7.2.3) globalid (>= 0.3.6) - activemodel (7.2.2.2) - activesupport (= 7.2.2.2) - activerecord (7.2.2.2) - activemodel (= 7.2.2.2) - activesupport (= 7.2.2.2) + activemodel (7.2.3) + activesupport (= 7.2.3) + activerecord (7.2.3) + activemodel (= 7.2.3) + activesupport (= 7.2.3) timeout (>= 0.4.0) - activestorage (7.2.2.2) - actionpack (= 7.2.2.2) - activejob (= 7.2.2.2) - activerecord (= 7.2.2.2) - activesupport (= 7.2.2.2) + activestorage (7.2.3) + actionpack (= 7.2.3) + activejob (= 7.2.3) + activerecord (= 7.2.3) + activesupport (= 7.2.3) marcel (~> 1.0) - activesupport (7.2.2.2) + activesupport (7.2.3) base64 benchmark (>= 0.3) bigdecimal @@ -284,28 +287,28 @@ GEM minitest (>= 5.1) securerandom (>= 0.3) tzinfo (~> 2.0, >= 2.0.5) - acts_as_list (1.2.4) + acts_as_list (1.2.6) activerecord (>= 6.1) activesupport (>= 6.1) - addressable (2.8.7) - public_suffix (>= 2.0.2, < 7.0) + addressable (2.8.9) + public_suffix (>= 2.0.2, < 8.0) ast (2.4.3) base64 (0.3.0) - batch-loader (2.0.5) - bcrypt (3.1.20) - benchmark (0.4.1) - better_html (2.1.1) - actionview (>= 6.0) - activesupport (>= 6.0) + batch-loader (2.0.6) + bcrypt (3.1.22) + benchmark (0.5.0) + better_html (2.2.0) + actionview (>= 7.0) + activesupport (>= 7.0) ast (~> 2.0) erubi (~> 1.4) parser (>= 2.4) smart_properties - bigdecimal (3.2.2) + bigdecimal (4.0.1) bindex (0.8.1) - bootsnap (1.18.6) + bootsnap (1.23.0) msgpack (~> 1.2) - brakeman (7.0.2) + brakeman (7.1.2) racc browser (6.2.0) builder (3.3.0) @@ -333,6 +336,7 @@ GEM cells-rails (0.1.6) actionpack (>= 5.0) cells (>= 4.1.6, < 5.0.0) + cgi (0.5.1) charlock_holmes (0.7.9) chartkick (5.1.5) childprocess (5.1.0) @@ -342,20 +346,20 @@ GEM fast-stemmer (~> 1.0) matrix (~> 0.4) cmdparse (3.0.7) - commonmarker (0.23.11) - concurrent-ruby (1.3.5) + commonmarker (0.23.12) + concurrent-ruby (1.3.6) connection_pool (2.5.5) - crack (1.0.0) + crack (1.0.1) bigdecimal rexml crass (1.0.6) - css_parser (1.21.1) + css_parser (2.0.0) addressable csv (3.3.5) data_migrate (11.3.1) activerecord (>= 6.1) railties (>= 6.1) - date (3.4.1) + date (3.5.1) date_validator (0.12.0) activemodel (>= 3) activesupport (>= 3) @@ -368,8 +372,9 @@ GEM railties (>= 4.1.0) responders warden (~> 1.2.3) - devise-i18n (1.12.1) + devise-i18n (1.15.0) devise (>= 4.9.0) + rails-i18n devise-jwt (0.12.1) devise (~> 4.0) warden-jwt_auth (~> 0.10) @@ -382,7 +387,7 @@ GEM nokogiri (>= 1.18.2) rubyzip (~> 2.3.0) docile (1.4.1) - doorkeeper (5.8.2) + doorkeeper (5.9.0) railties (>= 5) doorkeeper-i18n (4.0.1) drb (2.2.3) @@ -392,11 +397,11 @@ GEM dry-configurable (1.3.0) dry-core (~> 1.1) zeitwerk (~> 2.6) - dry-core (1.1.0) + dry-core (1.2.0) concurrent-ruby (~> 1.0) logger zeitwerk (~> 2.6) - erb (5.0.2) + erb (6.0.2) erb_lint (0.8.0) activesupport better_html (>= 2.0.1) @@ -408,26 +413,26 @@ GEM temple erubi (1.13.1) escape_utils (1.3.0) - excon (1.2.8) + excon (1.4.1) logger extended-markdown-filter (0.7.0) html-pipeline (~> 2.9) - factory_bot (6.5.4) + factory_bot (6.5.6) activesupport (>= 6.1.0) - factory_bot_rails (6.4.4) + factory_bot_rails (6.5.1) factory_bot (~> 6.5) - railties (>= 5.0.0) - faker (3.5.3) + railties (>= 6.1.0) + faker (3.6.1) i18n (>= 1.8.11, < 2) - faraday (2.13.4) + faraday (2.14.1) faraday-net_http (>= 2.0, < 3.5) json logger - faraday-net_http (3.4.1) - net-http (>= 0.5.0) + faraday-net_http (3.4.2) + net-http (~> 0.5) fast-stemmer (1.0.2) - ffi (1.17.2-arm64-darwin) - ffi (1.17.2-x86_64-linux-gnu) + ffi (1.17.3-arm64-darwin) + ffi (1.17.3-x86_64-linux-gnu) fiber-storage (1.0.1) file_validators (3.0.0) activemodel (>= 3.2) @@ -437,27 +442,28 @@ GEM excon (~> 1.0) formatador (>= 0.2, < 2.0) mime-types - fog-local (0.8.0) + fog-local (0.9.0) fog-core (>= 1.27, < 3.0) - formatador (1.1.1) + formatador (1.2.3) + reline gemoji (3.0.1) - geocoder (1.8.5) + geocoder (1.8.6) base64 (>= 0.1.0) csv (>= 3.0.0) geom2d (0.4.1) - globalid (1.2.1) + globalid (1.3.0) activesupport (>= 6.1) - google-protobuf (4.29.3-arm64-darwin) + google-protobuf (4.34.0-arm64-darwin) bigdecimal - rake (>= 13) - google-protobuf (4.29.3-x86_64-linux) + rake (~> 13.3) + google-protobuf (4.34.0-x86_64-linux-gnu) bigdecimal - rake (>= 13) + rake (~> 13.3) graphql (2.4.17) base64 fiber-storage logger - graphql-docs (5.1.0) + graphql-docs (5.2.0) commonmarker (~> 0.23, >= 0.23.6) escape_utils (~> 1.2) extended-markdown-filter (~> 0.4) @@ -467,8 +473,9 @@ GEM logger (~> 1.6) ostruct (~> 0.6) sass-embedded (~> 1.58) - hashdiff (1.1.2) - hashie (5.0.0) + hashdiff (1.2.1) + hashie (5.1.0) + logger hexapdf (1.1.1) cmdparse (~> 3.0, >= 3.0.3) geom2d (~> 0.4, >= 0.4.1) @@ -479,36 +486,40 @@ GEM html-pipeline (2.14.3) activesupport (>= 2) nokogiri (>= 1.4) - htmlentities (4.3.4) - i18n (1.14.7) + htmlentities (4.4.2) + i18n (1.14.8) concurrent-ruby (~> 1.0) - i18n-tasks (1.0.15) + i18n-tasks (1.1.2) activesupport (>= 4.0.2) ast (>= 2.1.0) erubi - highline (>= 2.0.0) + highline (>= 3.0.0) i18n parser (>= 3.2.2.1) + prism rails-i18n rainbow (>= 2.2.2, < 4.0) ruby-progressbar (~> 1.8, >= 1.8.1) terminal-table (>= 1.5.1) - icalendar (2.10.3) + icalendar (2.12.1) + base64 ice_cube (~> 0.16) + logger ostruct ice_cube (0.17.0) - image_processing (1.13.0) - mini_magick (>= 4.9.5, < 5) + image_processing (1.14.0) + mini_magick (>= 4.9.5, < 6) ruby-vips (>= 2.0.17, < 3) invisible_captcha (0.13.0) rails (>= 3.2.0) - io-console (0.8.1) - irb (1.15.2) + io-console (0.8.2) + irb (1.17.0) pp (>= 0.6.0) + prism (>= 1.3.0) rdoc (>= 4.0.0) reline (>= 0.4.2) - json (2.13.1) - jwt (2.10.2) + json (2.19.2) + jwt (3.1.2) base64 kaminari (1.2.2) activesupport (>= 4.1.0) @@ -523,9 +534,10 @@ GEM kaminari-core (= 1.2.2) kaminari-core (1.2.2) language_server-protocol (3.17.0.5) - launchy (3.0.1) + launchy (3.1.1) addressable (~> 2.8) childprocess (~> 5.0) + logger (~> 1.6) letter_opener (1.10.0) launchy (>= 2.2, < 4) letter_opener_web (2.0.0) @@ -534,33 +546,37 @@ GEM railties (>= 5.2) rexml lint_roller (1.1.0) - listen (3.9.0) + listen (3.10.0) + logger rb-fsevent (~> 0.10, >= 0.10.3) rb-inotify (~> 0.9, >= 0.9.10) logger (1.7.0) - loofah (2.24.1) + loofah (2.25.1) crass (~> 1.0.2) nokogiri (>= 1.12.0) - mail (2.8.1) + mail (2.9.0) + logger mini_mime (>= 0.1.1) net-imap net-pop net-smtp - marcel (1.0.4) + marcel (1.1.0) matrix (0.4.3) - mime-types (3.6.0) + mime-types (3.7.0) logger - mime-types-data (~> 3.2015) - mime-types-data (3.2025.0722) + mime-types-data (~> 3.2025, >= 3.2025.0507) + mime-types-data (3.2026.0317) mini_magick (4.13.2) mini_mime (1.1.5) - minitest (5.25.5) + minitest (6.0.2) + drb (~> 2.0) + prism (~> 1.5) msgpack (1.8.0) - multi_xml (0.7.2) - bigdecimal (~> 3.1) - net-http (0.6.0) - uri - net-imap (0.5.10) + multi_xml (0.8.1) + bigdecimal (>= 3.1, < 5) + net-http (0.9.1) + uri (>= 0.11.1) + net-imap (0.6.3) date net-protocol net-pop (0.1.2) @@ -569,32 +585,34 @@ GEM timeout net-smtp (0.5.1) net-protocol - nio4r (2.7.4) - nokogiri (1.18.9-arm64-darwin) + nio4r (2.7.5) + nokogiri (1.19.2-arm64-darwin) racc (~> 1.4) - nokogiri (1.18.9-x86_64-linux-gnu) + nokogiri (1.19.2-x86_64-linux-gnu) racc (~> 1.4) - oauth (1.1.0) - oauth-tty (~> 1.0, >= 1.0.1) + oauth (1.1.3) + base64 (~> 0.1) + oauth-tty (~> 1.0, >= 1.0.6) snaky_hash (~> 2.0) - version_gem (~> 1.1) - oauth-tty (1.0.5) - version_gem (~> 1.1, >= 1.1.1) - oauth2 (2.0.12) + version_gem (~> 1.1, >= 1.1.9) + oauth-tty (1.0.6) + version_gem (~> 1.1, >= 1.1.9) + oauth2 (2.0.18) faraday (>= 0.17.3, < 4.0) jwt (>= 1.0, < 4.0) logger (~> 1.2) multi_xml (~> 0.5) rack (>= 1.2, < 4) snaky_hash (~> 2.0, >= 2.0.3) - version_gem (>= 1.1.8, < 3) - omniauth (2.1.3) + version_gem (~> 1.1, >= 1.1.9) + omniauth (2.1.4) hashie (>= 3.4.6) + logger rack (>= 2.2.3) rack-protection omniauth-facebook (5.0.0) omniauth-oauth2 (~> 1.2) - omniauth-google-oauth2 (1.2.1) + omniauth-google-oauth2 (1.2.2) jwt (>= 2.9.2) oauth2 (~> 2.0) omniauth (~> 2.0) @@ -603,8 +621,8 @@ GEM oauth omniauth (>= 1.0, < 3) rack (>= 1.6.2, < 4) - omniauth-oauth2 (1.8.0) - oauth2 (>= 1.4, < 3) + omniauth-oauth2 (1.9.0) + oauth2 (>= 2.0.2, < 3) omniauth (~> 2.0) omniauth-rails_csrf_protection (1.0.2) actionpack (>= 4.2) @@ -612,28 +630,28 @@ GEM omniauth-twitter (1.4.0) omniauth-oauth (~> 1.1) rack - openssl (3.3.0) + openssl (4.0.1) orm_adapter (0.5.0) ostruct (0.6.3) - package_json (0.1.0) + package_json (0.2.0) paper_trail (16.0.0) activerecord (>= 6.1) request_store (~> 1.4) parallel (1.27.0) - parallel_tests (4.9.0) + parallel_tests (4.10.1) parallel paranoia (3.0.1) activerecord (>= 6, < 8.1) - parser (3.3.9.0) + parser (3.3.10.2) ast (~> 2.4.1) racc pg (1.5.9) pg_search (2.3.7) activerecord (>= 6.1) activesupport (>= 6.1) - pp (0.6.2) + pp (0.6.3) prettyprint - premailer (1.27.0) + premailer (1.29.0) addressable css_parser (>= 1.19.0) htmlentities (>= 4.0.0) @@ -642,23 +660,23 @@ GEM net-smtp premailer (~> 1.7, >= 1.7.9) prettyprint (0.2.0) - prism (1.4.0) - psych (5.2.6) + prism (1.9.0) + psych (5.3.1) date stringio - public_suffix (6.0.2) - puma (6.5.0) + public_suffix (7.0.5) + puma (6.6.1) nio4r (~> 2.0) racc (1.8.1) - rack (2.2.17) - rack-attack (6.7.0) + rack (2.2.22) + rack-attack (6.8.0) rack (>= 1.0, < 4) rack-cors (1.1.1) rack (>= 2.0.0) rack-protection (3.2.0) base64 (>= 0.1.0) rack (~> 2.2, >= 2.2.4) - rack-proxy (0.7.7) + rack-proxy (0.8.3) rack rack-session (1.0.2) rack (< 3) @@ -667,20 +685,20 @@ GEM rackup (1.0.1) rack (< 3) webrick - rails (7.2.2.2) - actioncable (= 7.2.2.2) - actionmailbox (= 7.2.2.2) - actionmailer (= 7.2.2.2) - actionpack (= 7.2.2.2) - actiontext (= 7.2.2.2) - actionview (= 7.2.2.2) - activejob (= 7.2.2.2) - activemodel (= 7.2.2.2) - activerecord (= 7.2.2.2) - activestorage (= 7.2.2.2) - activesupport (= 7.2.2.2) + rails (7.2.3) + actioncable (= 7.2.3) + actionmailbox (= 7.2.3) + actionmailer (= 7.2.3) + actionpack (= 7.2.3) + actiontext (= 7.2.3) + actionview (= 7.2.3) + activejob (= 7.2.3) + activemodel (= 7.2.3) + activerecord (= 7.2.3) + activestorage (= 7.2.3) + activesupport (= 7.2.3) bundler (>= 1.15.0) - railties (= 7.2.2.2) + railties (= 7.2.3) rails-controller-testing (1.0.5) actionpack (>= 5.0.1.rc1) actionview (>= 5.0.1.rc1) @@ -689,22 +707,24 @@ GEM activesupport (>= 5.0.0) minitest nokogiri (>= 1.6) - rails-html-sanitizer (1.6.2) - loofah (~> 2.21) + rails-html-sanitizer (1.7.0) + loofah (~> 2.25) nokogiri (>= 1.15.7, != 1.16.7, != 1.16.6, != 1.16.5, != 1.16.4, != 1.16.3, != 1.16.2, != 1.16.1, != 1.16.0.rc1, != 1.16.0) rails-i18n (7.0.10) i18n (>= 0.7, < 2) railties (>= 6.0.0, < 8) - railties (7.2.2.2) - actionpack (= 7.2.2.2) - activesupport (= 7.2.2.2) + railties (7.2.3) + actionpack (= 7.2.3) + activesupport (= 7.2.3) + cgi irb (~> 1.13) rackup (>= 1.0.0) rake (>= 12.2) thor (~> 1.0, >= 1.2.2) + tsort (>= 0.2) zeitwerk (~> 2.6) rainbow (3.1.1) - rake (13.3.0) + rake (13.3.1) ransack (4.2.1) activerecord (>= 6.1.5) activesupport (>= 6.1.5) @@ -712,32 +732,33 @@ GEM rb-fsevent (0.11.2) rb-inotify (0.11.1) ffi (~> 1.0) - rdoc (6.14.2) + rdoc (7.2.0) erb psych (>= 4.0.0) + tsort redcarpet (3.6.1) redis (4.8.1) - regexp_parser (2.10.0) - reline (0.6.2) + regexp_parser (2.11.3) + reline (0.6.3) io-console (~> 0.5) request_store (1.7.0) rack (>= 1.4) - responders (3.1.1) - actionpack (>= 5.2) - railties (>= 5.2) - rexml (3.4.1) + responders (3.2.0) + actionpack (>= 7.0) + railties (>= 7.0) + rexml (3.4.4) rqrcode (2.2.0) chunky_png (~> 1.0) rqrcode_core (~> 1.0) rqrcode_core (1.2.0) - rspec (3.13.1) + rspec (3.13.2) rspec-core (~> 3.13.0) rspec-expectations (~> 3.13.0) rspec-mocks (~> 3.13.0) rspec-cells (0.3.10) cells (>= 4.0.0, < 6.0.0) rspec-rails (>= 3.0.0) - rspec-core (3.13.5) + rspec-core (3.13.6) rspec-support (~> 3.13.0) rspec-expectations (3.13.5) diff-lcs (>= 1.2.0, < 2.0) @@ -745,7 +766,7 @@ GEM rspec-html-matchers (0.10.0) nokogiri (~> 1) rspec (>= 3.0.0.a) - rspec-mocks (3.13.5) + rspec-mocks (3.13.8) diff-lcs (>= 1.2.0, < 2.0) rspec-support (~> 3.13.0) rspec-rails (6.1.5) @@ -758,7 +779,7 @@ GEM rspec-support (~> 3.13) rspec-retry (0.6.2) rspec-core (> 3.3) - rspec-support (3.13.4) + rspec-support (3.13.7) rspec_junit_formatter (0.6.0) rspec-core (>= 2, < 4, != 2.12.0) rubocop (1.78.0) @@ -772,9 +793,9 @@ GEM rubocop-ast (>= 1.45.1, < 2.0) ruby-progressbar (~> 1.7) unicode-display_width (>= 2.4.0, < 4.0) - rubocop-ast (1.45.1) + rubocop-ast (1.49.1) parser (>= 3.3.7.2) - prism (~> 1.4) + prism (~> 1.7) rubocop-capybara (2.22.1) lint_roller (~> 1.1) rubocop (~> 1.72, >= 1.72.1) @@ -785,20 +806,20 @@ GEM faker (>= 2.12.0) lint_roller (~> 1.1) rubocop (>= 1.72.1) - rubocop-graphql (1.5.6) + rubocop-graphql (1.6.0) lint_roller (~> 1.1) rubocop (>= 1.72.1, < 2) - rubocop-performance (1.25.0) + rubocop-performance (1.26.1) lint_roller (~> 1.1) rubocop (>= 1.75.0, < 2.0) - rubocop-ast (>= 1.38.0, < 2.0) + rubocop-ast (>= 1.47.1, < 2.0) rubocop-rails (2.32.0) activesupport (>= 4.2.0) lint_roller (~> 1.1) rack (>= 1.1) rubocop (>= 1.75.0, < 2.0) rubocop-ast (>= 1.44.0, < 2.0) - rubocop-rspec (3.6.0) + rubocop-rspec (3.7.0) lint_roller (~> 1.1) rubocop (~> 1.72, >= 1.72.1) rubocop-rspec_rails (2.31.0) @@ -809,25 +830,25 @@ GEM lint_roller (~> 1.1) rubocop (~> 1.72, >= 1.72.1) ruby-progressbar (1.13.0) - ruby-vips (2.2.4) + ruby-vips (2.3.0) ffi (~> 1.12) logger rubyXL (3.4.33) nokogiri (>= 1.10.8) rubyzip (>= 1.3.0) rubyzip (2.3.2) - sass-embedded (1.83.4-arm64-darwin) - google-protobuf (~> 4.29) - sass-embedded (1.83.4-x86_64-linux-gnu) - google-protobuf (~> 4.29) + sass-embedded (1.98.0-arm64-darwin) + google-protobuf (~> 4.31) + sass-embedded (1.98.0-x86_64-linux-gnu) + google-protobuf (~> 4.31) securerandom (0.4.1) - selenium-webdriver (4.27.0) + selenium-webdriver (4.41.0) base64 (~> 0.2) logger (~> 1.4) rexml (~> 3.2, >= 3.2.5) - rubyzip (>= 1.2.2, < 3.0) + rubyzip (>= 1.2.2, < 4.0) websocket (~> 1.0) - semantic_range (3.1.0) + semantic_range (3.1.1) shakapacker (8.3.0) activesupport (>= 5.2) package_json @@ -847,32 +868,33 @@ GEM snaky_hash (2.0.3) hashie (>= 0.1.0, < 6) version_gem (>= 1.1.8, < 3) - spring (4.2.1) + spring (4.4.2) spring-watcher-listen (2.1.0) listen (>= 2.7, < 4.0) spring (>= 4) - stringio (3.1.7) - strscan (3.1.5) + stringio (3.2.0) + strscan (3.1.7) temple (0.10.4) terminal-table (4.0.0) unicode-display_width (>= 1.1.1, < 4) - thor (1.4.0) - tilt (2.5.0) - timeout (0.4.3) + thor (1.5.0) + tilt (2.7.0) + timeout (0.6.1) trailblazer-option (0.1.2) + tsort (0.2.0) tzinfo (2.0.6) concurrent-ruby (~> 1.0) uber (0.1.0) - unicode-display_width (3.1.4) - unicode-emoji (~> 4.0, >= 4.0.4) - unicode-emoji (4.0.4) - uniform_notifier (1.17.0) - uri (1.0.3) + unicode-display_width (3.2.0) + unicode-emoji (~> 4.1) + unicode-emoji (4.2.0) + uniform_notifier (1.18.0) + uri (1.1.1) useragent (0.16.11) - valid_email2 (7.0.13) + valid_email2 (7.0.15) activemodel (>= 6.0) mail (~> 2.5) - version_gem (1.1.8) + version_gem (1.1.9) w3c_rspec_validators (0.3.0) rails rspec @@ -883,24 +905,24 @@ GEM rexml (~> 3.2) warden (1.2.9) rack (>= 2.0.9) - warden-jwt_auth (0.11.0) + warden-jwt_auth (0.12.0) dry-auto_inject (>= 0.8, < 2) dry-configurable (>= 0.13, < 2) - jwt (~> 2.1) + jwt (>= 2.1, < 4) warden (~> 1.2) web-console (4.2.1) actionview (>= 6.0.0) activemodel (>= 6.0.0) bindex (>= 0.4.0) railties (>= 6.0.0) - web-push (3.0.1) - jwt (~> 2.0) - openssl (~> 3.0) - webmock (3.24.0) + web-push (3.1.0) + jwt (~> 3.0) + openssl (>= 3.0) + webmock (3.26.2) addressable (>= 2.8.0) crack (>= 0.3.2) hashdiff (>= 0.4.0, < 2.0.0) - webrick (1.9.1) + webrick (1.9.2) websocket (1.2.11) websocket-driver (0.8.0) base64 @@ -910,7 +932,7 @@ GEM wisper-rspec (1.1.0) xpath (3.2.0) nokogiri (~> 1.8) - zeitwerk (2.7.3) + zeitwerk (2.7.5) PLATFORMS arm64-darwin-23 diff --git a/bin/devcontainer b/bin/devcontainer new file mode 100755 index 0000000000000..6c975c41f5a7d --- /dev/null +++ b/bin/devcontainer @@ -0,0 +1,175 @@ +#!/usr/bin/env bash + +# Configuration +CONTAINER_NAME="decidim-rails-app" +SCRIPT_NAME=$(basename "$0") +CONTAINERS_TO_STOP=("decidim-rails-app-1" "decidim-selenium-1" "decidim-postgres-1" "decidim-redis-1") +DEVCONTAINER_DIR=".devcontainer" +DEVCONTAINER_JSON="$DEVCONTAINER_DIR/devcontainer.json" +DEVCONTAINER_LOCAL_JSON="$DEVCONTAINER_DIR/devcontainer.local.json" +DEVCONTAINER_BACKUP_JSON="$DEVCONTAINER_DIR/devcontainer.json.backup" + +# Function to use local config if it exists +# +# This allows having a file with local instructions for your personal developer environment at +# .devcontainer/devcontainer.local.json +# So, for instance, you can have +# +# ```json +# { +# "postCreateCommand": ".devcontainer/devcontainer.local.postCreateCommand.bash" +# } +# ``` +# +# And there you can add your own packages, dotfiles, etc. Do not forget to also call `bin/setup` +# at the end of your script. +# +use_local_config() { + if [ -f "$DEVCONTAINER_LOCAL_JSON" ]; then + # Check if jq is available + if command -v jq &> /dev/null; then + echo "Merging devcontainer.local.json with devcontainer.json..." >&2 + + # Backup original + cp "$DEVCONTAINER_JSON" "$DEVCONTAINER_BACKUP_JSON" + + # Merge configs: base config with local overrides + # jq -s '.[0] * .[1]' merges two objects, with the second overriding the first + if jq -s '.[0] * .[1]' "$DEVCONTAINER_BACKUP_JSON" "$DEVCONTAINER_LOCAL_JSON" > "$DEVCONTAINER_JSON"; then + return 0 + else + echo "Error: Failed to merge JSON configs. Restoring backup..." >&2 + mv "$DEVCONTAINER_BACKUP_JSON" "$DEVCONTAINER_JSON" + return 1 + fi + else + echo "Warning: jq not found. Install jq to use devcontainer.local.json." >&2 + return 1 + fi + fi + return 1 +} + +# Function to restore original devcontainer config +restore_devcontainer_config() { + if [ -f "$DEVCONTAINER_BACKUP_JSON" ]; then + mv "$DEVCONTAINER_BACKUP_JSON" "$DEVCONTAINER_JSON" + fi +} + +# Check if devcontainer CLI is installed +if ! command -v devcontainer &> /dev/null; then + echo "devcontainer CLI not found. Installing..." + npm install -g @devcontainers/cli + + # Check if installation was successful + if ! command -v devcontainer &> /dev/null; then + echo "Error: Failed to install devcontainer CLI" + exit 1 + fi + echo "devcontainer CLI installed successfully" +fi + +# Handle commands that don't need container ID first +case "$1" in + up) + use_local_config + devcontainer up --workspace-folder=. + status=$? + restore_devcontainer_config + exit "$status" + ;; + down) + echo "Stopping containers..." + for container in "${CONTAINERS_TO_STOP[@]}"; do + if docker ps -a --format "{{.Names}}" | grep -q "^${container}$"; then + echo "Stopping $container..." + docker stop "$container" + else + echo "Container $container not found, skipping..." + fi + done + restore_devcontainer_config + exit 0 + ;; + rebuild) + echo "Removing development_app directory..." + rm -rf development_app/ + use_local_config + devcontainer up --workspace-folder=. --remove-existing-container + status=$? + restore_devcontainer_config + exit "$status" + ;; + rm) + echo "Removing all containers and cleaning up..." + for container in "${CONTAINERS_TO_STOP[@]}"; do + if docker ps -a --format "{{.Names}}" | grep -q "^${container}$"; then + echo "Removing $container..." + docker rm -f "$container" + else + echo "Container $container not found, skipping..." + fi + done + echo "Cleaning up development_app directory..." + rm -rf development_app/ + restore_devcontainer_config + echo "Cleanup complete!" + exit 0 + ;; + ps) + echo "Checking container status..." + echo "" + found_any=false + for container in "${CONTAINERS_TO_STOP[@]}"; do + if docker ps -a --format "{{.Names}}" | grep -q "^${container}$"; then + found_any=true + status=$(docker ps -a --format "{{.Names}}\t{{.Status}}" | grep "^${container}\s" | cut -f2) + echo " $container: $status" + fi + done + if [ "$found_any" = false ]; then + echo " No containers found" + fi + exit 0 + ;; + ""| help | --help | -h) + echo "Usage: $SCRIPT_NAME " + echo "" + echo "Container Management:" + echo " up - Start the devcontainer" + echo " down - Stop all containers" + echo " rebuild - Rebuild the devcontainer" + echo " rm - Remove all containers and clean up" + echo " ps - Check container status" + echo "" + echo "Execute Commands:" + echo " $SCRIPT_NAME Execute any command in the container" + echo "" + echo "Examples:" + echo " $SCRIPT_NAME dev - Run bin/dev" + echo " $SCRIPT_NAME rails console - Run bin/rails console" + echo " $SCRIPT_NAME bundle install - Run bin/bundle install" + echo " $SCRIPT_NAME bundle exec rake test_app - Generates the test_app" + echo " $SCRIPT_NAME rspec decidim-budgets/spec/models/order_spec.rb - Runs the specs for the budgets' order model" + exit 0 + ;; +esac + +# Get the container ID for decidim-rails-app +container_id=$(docker ps --filter "name=$CONTAINER_NAME" --format "{{.ID}}" | head -n 1) + +# Check if container was found +if [ -z "$container_id" ]; then + echo "Error: $CONTAINER_NAME container not found. Start it with '$SCRIPT_NAME up'" + exit 1 +fi + +# Check if the command exists in ./bin directory +if [ -f "./bin/$1" ] && [ -x "./bin/$1" ]; then + # If it's a script in bin/, prepend bin/ to the path + devcontainer exec --container-id "$container_id" --workspace-folder=. "bin/$@" +else + # Otherwise execute the command as-is + devcontainer exec --container-id "$container_id" --workspace-folder=. "$@" +fi diff --git a/bin/setup b/bin/setup new file mode 100755 index 0000000000000..e472a0a696a9e --- /dev/null +++ b/bin/setup @@ -0,0 +1,95 @@ +#!/usr/bin/env ruby +require "fileutils" +require "json" + +APP_ROOT = File.expand_path("..", __dir__) +APP_NAME = "decidim-development-app" + +def system!(env = {}, *args) + if args.empty? + # env is actually the command + system(env, exception: true) + else + system(env, *args, exception: true) + end +end + +class CodespacesConfig + ENV_FILE = "/workspaces/.codespaces/shared/environment-variables.json" + APP_CONFIG = "development_app/config/application.rb" + + def self.running? + File.exist?(ENV_FILE) + end + + def initialize + @hostname = nil + end + + def hostname + @hostname ||= fetch_hostname + end + + def env_vars + hostname ? { "DECIDIM_HOST" => hostname } : {} + end + + def configure_application! + return unless hostname + return unless File.exist?(APP_CONFIG) + + config_content = File.read(APP_CONFIG) + return if config_content.match?(/^\s+config\.hosts/) + + updated_content = config_content.sub( + /(config\.load_defaults\s+[\d.]+\s*\n)/, + "\\1 config.hosts << \"#{hostname}\"\n" + ) + + File.write(APP_CONFIG, updated_content) + puts "\n== Configured Codespaces host: #{hostname} ==" + end + + private + + def fetch_hostname + return nil unless File.exist?(ENV_FILE) + + env_data = JSON.parse(File.read(ENV_FILE)) + codespace_name = env_data["CODESPACE_NAME"] + return nil unless codespace_name + + "#{codespace_name}-3000.app.github.dev" + end +end + +FileUtils.chdir APP_ROOT do + # This script is a way to set up or update your development environment automatically. + # This script is idempotent, so that you can run it at any time and get an expectable outcome. + # Add necessary setup steps to this file. + + puts "== Installing dependencies ==" + system! "gem install bundler --conservative" + system("bundle check") || system!("bundle install") + system("npm install") + + puts "\n== Preparing decidim development app ==" + if CodespacesConfig.running? + codespaces = CodespacesConfig.new + system!(codespaces.env_vars, "bundle exec rake development_app") unless Dir.exist?("development_app") + codespaces.configure_application! + else + system!("bundle exec rake development_app") unless Dir.exist?("development_app") + end + + puts "\n== Preparing database ==" + system("bin/rails db:create") + + if File.exist?("development_app/tmp/pids/server.pid") + puts "\n== Removing the leftover pid file ==" + system("rm development_app/tmp/pids/server.pid") + end + + puts "\n== Starting application server ==" + system! "bin/dev" +end diff --git a/crowdin.yaml b/crowdin.yaml index c8ec1bce62c2f..1050580e75c0c 100644 --- a/crowdin.yaml +++ b/crowdin.yaml @@ -34,7 +34,7 @@ files: lv: lv mt: mt nl: nl - no: no + 'no': 'no' pl: pl pt: pt pt-PT: pt diff --git a/decidim-accountability/app/forms/decidim/accountability/admin/status_form.rb b/decidim-accountability/app/forms/decidim/accountability/admin/status_form.rb index c7e2f7353b8cf..66f95c2bb9ad7 100644 --- a/decidim-accountability/app/forms/decidim/accountability/admin/status_form.rb +++ b/decidim-accountability/app/forms/decidim/accountability/admin/status_form.rb @@ -15,6 +15,7 @@ class StatusForm < Decidim::Form validates :key, presence: true validates :name, translatable_presence: true + validates :progress, numericality: { greater_than_or_equal_to: 0, less_than_or_equal_to: 100 }, if: ->(form) { form.progress.present? } end end end diff --git a/decidim-accountability/app/views/decidim/accountability/admin/results/_actions.html.erb b/decidim-accountability/app/views/decidim/accountability/admin/results/_actions.html.erb index bad8b55d00b02..b88cfa90e3497 100644 --- a/decidim-accountability/app/views/decidim/accountability/admin/results/_actions.html.erb +++ b/decidim-accountability/app/views/decidim/accountability/admin/results/_actions.html.erb @@ -88,7 +88,7 @@ <% else %> - + <% if statuses.any? %> + + <% end %> diff --git a/decidim-accountability/config/locales/ar.yml b/decidim-accountability/config/locales/ar.yml index 268fc12f947c9..ec6813fff1481 100644 --- a/decidim-accountability/config/locales/ar.yml +++ b/decidim-accountability/config/locales/ar.yml @@ -228,7 +228,6 @@ ar: global: clear_all: إمسح الكل comments_enabled: تم تمكين التعليقات - comments_max_length: الحد الأقصى لطول التعليقات (اترك ال0 للقيمة الافتراضية) define_taxonomy_filters: الرجاء تحديد بعض عوامل التصفية لهذه المساحة التشاركية قبل استخدام هذا الإعداد. display_progress_enabled: عرض التقدم geocoding_enabled: تم تمكين الخرائط diff --git a/decidim-accountability/config/locales/bg.yml b/decidim-accountability/config/locales/bg.yml index 4ad075d25d71d..71e9cb20d8216 100644 --- a/decidim-accountability/config/locales/bg.yml +++ b/decidim-accountability/config/locales/bg.yml @@ -162,7 +162,6 @@ bg: settings: global: comments_enabled: Коментарите са разрешени - comments_max_length: Максимална дължина на коментарите (Оставете 0 за стойност по подразбиране) display_progress_enabled: Показвай развитието intro: Въведение step: diff --git a/decidim-accountability/config/locales/ca-IT.yml b/decidim-accountability/config/locales/ca-IT.yml index 013e39ecfbfeb..7b0fde2dea781 100644 --- a/decidim-accountability/config/locales/ca-IT.yml +++ b/decidim-accountability/config/locales/ca-IT.yml @@ -302,7 +302,7 @@ ca-IT: global: clear_all: Netejar-ho tot comments_enabled: Comentaris habilitats - comments_max_length: Longitud màxima dels comentaris (deixa 0 si vols mantenir la configuració per defecte) + comments_max_length: Caràcters màxims per comentari (deixar a 0 el valor predeterminat) default_taxonomy: Taxonomia predeterminada default_taxonomy_help: Selecciona quina taxonomia vols mostrar per defecte. Si no se selecciona cap taxonomia, els resultats es mostraran en un format de llista. define_taxonomy_filters: Si us plau, defineix algunes filtres per aquest espai de participació abans de fer servir aquesta configuració. diff --git a/decidim-accountability/config/locales/ca.yml b/decidim-accountability/config/locales/ca.yml index 72af9173ff0e1..938f18dafaf5b 100644 --- a/decidim-accountability/config/locales/ca.yml +++ b/decidim-accountability/config/locales/ca.yml @@ -302,7 +302,7 @@ ca: global: clear_all: Netejar-ho tot comments_enabled: Comentaris habilitats - comments_max_length: Longitud màxima dels comentaris (deixa 0 si vols mantenir la configuració per defecte) + comments_max_length: Caràcters màxims per comentari (deixar a 0 el valor predeterminat) default_taxonomy: Taxonomia predeterminada default_taxonomy_help: Selecciona quina taxonomia vols mostrar per defecte. Si no se selecciona cap taxonomia, els resultats es mostraran en un format de llista. define_taxonomy_filters: Si us plau, defineix algunes filtres per aquest espai de participació abans de fer servir aquesta configuració. diff --git a/decidim-accountability/config/locales/cs.yml b/decidim-accountability/config/locales/cs.yml index 4fd1783312d51..23dd1ddeac812 100644 --- a/decidim-accountability/config/locales/cs.yml +++ b/decidim-accountability/config/locales/cs.yml @@ -315,7 +315,6 @@ cs: global: clear_all: Vymazat vše comments_enabled: Komentáře povoleny - comments_max_length: Maximální délka komentáře (ponechte 0 pro výchozí hodnotu) default_taxonomy: Výchozí taxonomie default_taxonomy_help: Vyberte taxonomii, která se má zobrazovat jako výchozí. Pokud není vybrána žádná taxonomie, výsledky se zobrazí ve formátu seznamu. define_taxonomy_filters: Před použitím tohoto nastavení prosím definujte některé filtry pro tento participační prostor. diff --git a/decidim-accountability/config/locales/da.yml b/decidim-accountability/config/locales/da.yml index a405209eea8a5..831a4ab0bb108 100644 --- a/decidim-accountability/config/locales/da.yml +++ b/decidim-accountability/config/locales/da.yml @@ -111,7 +111,6 @@ da: settings: global: comments_enabled: Kommentarer aktiveret - comments_max_length: Kommentarer maks. længde (Leave 0 for standardværdi) display_progress_enabled: Vis fremskridt intro: Intro resource_links: diff --git a/decidim-accountability/config/locales/de.yml b/decidim-accountability/config/locales/de.yml index 736884236b53c..2c3a317d2db88 100644 --- a/decidim-accountability/config/locales/de.yml +++ b/decidim-accountability/config/locales/de.yml @@ -301,7 +301,6 @@ de: global: clear_all: Alles löschen comments_enabled: Kommentare aktiviert - comments_max_length: Maximale Länge der Kommentare (0 für Standardwert) default_taxonomy: Standard Klassifizierung default_taxonomy_help: Wählen Sie, welche Klassifizierung standardmäßig angezeigt werden soll. Wenn keine Taxonomie ausgewählt ist, werden die Ergebnisse in einem Listenformat angezeigt. define_taxonomy_filters: Bitte definieren Sie einige Filter für diesen partizipativen Bereich, bevor Sie diese Einstellung verwenden. diff --git a/decidim-accountability/config/locales/el.yml b/decidim-accountability/config/locales/el.yml index 422fd3d66c2a9..94aa4de8aa8a2 100644 --- a/decidim-accountability/config/locales/el.yml +++ b/decidim-accountability/config/locales/el.yml @@ -292,7 +292,6 @@ el: global: clear_all: Εκκαθάριση όλων comments_enabled: Τα σχόλια ενεργοποιήθηκαν - comments_max_length: Μέγιστο μέγεθος σχολίων (Αφήστε το 0 για το προκαθορισμένο μέγεθος) define_taxonomy_filters: Παρακαλώ καθορίστε μερικά φίλτρα για αυτόν τον συμμετοχικό χώρο πριν χρησιμοποιήσετε αυτή τη ρύθμιση. display_progress_enabled: Εμφάνιση προόδου geocoding_enabled: Χάρτες ενεργοποιημένοι diff --git a/decidim-accountability/config/locales/en.yml b/decidim-accountability/config/locales/en.yml index 6e794e4e3465c..4b944a2cce429 100644 --- a/decidim-accountability/config/locales/en.yml +++ b/decidim-accountability/config/locales/en.yml @@ -303,7 +303,7 @@ en: global: clear_all: Clear all comments_enabled: Comments enabled - comments_max_length: Comments max length (Leave 0 for default value) + comments_max_length: Max characters per comment (Leave 0 for default value) default_taxonomy: Default taxonomy default_taxonomy_help: Select which taxonomy you want to show by default. If no taxonomy is selected, the results will be shown in a list format. define_taxonomy_filters: Please define some filters for this participatory space before using this setting. diff --git a/decidim-accountability/config/locales/es-MX.yml b/decidim-accountability/config/locales/es-MX.yml index ef1137b27cf72..37a041d36d390 100644 --- a/decidim-accountability/config/locales/es-MX.yml +++ b/decidim-accountability/config/locales/es-MX.yml @@ -95,7 +95,7 @@ es-MX:
  • Haz los cambios en local. Sólo puedes modificar las siguientes columnas del CSV (el resto será ignorado):
    • taxonomies/ids: IDs para la taxonomia (si hay más de una, sepárelas con una coma)
    • -
    • parent/id: ID para el padre (para resultados relacionados). +
    • parent/id: ID para el padre (para resultados relacionados).
      Opcional
    • title/I18N: título en el idioma X
    • description/I18N: descripción en el idioma X
    • @@ -302,7 +302,7 @@ es-MX: global: clear_all: Limpiar todo comments_enabled: Comentarios habilitados - comments_max_length: Longitud máxima de los comentarios (deja 0 si quieres mantener la configuración por defecto) + comments_max_length: Caracteres máximos por comentario (dejar 0 para el valor predeterminado) default_taxonomy: Taxonomía predeterminada default_taxonomy_help: Selecciona qué taxonomía quieres mostrar por defecto. Si no se selecciona alguna taxonomía, los resultados se mostrarán en un formato de lista. define_taxonomy_filters: Por favor, define algunos filtros para este espacio de participación antes de utilizar esta configuración. diff --git a/decidim-accountability/config/locales/es-PY.yml b/decidim-accountability/config/locales/es-PY.yml index aa3549b668311..8f378c91e6a90 100644 --- a/decidim-accountability/config/locales/es-PY.yml +++ b/decidim-accountability/config/locales/es-PY.yml @@ -95,7 +95,7 @@ es-PY:
    • Haz los cambios en local. Sólo puedes modificar las siguientes columnas del CSV (el resto será ignorado):
      • taxonomies/ids: IDs para la taxonomia (si hay más de una, sepárelas con una coma)
      • -
      • parent/id: ID para el padre (para resultados relacionados). +
      • parent/id: ID para el padre (para resultados relacionados).
        Opcional
      • title/I18N: título en el idioma X
      • description/I18N: descripción en el idioma X
      • @@ -302,7 +302,7 @@ es-PY: global: clear_all: Limpiar todo comments_enabled: Comentarios habilitados - comments_max_length: Longitud máxima de los comentarios (deja 0 si quieres mantener la configuración por defecto) + comments_max_length: Caracteres máximos por comentario (dejar 0 para el valor predeterminado) default_taxonomy: Taxonomía predeterminada default_taxonomy_help: Selecciona qué taxonomía quieres mostrar por defecto. Si no se selecciona alguna taxonomía, los resultados se mostrarán en un formato de lista. define_taxonomy_filters: Por favor, define algunos filtros para este espacio de participación antes de utilizar esta configuración. diff --git a/decidim-accountability/config/locales/es.yml b/decidim-accountability/config/locales/es.yml index 7e4404011fbc9..5b4d19aa61c23 100644 --- a/decidim-accountability/config/locales/es.yml +++ b/decidim-accountability/config/locales/es.yml @@ -302,7 +302,7 @@ es: global: clear_all: Limpiar todo comments_enabled: Comentarios habilitados - comments_max_length: Longitud máxima de los comentarios (deja 0 si quieres mantener la configuración por defecto) + comments_max_length: Caracteres máximos por comentario (dejar 0 para el valor predeterminado) default_taxonomy: Taxonomía predeterminada default_taxonomy_help: Selecciona qué taxonomía quieres mostrar por defecto. Si no se selecciona alguna taxonomía, los resultados se mostrarán en un formato de lista. define_taxonomy_filters: Por favor, define algunos filtros para este espacio de participación antes de utilizar esta configuración. diff --git a/decidim-accountability/config/locales/eu.yml b/decidim-accountability/config/locales/eu.yml index df63c4cc353b3..a1eb2c81be718 100644 --- a/decidim-accountability/config/locales/eu.yml +++ b/decidim-accountability/config/locales/eu.yml @@ -9,7 +9,7 @@ eu: result: decidim_accountability_status_id: Egoera decidim_category_id: Kategoria - decidim_scope_id: Eremua + decidim_scope_id: Esparrua description: Deskribapena end_date: Bukaera-data progress: Aurrerapena @@ -106,7 +106,7 @@ eu:
    • - title: Inportatu emaitzak CSV fitxategitik + title: Emaitzak CSV fitxategitik inportartu imports: create: invalid: Arazo bat egon da emaitzak inportatzean. @@ -277,7 +277,7 @@ eu: title: Mugarriak no_results: Ez dago proiekturik root_taxonomies: - title: 'Ikusi honela:' + title: 'Honen bidez bistaratu:' search: search: Bilatu ekintzak show: @@ -301,7 +301,7 @@ eu: global: clear_all: Garbitu dena comments_enabled: Iruzkinak gaituta - comments_max_length: Iruzkinen gehieneko luzera (utzi 0 hasierako konfigurazioari eusteko) + comments_max_length: Iruzkin bakoitzeko gehieneko karaktereak (utzi 0 aurrez zehaztutako baliorako) default_taxonomy: Taxonomia akatsa default_taxonomy_help: Aukeratu zein taxonomia erakutsi nahi duzun akatsez. Taxonomiarik aukeratzen ez bada, emaitzak zerrenda formatuan agertuko dira. define_taxonomy_filters: Mesedez, eszenatoki hau erabili aurretik, zehaztu iragazki batzuk partaidetza-espazio honetarako. diff --git a/decidim-accountability/config/locales/fr-CA.yml b/decidim-accountability/config/locales/fr-CA.yml index eac77d8857265..0485ab0b2edfd 100644 --- a/decidim-accountability/config/locales/fr-CA.yml +++ b/decidim-accountability/config/locales/fr-CA.yml @@ -302,7 +302,7 @@ fr-CA: global: clear_all: Tout supprimer comments_enabled: Activer le module de commentaire - comments_max_length: Longueur max des commentaires (laisser 0 pour la valeur par défaut) + comments_max_length: Nombre maximum de caractères par commentaire (Laisser 0 pour la valeur par défaut) default_taxonomy: Taxonomie par défaut default_taxonomy_help: Sélectionnez la taxonomie que vous voulez afficher par défaut. Si aucune taxonomie n'est sélectionnée, les résultats seront affichés dans un format de liste. define_taxonomy_filters: Pour utiliser ce paramètre, des filtres doivent être définis dans cet espace participatif. diff --git a/decidim-accountability/config/locales/fr.yml b/decidim-accountability/config/locales/fr.yml index 58493a21eb60a..a0aac76d02f4f 100644 --- a/decidim-accountability/config/locales/fr.yml +++ b/decidim-accountability/config/locales/fr.yml @@ -302,7 +302,7 @@ fr: global: clear_all: Tout supprimer comments_enabled: Activer le module de commentaire - comments_max_length: Longueur max des commentaires (laisser 0 pour la valeur par défaut) + comments_max_length: Nombre maximum de caractères par commentaire (Laisser 0 pour la valeur par défaut) default_taxonomy: Taxonomie par défaut default_taxonomy_help: Sélectionnez la taxonomie que vous voulez afficher par défaut. Si aucune taxonomie n'est sélectionnée, les résultats seront affichés dans un format de liste. define_taxonomy_filters: Pour utiliser ce paramètre, des filtres doivent être définis dans cet espace participatif. diff --git a/decidim-accountability/config/locales/gl.yml b/decidim-accountability/config/locales/gl.yml index c474184d5a688..7932fa8f8224a 100644 --- a/decidim-accountability/config/locales/gl.yml +++ b/decidim-accountability/config/locales/gl.yml @@ -124,7 +124,6 @@ gl: settings: global: comments_enabled: Comentarios habilitados - comments_max_length: Lonxitude máxima dos comentarios (0 para valor predefinido) display_progress_enabled: Mostrar o progreso intro: Intro step: diff --git a/decidim-accountability/config/locales/he-IL.yml b/decidim-accountability/config/locales/he-IL.yml index 846620afc4c44..565ae1f6f7f02 100644 --- a/decidim-accountability/config/locales/he-IL.yml +++ b/decidim-accountability/config/locales/he-IL.yml @@ -211,7 +211,6 @@ he: global: clear_all: נקה הכל comments_enabled: תגובות אפשריות - comments_max_length: אורך מקסימלי להערות (השאירו 0 לערך ברירת המחדל) display_progress_enabled: הצגת התקדמות intro: הקדמה step: diff --git a/decidim-accountability/config/locales/hu.yml b/decidim-accountability/config/locales/hu.yml index 6a3f59e35dc3f..c302b1239f805 100644 --- a/decidim-accountability/config/locales/hu.yml +++ b/decidim-accountability/config/locales/hu.yml @@ -167,7 +167,6 @@ hu: settings: global: comments_enabled: Megjegyzések engedélyezve - comments_max_length: Kommentek maximális hossza (Hagyjon 0 -t az alapértékhez) display_progress_enabled: Állapot megjelenítése intro: Intro step: diff --git a/decidim-accountability/config/locales/it.yml b/decidim-accountability/config/locales/it.yml index adf4bb14825dd..51fad32d3987c 100644 --- a/decidim-accountability/config/locales/it.yml +++ b/decidim-accountability/config/locales/it.yml @@ -281,7 +281,6 @@ it: global: clear_all: Cancella tutto comments_enabled: Commenti abilitati - comments_max_length: Lunghezza massima dei commenti (Lasciare 0 per il valore predefinito) default_taxonomy: Tassonomia di default default_taxonomy_help: Seleziona quale tassonomia vuoi mostrare di default. Se nessuna tassonomia è selezionata, i risultati saranno mostrati in formato elenco. define_taxonomy_filters: Si prega di definire alcuni filtri per questo spazio partecipativo prima di utilizzare questa impostazione. diff --git a/decidim-accountability/config/locales/ja.yml b/decidim-accountability/config/locales/ja.yml index b10dceb2c9250..df0fd4ec2111d 100644 --- a/decidim-accountability/config/locales/ja.yml +++ b/decidim-accountability/config/locales/ja.yml @@ -294,7 +294,7 @@ ja: global: clear_all: すべてクリア comments_enabled: コメントを有効にする - comments_max_length: コメント最大長 (デフォルト値は 0 のまま) + comments_max_length: 各コメントの最大文字数 (0はデフォルト値のまま) default_taxonomy: デフォルトのタクソノミー default_taxonomy_help: デフォルトで表示するタクソノミーを選択します。タクソノミーが選択されていない場合、結果はリスト形式で表示されます。 define_taxonomy_filters: この設定を使用する前に、参加型スペースのフィルターをいくつか定義してください。 diff --git a/decidim-accountability/config/locales/ko.yml b/decidim-accountability/config/locales/ko.yml index daebb79673eb3..22f78a79bc98c 100644 --- a/decidim-accountability/config/locales/ko.yml +++ b/decidim-accountability/config/locales/ko.yml @@ -154,7 +154,6 @@ ko: settings: global: comments_enabled: 댓글 활성화됨 - comments_max_length: 댓글 최대 길이(기본값은 0으로 남김) display_progress_enabled: 진행사항 보기 intro: 소개 step: diff --git a/decidim-accountability/config/locales/lb.yml b/decidim-accountability/config/locales/lb.yml index 87e27cc061426..5cf150c410e94 100644 --- a/decidim-accountability/config/locales/lb.yml +++ b/decidim-accountability/config/locales/lb.yml @@ -124,7 +124,6 @@ lb: settings: global: comments_enabled: Kommentare aktiviert - comments_max_length: Maximale Länge der Kommentare (0 für Standardwert) display_progress_enabled: Fortschritt anzeigen intro: Einführung step: diff --git a/decidim-accountability/config/locales/lt.yml b/decidim-accountability/config/locales/lt.yml index 3da14b29a3e29..72b1b792e8bcf 100644 --- a/decidim-accountability/config/locales/lt.yml +++ b/decidim-accountability/config/locales/lt.yml @@ -163,7 +163,6 @@ lt: settings: global: comments_enabled: Įjungti komentarai - comments_max_length: Maksimalus komentaro ilgis (įrašyti 0 įprastam ilgiui) display_progress_enabled: Rodyti progresą intro: Įžanga step: diff --git a/decidim-accountability/config/locales/nl.yml b/decidim-accountability/config/locales/nl.yml index 845ce8ba3af84..d89160eb82dfa 100644 --- a/decidim-accountability/config/locales/nl.yml +++ b/decidim-accountability/config/locales/nl.yml @@ -128,7 +128,6 @@ nl: settings: global: comments_enabled: Reacties ingeschakeld - comments_max_length: Commentaar maximale lengte (laat 0 voor standaard waarde) display_progress_enabled: Geef de voortgang weer intro: Inleiding step: diff --git a/decidim-accountability/config/locales/no.yml b/decidim-accountability/config/locales/no.yml index 7107d3b7e5b14..85b59cbe2f7fc 100644 --- a/decidim-accountability/config/locales/no.yml +++ b/decidim-accountability/config/locales/no.yml @@ -128,7 +128,6 @@ settings: global: comments_enabled: Kommentarer aktivert - comments_max_length: Maks lengde på kommentarer (Sett 0 for standardverdi) display_progress_enabled: Vis fremgang intro: Introduksjon step: diff --git a/decidim-accountability/config/locales/pl.yml b/decidim-accountability/config/locales/pl.yml index a969cb1431009..0bc8435871f89 100644 --- a/decidim-accountability/config/locales/pl.yml +++ b/decidim-accountability/config/locales/pl.yml @@ -2,6 +2,9 @@ pl: activemodel: attributes: + milestone: + description: Opis + entry_date: Data result: decidim_accountability_status_id: Status decidim_category_id: Kategoria @@ -169,7 +172,6 @@ pl: settings: global: comments_enabled: Komentarze włączone - comments_max_length: Maksymalna długość komentarzy (Pozostaw 0 dla wartości domyślnej) display_progress_enabled: Wyświetl postęp intro: Wprowadzenie step: diff --git a/decidim-accountability/config/locales/pt-BR.yml b/decidim-accountability/config/locales/pt-BR.yml index b7f18e1f976ca..e4e188e1c924f 100644 --- a/decidim-accountability/config/locales/pt-BR.yml +++ b/decidim-accountability/config/locales/pt-BR.yml @@ -300,7 +300,6 @@ pt-BR: global: clear_all: Apagar tudo comments_enabled: Comentários ativados - comments_max_length: Tamanho máximo de comentários (deixe 0 para o valor padrão) default_taxonomy: Taxonomia padrão default_taxonomy_help: Selecione qual taxonomia você deseja mostrar por padrão. Se nenhuma taxonomia for selecionada, os resultados serão exibidos em um formato de lista. define_taxonomy_filters: Por favor, defina alguns filtros para este espaço participativo antes de usar esta configuração. diff --git a/decidim-accountability/config/locales/pt.yml b/decidim-accountability/config/locales/pt.yml index ef780cc810755..2652c56821a9e 100644 --- a/decidim-accountability/config/locales/pt.yml +++ b/decidim-accountability/config/locales/pt.yml @@ -144,7 +144,6 @@ pt: global: clear_all: Apagar tudo comments_enabled: Comentários ativados - comments_max_length: Comprimento máximo dos comentários (Deixar 0 para o valor predefinido) define_taxonomy_filters: Para usar esta definição, filtros devem estar definidos neste espaço participativo. display_progress_enabled: Mostrar progresso intro: Introdução diff --git a/decidim-accountability/config/locales/ro-RO.yml b/decidim-accountability/config/locales/ro-RO.yml index 9ed0e9741da52..790070ba969f0 100644 --- a/decidim-accountability/config/locales/ro-RO.yml +++ b/decidim-accountability/config/locales/ro-RO.yml @@ -308,7 +308,6 @@ ro: global: clear_all: Eliminați tot comments_enabled: Comentarii activate - comments_max_length: Lungimea maximă a comentariilor (Lăsați 0 pentru valoarea implicită) default_taxonomy: Taxonomie implicită default_taxonomy_help: Selectați ce taxonomie doriți să afișați implicit. Dacă nu este selectată nicio taxonomie, rezultatele vor fi afișate într-un format de listă. define_taxonomy_filters: Vă rugăm să definiți niște filtre pentru acest spațiu participativ înainte de a utiliza această setare. diff --git a/decidim-accountability/config/locales/ru.yml b/decidim-accountability/config/locales/ru.yml index 9839843ac6003..4144e695b4816 100644 --- a/decidim-accountability/config/locales/ru.yml +++ b/decidim-accountability/config/locales/ru.yml @@ -2,6 +2,10 @@ ru: activemodel: attributes: + milestone: + description: Описание + entry_date: Дата + title: Название result: decidim_accountability_status_id: Состояние decidim_category_id: Категория @@ -10,6 +14,7 @@ ru: end_date: Дата окончания progress: Продвижение start_date: Дата начала + subresults: Подрезультаты title: Заголовок updated_at: 'Обновлено:' status: @@ -22,6 +27,14 @@ ru: decidim/accountability/result_progress_updated_event: Прогресс результатов обновлен activerecord: models: + decidim: + accountability: + result: + budget_text: Этот результат %{link} был включен + meetings_ids: 'Что обсуждалось на этой встрече: %{link}' + project_ids: 'Что было включено в этот проект: %{link}' + proposal_ids: 'Что было включено в это предложение: %{link}' + text: 'Что было включено в этот результат: %{link}' decidim/accountability/result: one: Итог few: Итога @@ -30,35 +43,144 @@ ru: decidim: accountability: actions: + add_milestone: Добавить этап + add_result: Добавить результат + confirm_delete_result: Вы уверены, что хотите удалить этот результат? confirm_destroy: Вы действительно хотите удалить %{name}? + deleted_results_info: Удаленные результаты могут быть восстановлены из корзины. destroy: Удалить edit: Редактировать + import: Импорт результатов из другого компонента + import_csv: Импорт результатов из CSV файла + new_milestone: Новый этап + new_result: Новый результат + new_status: Новый статус preview: Предварительный просмотр title: Действия + view_deleted_results: Просмотр удаленных результатов admin: exports: + result_comments: Комментарии results: Итоги import_components: + create: + invalid: Возникла проблема при импорте результатов. Пожалуйста, тщательно следуйте инструкциям и убедитесь, что вы выбрали проекты для реализации. + filters: + proposal_state: Статус предложения + select_state: Выберите статус form: + create: Импорт no_components: + origin_component_id: Исходный компонент + select_component: Выберите компонент + new: + title: Импорт резуотатов из другого компонента + import_results: + new: + download_export: Скачать Экспорт в CSV формате + import: Импорт + info: | +

      Мы рекомендуем выполнить следующие шаги:

      +
        +
      1. Создайте Статусы для Результатов, которые вы хотите добавить
      2. +
      3. Создайте вручную хотя бы один Результат через эту панель Администратора перед использованием Импорта, чтобы лучше понять формат и что потребуется заполнить.
      4. +
      5. %{link_export_csv}
      6. +
      7. Внесите изменения локально. Вы можете изменять только следующие столбцы CSV (остальные будут проигнорированы):
      8. +
          +
        • taxonomies/ids: идентификаторы таксономий (если более одного — разделите запятой)
        • +
        • parent/id: идентификатор родительского элемента (для связанных Результатов). Необязательно
        • +
        • title/en: заголовок на английском языке. Зависит от языковой конфигурации вашей платформы.
        • +
        • description/en: описание на английском языке. Зависит от языковой конфигурации вашей платформы.
        • +
        • start_date: дата начала выполнения результата (формат YYYY-MM-DD)
        • +
        • end_date: дата окончания выполнения результата (формат YYYY-MM-DD)
        • +
        • status/id: идентификатор Статуса для данного результата
        • +
        • progress: процент выполнения (от 0 до 100)
        • +
        • proposals_ids: внутренний идентификатор связанных предложений (разделённых запятой). Автоматически преобразуется в proposal_url
        • +
        + +
      + title: Импорт результатов из CSV файла + imports: + create: + invalid: При попытке импорта этого результата произошла ошибка. + success: Начался импорт файла. В ближайшие минуты вы получите письмо с результатом импорта. + milestones: + create: + invalid: При попытке добавить этот этап произошла ошибка. + success: Этап успешно создан. + destroy: + success: Этап успешно удален. + edit: + title: Редактировать этап + update: Обновить этап + index: + title: Этапы + new: + create: Создать этап + title: Новый этап + update: + invalid: При попытке обновить этот этап произошла ошибка. + success: Этап успешно обнавлен. models: result: name: Итог status: name: Состояние results: + bulk_actions: + dates_form: + change_dates: Изменить дату + end_date: Дата окончания + start_date: Дата начала + dropdown: + actions: Действия + change_dates: Изменить даты + change_status: Изменить статус + change_taxonomies: Изменить таксономии + status_form: + change_status: Изменить статус + status: Статус + submit_buttons: + cancel: Отменить + taxonomies_form: + change_taxonomies: Изменить таксономии + create: + invalid: При создании этого результата возникла проблема. + success: Результат успешно создан. edit: title: Редактировать итог update: Обновить итог index: + selected: Выбранные title: Итоги + manage_trash: + title: Удаленные результаты new: create: Создать итог title: Добавить итог + update: + invalid: При обновлении этого результата возникла проблема. + success: Результат успешно обновлен. + update_dates: + invalid: При обновлении дат результатов возникла проблема + success: Даты результатов успешно обновлены + update_status: + invalid: При обновлении статуса результатов возникла проблема + success: Статус результатов успешно обновлен + update_taxonomies: + invalid: Не удалось обновить таксономии %{taxonomies} для результатов %{results} + select_a_result: Выберите результат + select_a_taxonomy: Выберите таксономию + success: Успешно обновлены таксономии %{taxonomies} для результатов %{results} shared: subnav: statuses: Состояния statuses: + create: + invalid: Возникла проблема при создании этого статуса. + success: Статус успешно создан. + destroy: + success: Статус успешно удален. edit: title: Редактировать состояние update: Обновить состояние @@ -67,21 +189,62 @@ ru: new: create: Создать состояние title: Добавить состояние + update: + invalid: При обновлении статуса возникла проблема. + success: Статус успешно обновлен. admin_log: + milestones: + create: "%{user_name} создал этап %{resource_name}" + delete: "%{user_name} удалил этап %{resource_name}" + update: "%{user_name} обновил этап %{resource_name}" result: create: "%{user_name} создал итог %{resource_name} в %{space_name}" delete: "%{user_name} удалил итог %{resource_name} в %{space_name}" + restore: "%{user_name} восстановил результат %{resource_name} в %{space_name}" + soft_delete: "%{user_name} переместил результат %{resource_name} в корзину %{space_name}" update: "%{user_name} обновил итог %{resource_name} в %{space_name}" + status: + create: "%{user_name} создал статус %{resource_name}" + delete: "%{user_name} удалил статус %{resource_name}" + update: "%{user_name} обновил статус %{resource_name}" value_types: parent_presenter: not_found: 'Родительский объект не найден в базе данных (ID: %{id})' + content_blocks: + highlighted_results: + results: Результаты + creation: + text: Этот результат был создан + import_mailer: + import: + errors: Ошибки + errors_present: Произошла ошибка при импорте результатов. + row_number: Строка + subject: Успешный импорт результатов + success: Успешный импорт результатов. Вы можете просмотреть результаты в интерфейсе администрирования. + import_projects_mailer: + import: + subject: Успешный импорт проектов + success: Проекты успешно импортированны в результаты в компоненте %{component_name}. Вы можете просмотреть результаты в интерфейсе администрирования. + import_proposals_mailer: + import: + subject: Успешный импорт предложений + success: Предложения успешно импортированны в результаты в компоненте %{component_name}. Вы можете просмотреть результаты в интерфейсе администрирования. + last_activity: + new_result: 'Новый результат:' models: + milestone: + fields: + entry_date: Дата + title: Название result: fields: + created_at: Создано end_date: Дата окончания progress: Продвижение start_date: Дата начала status: Состояние + taxonomies: Таксономии title: Заголовок status: fields: @@ -98,21 +261,50 @@ ru: other: "%{count} итога" home_header: global_status: Состояние общего исполнения + milestones: + title: Этапы + no_results: Нет проектов + root_taxonomies: + title: 'Отображать по:' search: search: Поиск действий show: stats: back_to_resource: Вернуться к итогу + admin: + filters: + results: + status_id_eq: + label: Статус + taxonomies_part_of_contains: + label: Таксономия + tooltips: + deleted_results_info: Невозможно удалить этот результат components: accountability: + actions: + comment: Комментарий name: Отчетность settings: global: + clear_all: Очистить все comments_enabled: Комментарии включены + default_taxonomy: Таксономия по умолчанию + default_taxonomy_help: Выберите, какую таксономию вы хотите показать по умолчанию. Если таксономия не выбрана, результаты будут показаны в виде списка. + define_taxonomy_filters: Пожалуйста, определите фильтры для этого партисипативного пространства перед использованием этой настройки. display_progress_enabled: Показывать ход выполнения + geocoding_enabled: Карты включены intro: Вступление + no_taxonomy_filters_found: Фильтры таксономии не найдены. + taxonomy_filters: Выберите фильтры для компонента + taxonomy_filters_add: Добавить фильтр step: comments_blocked: Комментарии отключены + visualization: Визуализация + download_your_data: + show: + result_comments: Экспорт комментариев результатов + results: Экспорт результатов events: accountability: proposal_linked: @@ -123,9 +315,50 @@ ru: result_progress_updated: email_intro: 'Результат "%{resource_title}", который включает предложение "%{proposal_title}", теперь завершено на %{progress}%. Вы можете увидеть его на этой странице:' email_outro: Вы получили это уведомление, потому что вы следите за "%{proposal_title}", и это предложение включено в результат "%{resource_title}". Вы можете прекратить получение уведомлений, перейдя по предыдущей ссылке. + email_subject: Обновление прогресса %{resource_title} notification_title: Результат %{resource_title}, который включает предложение %{proposal_title}, теперь %{progress}% завершен. + open_data: + help: + result_comments: + alignment: Если этот комментарий был за, против или нейтральный + author: Имя участника, который написал этот комментарий + body: Сам комментарий + commentable_id: Уникальный идентификатор комментария + commentable_type: Тип комментируемого элемента (результат, предложение и т.д.) + created_at: Дата создания комментария + depth: Позиция комментария в цепочке обсуждения (прямой ответ или ответ на ответ) + id: Идентификатор этого комментария + locale: Язык, при котором участник оставлял этот комментарий + root_commentable_url: URL ресурса, который связан с этим комментарием + results: + address: Адрес результата (если есть) + children_count: Количество результатов дочернего процесса + comments_count: Количество комментариев к этому результату + component: Компонент, к которому относится результат + created_at: Дата создания результата + description: Описание результата + end_date: Дата окончания выполнения результата + id: Уникальный идентификатор результата + latitude: Географическая широта результата в случае, если он имеет физическое расположение + longitude: Географическая долгота результата в случае, если он имеет физическое местоположение + parent: Родительский результат (если есть) результата + progress: Процент выполнения результата + proposal_urls: URL-адреса предложений, которые включены в этот результат + reference: Уникальная ссылка на результат + start_date: Дата начала выполнения результата + status: Текущий статус этого результата + taxonomies: Таксономии результата + title: Заголовок результата + updated_at: Последняя дата обновления результата + url: URL-адрес, где можно найти этот результат + participatory_spaces: + highlighted_results: + see_all: Посмотреть все результаты resource_links: included_projects: result_project: Проекты, включенные в эти итоги included_proposals: result_proposal: Предложения, включенные в этот итог + statistics: + results_count: Результаты + results_count_tooltip: Количество решений или итогов, выработанных в рамках данного пространства. diff --git a/decidim-accountability/config/locales/sk.yml b/decidim-accountability/config/locales/sk.yml index 5065721165308..2810dcb4c7c4a 100644 --- a/decidim-accountability/config/locales/sk.yml +++ b/decidim-accountability/config/locales/sk.yml @@ -13,7 +13,7 @@ sk: description: Popis end_date: Koniec progress: Postup - start_date: Začiatok + start_date: Začiatok subresults: Čiastkové výsledky title: Názov updated_at: Aktualizované @@ -268,7 +268,7 @@ sk: end_date: Koniec id: ID progress: Postup - start_date: Začiatok + start_date: Začiatok status: Stav taxonomies: Taxonómie title: Názov @@ -315,7 +315,6 @@ sk: global: clear_all: Vymazať všetko comments_enabled: Komentáre povolené - comments_max_length: Maximálna dĺžka komentárov (Ponechajte 0 pre predvolenú hodnotu) default_taxonomy: Predvolená taxonómia default_taxonomy_help: Vyberte, ktorú taxonómiu chcete predvolene zobraziť. Ak nie je vybraná žiadna taxonómia, výsledky sa zobrazia vo formáte zoznamu. define_taxonomy_filters: Pred použitím tohto nastavenia definujte nejaké filtre pre tento participatívny priestor. diff --git a/decidim-accountability/config/locales/sq-AL.yml b/decidim-accountability/config/locales/sq-AL.yml index 76e751f7c074e..4871b3fe797e4 100644 --- a/decidim-accountability/config/locales/sq-AL.yml +++ b/decidim-accountability/config/locales/sq-AL.yml @@ -162,7 +162,6 @@ sq: settings: global: comments_enabled: Komentet e aktivizuara - comments_max_length: Madhësia maks. e komenteve display_progress_enabled: Shfaq ecurinë intro: Hyrje step: diff --git a/decidim-accountability/config/locales/sv.yml b/decidim-accountability/config/locales/sv.yml index ef0fbdbcd9c73..cd7937cec716a 100644 --- a/decidim-accountability/config/locales/sv.yml +++ b/decidim-accountability/config/locales/sv.yml @@ -33,7 +33,7 @@ sv: budget_text: Resultatet %{link} har tagits med meetings_ids: 'Diskuterades på det här mötet: %{link}' project_ids: 'Lades till i det här projektet: %{link}' - proposal_ids: 'Lades till i det här förslaget: %{link}' + proposal_ids: 'Förslaget som röstades fram: %{link}' text: 'Lades till i det här resultatet: %{link}' decidim/accountability/result: one: Resultat @@ -302,7 +302,6 @@ sv: global: clear_all: Rensa alla comments_enabled: Aktivera kommentarer - comments_max_length: Maximal kommentarslängd (ange 0 för att använda standardvärdet) default_taxonomy: Standardkategori default_taxonomy_help: Välj vilka kategorier du vill visa som standard. Om ingen kategori är vald, kommer resultatet visas som en lista. define_taxonomy_filters: Ställ in filter innan du använder den här inställningen. diff --git a/decidim-accountability/config/locales/th-TH.yml b/decidim-accountability/config/locales/th-TH.yml index ba4ceb24cb5aa..4c72bfe0088bb 100644 --- a/decidim-accountability/config/locales/th-TH.yml +++ b/decidim-accountability/config/locales/th-TH.yml @@ -110,7 +110,6 @@ th: settings: global: comments_enabled: เปิดใช้งานความคิดเห็นแล้ว - comments_max_length: ความคิดเห็นความยาวสูงสุด (ปล่อยให้ 0 เป็นค่าเริ่มต้น) display_progress_enabled: แสดงความคืบหน้า intro: คำแนะนำ step: diff --git a/decidim-accountability/config/locales/tr-TR.yml b/decidim-accountability/config/locales/tr-TR.yml index d967ab9add062..39fe34d8d7a2c 100644 --- a/decidim-accountability/config/locales/tr-TR.yml +++ b/decidim-accountability/config/locales/tr-TR.yml @@ -301,7 +301,6 @@ tr: global: clear_all: Tümünü sil comments_enabled: Yorumlar etkin - comments_max_length: Maksimum yorum uzunluğu (Varsayılan değer için 0 bırakın) default_taxonomy: Varsayılan sınıflandırma default_taxonomy_help: Varsayılan olarak hangi sınıflandırmayı göstermek istediğinizi seçin. Eğer herhangi bir sınıflandırma seçilmezse, sonuçlar liste biçiminde gösterilecektir. define_taxonomy_filters: Bu ayarı kullanmadan önce lütfen bu katılımcı alan için bazı filtreler tanımlayın. diff --git a/decidim-accountability/config/locales/zh-CN.yml b/decidim-accountability/config/locales/zh-CN.yml index ea49bc27cabc4..ef0488296af82 100644 --- a/decidim-accountability/config/locales/zh-CN.yml +++ b/decidim-accountability/config/locales/zh-CN.yml @@ -109,7 +109,6 @@ zh-CN: settings: global: comments_enabled: 评论已启用 - comments_max_length: 评论最大长度 (默认值留0) display_progress_enabled: 显示进度 intro: 简介 step: diff --git a/decidim-accountability/config/locales/zh-TW.yml b/decidim-accountability/config/locales/zh-TW.yml index 5ea94b37309ba..04bb6c3692bac 100644 --- a/decidim-accountability/config/locales/zh-TW.yml +++ b/decidim-accountability/config/locales/zh-TW.yml @@ -153,7 +153,6 @@ zh-TW: settings: global: comments_enabled: 已啟用留言 - comments_max_length: 留言字數上限 (0 表示使用預設) display_progress_enabled: 顯示進度 intro: 介紹 step: diff --git a/decidim-accountability/lib/decidim/accountability/component.rb b/decidim-accountability/lib/decidim/accountability/component.rb index 027802b101c59..3c48d9b8be5d9 100644 --- a/decidim-accountability/lib/decidim/accountability/component.rb +++ b/decidim-accountability/lib/decidim/accountability/component.rb @@ -51,7 +51,7 @@ icon_name: "chat-1-line", tooltip_key: "comments_count", tag: :comments do |components, _start_at, _end_at| - Decidim::Accountability::Result.where(component: components).count + Decidim::Accountability::Result.where(component: components).sum(:comments_count) end component.settings(:step) do |settings| diff --git a/decidim-accountability/lib/decidim/accountability/version.rb b/decidim-accountability/lib/decidim/accountability/version.rb index 27c55e8079ab1..2ae5c1e1eff32 100644 --- a/decidim-accountability/lib/decidim/accountability/version.rb +++ b/decidim-accountability/lib/decidim/accountability/version.rb @@ -4,7 +4,7 @@ module Decidim # This holds decidim-accountability version. module Accountability def self.version - "0.31.4" + "0.31.7" end end end diff --git a/decidim-accountability/spec/forms/admin/status_form_spec.rb b/decidim-accountability/spec/forms/admin/status_form_spec.rb index fbf672487e3aa..a7be1b8be3561 100644 --- a/decidim-accountability/spec/forms/admin/status_form_spec.rb +++ b/decidim-accountability/spec/forms/admin/status_form_spec.rb @@ -46,5 +46,29 @@ module Decidim::Accountability it { is_expected.not_to be_valid } end + + describe "when progress is negative" do + let(:progress) { -12 } + + it { is_expected.not_to be_valid } + end + + describe "when progress is greater than 100" do + let(:progress) { 999 } + + it { is_expected.not_to be_valid } + end + + describe "when progress is between 0 and 100" do + let(:progress) { (0..100).to_a.sample } + + it { is_expected.to be_valid } + end + + describe "when progress is empty" do + let(:progress) { nil } + + it { is_expected.to be_valid } + end end end diff --git a/decidim-accountability/spec/lib/decidim/accountability/component_spec.rb b/decidim-accountability/spec/lib/decidim/accountability/component_spec.rb index bde48b30bc2d3..53b2e8c39869e 100644 --- a/decidim-accountability/spec/lib/decidim/accountability/component_spec.rb +++ b/decidim-accountability/spec/lib/decidim/accountability/component_spec.rb @@ -7,6 +7,33 @@ let(:organization) { component.organization } let!(:current_user) { create(:user, :confirmed, :admin, organization:) } + describe "stats" do + subject { current_stat[1][:data] } + + let(:raw_stats) do + Decidim.component_manifests.map do |component_manifest| + component_manifest.stats.filter(name: stats_name).with_context(component).flat_map { |name, data| [component_manifest.name, name, data] } + end + end + + let(:stats) { raw_stats.select { |stat| stat[0] == :accountability } } + let!(:result) { create(:result, component:) } + let(:current_stat) { stats.find { |stat| stat[1][:name] == stats_name } } + + describe "comments_count" do + let(:stats_name) { :comments_count } + + before do + create_list(:comment, 3, commentable: result) + end + + it "counts the comments" do + expect(Decidim::Comments::Comment.count).to eq 3 + expect(subject).to eq 3 + end + end + end + describe "on edit", type: :system do let(:edit_component_path) do Decidim::EngineRouter.admin_proxy(component.participatory_space).edit_component_path(component.id) diff --git a/decidim-accountability/spec/shared/manage_results_bulk_actions_examples.rb b/decidim-accountability/spec/shared/manage_results_bulk_actions_examples.rb index 950236f2ae50d..6f7305720e344 100644 --- a/decidim-accountability/spec/shared/manage_results_bulk_actions_examples.rb +++ b/decidim-accountability/spec/shared/manage_results_bulk_actions_examples.rb @@ -37,6 +37,21 @@ expect(page).to have_selector(:link_or_button, "Change status") expect(page).to have_selector(:link_or_button, "Change dates") end + + context "when there are no statuses" do + before do + Decidim::Accountability::Status.where(component: current_component).destroy_all + visit current_path + page.find_by_id("results_bulk").set(true) + click_on "Actions" + end + + it "does not show the change status option" do + expect(page).to have_selector(:link_or_button, "Change taxonomies") + expect(page).to have_no_selector(:link_or_button, "Change status") + expect(page).to have_selector(:link_or_button, "Change dates") + end + end end context "when change taxonomies is selected from actions dropdown" do diff --git a/decidim-accountability/spec/shared/manage_results_examples.rb b/decidim-accountability/spec/shared/manage_results_examples.rb index e4fead52c5839..b2bb665449e25 100644 --- a/decidim-accountability/spec/shared/manage_results_examples.rb +++ b/decidim-accountability/spec/shared/manage_results_examples.rb @@ -9,6 +9,27 @@ it_behaves_like "having a rich text editor", "new_result", "full" end + context "when there are statuses" do + before do + click_on "New result" + end + + it "displays the status select" do + expect(page).to have_select "result_decidim_accountability_status_id" + end + end + + context "when there are no statuses" do + before do + Decidim::Accountability::Status.where(component: current_component).destroy_all + click_on "New result" + end + + it "does not display the status select" do + expect(page).to have_no_select "result_decidim_accountability_status_id" + end + end + context "when the proposal module is not installed" do before do allow(Decidim).to receive(:module_installed?).and_return(false) diff --git a/decidim-accountability/spec/types/integration_schema_spec.rb b/decidim-accountability/spec/types/integration_schema_spec.rb index 312da1eeaa58d..725e14629a500 100644 --- a/decidim-accountability/spec/types/integration_schema_spec.rb +++ b/decidim-accountability/spec/types/integration_schema_spec.rb @@ -156,7 +156,7 @@ ] }, "url" => Decidim::EngineRouter.main_proxy(current_component).root_url, - "weight" => 0 + "weight" => current_component.weight } end let!(:current_component) { create(:accountability_component, participatory_space: participatory_process) } diff --git a/decidim-admin/app/commands/decidim/admin/create_newsletter.rb b/decidim-admin/app/commands/decidim/admin/create_newsletter.rb index abd9fd5a4f1b4..66fdc7bec55b0 100644 --- a/decidim-admin/app/commands/decidim/admin/create_newsletter.rb +++ b/decidim-admin/app/commands/decidim/admin/create_newsletter.rb @@ -31,7 +31,7 @@ def run_after_hooks @content_block = content_block end on(:invalid) do - raise "There was a problem persisting the changes to the content block" + raise Decidim::Commands::HookError, "There was a problem persisting the changes to the content block" end end end diff --git a/decidim-admin/app/commands/decidim/admin/create_taxonomy_filter.rb b/decidim-admin/app/commands/decidim/admin/create_taxonomy_filter.rb index 0e5b373d18d17..d89ac3721d3ca 100644 --- a/decidim-admin/app/commands/decidim/admin/create_taxonomy_filter.rb +++ b/decidim-admin/app/commands/decidim/admin/create_taxonomy_filter.rb @@ -5,20 +5,34 @@ module Admin # A command with all the business logic to create a new taxonomy filter in the # system. class CreateTaxonomyFilter < Decidim::Commands::CreateResource - fetch_form_attributes :root_taxonomy_id, :filter_items, :internal_name, :name, :participatory_space_manifests + fetch_form_attributes :root_taxonomy_id, :internal_name, :name, :participatory_space_manifests protected def resource_class = Decidim::TaxonomyFilter + def run_after_hooks + create_filter_items! + end + def extra_params { extra: { taxonomy_name: form.root_taxonomy.name, - filter_items_count: form.filter_items.count + filter_items_count: selected_taxonomy_item_ids.size } } end + + private + + def create_filter_items! + selected_taxonomy_item_ids.each { |taxonomy_item_id| resource.filter_items.create!(taxonomy_item_id:) } + end + + def selected_taxonomy_item_ids + form.taxonomy_items.map(&:to_i).uniq + end end end end diff --git a/decidim-admin/app/commands/decidim/admin/update_taxonomy_filter.rb b/decidim-admin/app/commands/decidim/admin/update_taxonomy_filter.rb index 03f8b1f485749..0f34371017192 100644 --- a/decidim-admin/app/commands/decidim/admin/update_taxonomy_filter.rb +++ b/decidim-admin/app/commands/decidim/admin/update_taxonomy_filter.rb @@ -2,27 +2,45 @@ module Decidim module Admin - # A command with all the business logic to create a new taxonomy filter in the - # system. + # A command with all the business logic to update an existing taxonomy filter + # in the system. class UpdateTaxonomyFilter < Decidim::Commands::UpdateResource - fetch_form_attributes :filter_items, :internal_name, :name, :participatory_space_manifests + fetch_form_attributes :internal_name, :name, :participatory_space_manifests protected def resource_class = Decidim::TaxonomyFilter - def run_before_hooks - resource.filter_items.destroy_all + def run_after_hooks + sync_filter_items! end def extra_params { extra: { taxonomy_name: resource.root_taxonomy.name, - filter_items_count: form.filter_items.count + filter_items_count: selected_taxonomy_item_ids.size } } end + + private + + def sync_filter_items! + removed_ids = current_taxonomy_item_ids - selected_taxonomy_item_ids + added_ids = selected_taxonomy_item_ids - current_taxonomy_item_ids + + resource.filter_items.where(taxonomy_item_id: removed_ids).destroy_all if removed_ids.any? + added_ids.each { |taxonomy_item_id| resource.filter_items.create!(taxonomy_item_id:) } + end + + def current_taxonomy_item_ids + resource.filter_items.pluck(:taxonomy_item_id) + end + + def selected_taxonomy_item_ids + form.taxonomy_items.map(&:to_i).uniq + end end end end diff --git a/decidim-admin/app/controllers/decidim/admin/block_user_controller.rb b/decidim-admin/app/controllers/decidim/admin/block_user_controller.rb index 4cc2cf264069e..ccb88a7acb4e6 100644 --- a/decidim-admin/app/controllers/decidim/admin/block_user_controller.rb +++ b/decidim-admin/app/controllers/decidim/admin/block_user_controller.rb @@ -10,6 +10,8 @@ class BlockUserController < Decidim::Admin::ApplicationController def new enforce_permission_to :block, :admin_user + return redirect_to(officializations_path, alert: I18n.t("officializations.block.no_user", scope: "decidim.admin")) unless user + @form = form(BlockUserForm).from_model(user) @form.hide = params[:hide] || false end diff --git a/decidim-admin/app/controllers/decidim/admin/newsletters_controller.rb b/decidim-admin/app/controllers/decidim/admin/newsletters_controller.rb index fbdc80e89ff86..a8409768eeb79 100644 --- a/decidim-admin/app/controllers/decidim/admin/newsletters_controller.rb +++ b/decidim-admin/app/controllers/decidim/admin/newsletters_controller.rb @@ -55,6 +55,7 @@ def create on(:invalid) do |newsletter| @newsletter = newsletter + @form.images = content_block.images_container flash.now[:error] = I18n.t("newsletters.create.error", scope: "decidim.admin") render action: :new, status: :unprocessable_entity end diff --git a/decidim-admin/app/controllers/decidim/admin/officializations_controller.rb b/decidim-admin/app/controllers/decidim/admin/officializations_controller.rb index 6d80a4ba60bc2..dd9158819296d 100644 --- a/decidim-admin/app/controllers/decidim/admin/officializations_controller.rb +++ b/decidim-admin/app/controllers/decidim/admin/officializations_controller.rb @@ -22,6 +22,8 @@ def index def new enforce_permission_to :create, :officialization + return redirect_to(officializations_path, alert: I18n.t("officializations.create.no_user_found", scope: "decidim.admin")) unless user + @form = form(OfficializationForm).from_model(user) end diff --git a/decidim-admin/app/forms/decidim/admin/taxonomy_filter_form.rb b/decidim-admin/app/forms/decidim/admin/taxonomy_filter_form.rb index a0eacb5de4632..54d50dc7a02a5 100644 --- a/decidim-admin/app/forms/decidim/admin/taxonomy_filter_form.rb +++ b/decidim-admin/app/forms/decidim/admin/taxonomy_filter_form.rb @@ -43,7 +43,7 @@ def filter_items def items_collection return [] unless root_taxonomy - @items_collection ||= map_items_collection(root_taxonomy) + @items_collection ||= build_items_collection end def root_taxonomy @@ -61,22 +61,24 @@ def available_participatory_space_manifests private - def map_items_collection(taxonomy) - taxonomy.children.map do |item| + def build_items_collection + children_by_parent_id = root_taxonomy.all_children.group_by(&:parent_id) + build_subtree(root_taxonomy.id, children_by_parent_id) + end + + def build_subtree(parent_id, children_by_parent_id) + Array(children_by_parent_id[parent_id]).map do |item| Item.new( name: translated_attribute(item.name), value: item.id, - children: map_items_collection(item) + children: build_subtree(item.id, children_by_parent_id) ) end end def valid_taxonomy_items - return if taxonomy_items.all? do |item| - next unless root_taxonomy - - root_taxonomy.all_children.map(&:id).include?(item.to_i) - end + valid_ids = root_taxonomy ? root_taxonomy.all_children.pluck(:id).to_set : Set.new + return if taxonomy_items.all? { |item| valid_ids.include?(item.to_i) } errors.add(:taxonomy_items, :invalid) end diff --git a/decidim-admin/app/packs/stylesheets/decidim/admin/application.scss b/decidim-admin/app/packs/stylesheets/decidim/admin/application.scss index 359d6224a1deb..99924a3cac2d6 100755 --- a/decidim-admin/app/packs/stylesheets/decidim/admin/application.scss +++ b/decidim-admin/app/packs/stylesheets/decidim/admin/application.scss @@ -24,7 +24,7 @@ @use "stylesheets/decidim/admin/datepicker"; @use "stylesheets/decidim/admin/minimap"; @use "stylesheets/decidim/admin/proposal_status"; -@use "stylesheets/decidim/tribute"; +@use "stylesheets/decidim/editor_suggestions"; :root { --primary: #e02d2d; diff --git a/decidim-admin/app/views/decidim/admin/attachment_collections/index.html.erb b/decidim-admin/app/views/decidim/admin/attachment_collections/index.html.erb index 8a759b079324e..bae1c8c885b68 100644 --- a/decidim-admin/app/views/decidim/admin/attachment_collections/index.html.erb +++ b/decidim-admin/app/views/decidim/admin/attachment_collections/index.html.erb @@ -51,7 +51,7 @@ <% end %> <% else %> + +
      + <%= + form.select( + :max_choices, + (2..question.number_of_options), + { include_blank: t("any", scope: "decidim.forms.admin.questionnaires.question") }, + disabled: !editable + ) + %> +
      diff --git a/decidim-elections/app/views/decidim/elections/census_checks/show.html.erb b/decidim-elections/app/views/decidim/elections/census_checks/show.html.erb new file mode 100644 index 0000000000000..7bdeb45e33781 --- /dev/null +++ b/decidim-elections/app/views/decidim/elections/census_checks/show.html.erb @@ -0,0 +1,8 @@ + diff --git a/decidim-elections/app/views/decidim/elections/elections/_election_aside.html.erb b/decidim-elections/app/views/decidim/elections/elections/_election_aside.html.erb index c45ef479826c3..91442a6932dc0 100644 --- a/decidim-elections/app/views/decidim/elections/elections/_election_aside.html.erb +++ b/decidim-elections/app/views/decidim/elections/elections/_election_aside.html.erb @@ -9,6 +9,14 @@ <%= t("decidim.elections.elections.show.voted") %> <% end %> + <% elsif allowed_to? :create, :census_check, election: election %> + <%= link_to t("decidim.elections.elections.show.check_census_button"), + new_election_census_check_path(election), + class: "button button__lg button__secondary #{"hidden" if election.published? && !election.allow_census_check_before_start}", + data: election.published? ? { census_check_button: true, census_check_url: election_path(election, format: :json) } : {} %> +
      " data-census-check-explanation="<%= election.published? %>"> + <%= t("decidim.elections.elections.show.check_census_explanation") %> +
      <% end %> diff --git a/decidim-elections/app/views/decidim/elections/elections/_questions.html.erb b/decidim-elections/app/views/decidim/elections/elections/_questions.html.erb index 9cbd2fea2b1fa..9624af4cdbdd3 100644 --- a/decidim-elections/app/views/decidim/elections/elections/_questions.html.erb +++ b/decidim-elections/app/views/decidim/elections/elections/_questions.html.erb @@ -12,7 +12,10 @@ -
      +
      <% question.response_options.each do |option| %> -
      diff --git a/decidim-elections/app/views/layouts/decidim/election_booth.html.erb b/decidim-elections/app/views/layouts/decidim/election_booth.html.erb index d2758a4c79248..96eff8c954680 100644 --- a/decidim-elections/app/views/layouts/decidim/election_booth.html.erb +++ b/decidim-elections/app/views/layouts/decidim/election_booth.html.erb @@ -12,7 +12,7 @@
      -
      +
      <%= render partial: "layouts/decidim/election_votes_header" %>
      @@ -22,7 +22,7 @@ <%= display_flash_messages %>
      <% end %> -
      +
      <%= yield %>
      diff --git a/decidim-elections/config/locales/ca.yml b/decidim-elections/config/locales/ca.yml index ea253c0ea784a..8fc7fedaa9735 100644 --- a/decidim-elections/config/locales/ca.yml +++ b/decidim-elections/config/locales/ca.yml @@ -2,6 +2,8 @@ ca: activemodel: attributes: + elections_question: + max_choices: Nombre màxim d'opcions token_csv: file: Arxiu remove_all: Eliminar totes les dades del cens actual @@ -101,6 +103,7 @@ ca: start_question_button: Activar la votació title: Resultats status: + allow_census_check_before_start: Permetre que les usuàries comprovin si poden votar abans que comenci l'elecció census: 'Cens:' results_availability: after_end: Resultats disponibles després de la finalització de les eleccions @@ -179,14 +182,19 @@ ca: unknown: Estat desconegut admin_log: election: - create: "%{user_name} ha creat l'elecció \"%{resource_name}\" a %{space_name}" - publish: "%{user_name} ha publicat l'elecció \"%{resource_name}\" a %{space_name}" - restore: "%{user_name} ha restaurat l'elecció \"%{resource_name}\" a %{space_name}" - soft_delete: "%{user_name} ha mogut l'elecció \"%{resource_name}\" de %{space_name} a la paperera" - unpublish: "%{user_name} ha despublicat l'elecció \"%{resource_name}\" a %{space_name}" - update: "%{user_name} ha actualitzat l'elecció \"%{resource_name}\" a %{space_name}" + create: '%{user_name} ha creat l''elecció "%{resource_name}" a %{space_name}' + publish: '%{user_name} ha publicat l''elecció "%{resource_name}" a %{space_name}' + restore: '%{user_name} ha restaurat l''elecció "%{resource_name}" a %{space_name}' + soft_delete: '%{user_name} ha mogut l''elecció "%{resource_name}" de %{space_name} a la paperera' + unpublish: '%{user_name} ha despublicat l''elecció "%{resource_name}" a %{space_name}' + update: '%{user_name} ha actualitzat l''elecció "%{resource_name}" a %{space_name}' question: - update: "%{user_name} va actualitzar les preguntes de l'elecció \"%{resource_name}\"" + update: '%{user_name} va actualitzar les preguntes de l''elecció "%{resource_name}"' + census_checks: + show: + description: Això vol dir que, un cop comenci l'elecció, hi podràs votar. + exit_button: Sortir de la comprovació del cens + title: T'has verificat correctament censuses: census_ready_html: S'han carregat les dades censals i estan a punt per utilitzar-les a l'elecció "%{election_title}". census_size_html: @@ -195,8 +203,9 @@ ca: internal_users: already_have_an_account?: Ja tens un compte? are_you_new?: Encara no ets participant? - info_html: | - Pots restringir la participació en l'elecció a les participants que tinguin una autorització.
      Tingues en compte que les participants obtenir l'autorització seleccionada per poder votar. Si deixes totes les caselles de verificació buides, qualsevol persona registrada podrà votar. + info_html: 'Pots restringir la participació en l''elecció a les participants que tinguin una autorització.
      Tingues en compte que les participants obtenir l''autorització seleccionada per poder votar. Si deixes totes les caselles de verificació buides, qualsevol persona registrada podrà votar. + + ' internal_type_title: Autoritzacions addicionals necessàries per votar (opcional) label: Participants registrades (dinàmic) sign_in_description: Inicia la teva sessió per a votar en aquestes eleccions @@ -212,8 +221,9 @@ ca: email;token user@example.org;123456 user2@example.org;ABCXYZ - info_html: | - Ha de ser un arxiu en format CSV amb només dues columnes, una amb l'adreça de correu electrònic i una altra amb el valor de l'autenticador (token). Els camps han d'estar separats amb punt i coma (;). + info_html: 'Ha de ser un arxiu en format CSV amb només dues columnes, una amb l''adreça de correu electrònic i una altra amb el valor de l''autenticador (token). Els camps han d''estar separats amb punt i coma (;). + + ' label: Participants no registrats amb autentificador/token (fixat) remove_before_upload: Si vols pujar un nou cens, primer has d'eliminar el que ja existeix. upload_file: Puja arxiu @@ -249,13 +259,15 @@ ca: title: Preguntes de l'elecció show: active_voting_until: 'Votació activa fins: %{end_date}' + check_census_button: Comprovar si puc votar + check_census_explanation: Aquesta elecció encara no ha començat, però pots comprovar si estàs inclosa al cens. edit_vote_button: Edita el vot vote_button: Votar voted: Ja has votat. Pots tornar a votar, això esborrarà el teu vot anterior i, només es comptabilitzarà la teva última votació. votes_count: one: 1 vot other: "%{count} vots" - voting_began: 'La votació es va iniciar el %{start_date}' + voting_began: La votació es va iniciar el %{start_date} vote_results: subtitle: after_end: Les eleccions han finalitzat. Ara pot veure'n els resultats. @@ -308,6 +320,9 @@ ca: question: back: Tornar cast_vote: Enviar el vot + max_choices: 'Màxim d''opcions: %{count}' + max_choices_alert: Has seleccionat massa opcions. Si us plau, desselecciona'n algunes per continuar. + max_choices_exceeded: No pots seleccionar més de %{max} opcions. Torna enrere i ajusta la selecció. next: Següent receipt: description: Pots tornar a votar en qualsevol moment mentre el període de votació estigui obert. El teu vot anterior serà substituït pel nou. diff --git a/decidim-elections/config/locales/cs.yml b/decidim-elections/config/locales/cs.yml index 10b75288c1d82..3ab3df860cef3 100644 --- a/decidim-elections/config/locales/cs.yml +++ b/decidim-elections/config/locales/cs.yml @@ -34,15 +34,18 @@ cs: elections: actions: confirm_delete_election: Opravdu chcete odstranit tuto volbu? + confirm_unpublish_election: Opravdu chcete zrušit zveřejnění těchto voleb? deleted_election_info: Smazané volby nejsou zobrazeny v seznamu. Můžete je zobrazit kliknutím na tlačítko níže. edit: Upravit volby new: Nové volby preview: Náhled title: Akce + view: Zobrazit volby view_deleted_elections: Zobrazit odstraněné volby admin: census: edit: + choose_census: Vyberte typ seznamu voličů, který chcete použít pro tyto volby created_at: Vytvořeno v identifier: Identifikátor uživatele dashboard: @@ -113,6 +116,8 @@ cs: publish: Publikovat results_availability: after_end: Po ukončení voleb + per_question: Otázka po otázce + per_question_help: ručně zpracovat hlasování a publikovat výsledky pro každou otázku real_time: V reálném čase title: Dostupnost výsledků save: Uložit a pokračovat @@ -142,9 +147,20 @@ cs: form_description: Otázka musí mít alespoň dvě odpovědi, aby mohla jít k dalšímu kroku. update: invalid: Při aktualizaci otázek došlo k chybě. + success: Otázky byly úspěšně aktualizovány. statuses: + enable_voting: + invalid: Při povolování hlasování došlo k chybě. + success: Hlasování bylo úspěšně aktivováno. + end: + invalid: Vyskytl se problém s ukončením voleb. + success: Volba byla úspěšně ukončena. publish_results: invalid: Při publikování výsledků došlo k chybě. + success: Výsledky byly úspěšně zveřejněny. + start: + invalid: Vyskytl se problém při zahájení voleb. + success: Volba byla úspěšně zahájena. unknown: Neznámý stav admin_log: election: @@ -244,12 +260,14 @@ cs: failed: Vaši identitu nelze ověřit. Zkontrolujte zadané informace a zkuste to znovu. form_title: Ověřte svou identitu confirm: + cast_vote: Odevzdat hlas edit_vote: Upravte svůj hlas not_answered: Na tuto otázku jste neodpověděl. title: Potvrďte svůj hlas not_authorized: V těchto volbách nemáte oprávnění volit. question: back: Zpět + cast_vote: Odevzdat hlas next: Další statistics: elections_count: Volby diff --git a/decidim-elections/config/locales/en.yml b/decidim-elections/config/locales/en.yml index bc3f4d916f8c9..fdeafa288881d 100644 --- a/decidim-elections/config/locales/en.yml +++ b/decidim-elections/config/locales/en.yml @@ -2,6 +2,8 @@ en: activemodel: attributes: + elections_question: + max_choices: Maximum number of choices token_csv: file: File remove_all: Remove all current census data @@ -101,6 +103,7 @@ en: start_question_button: Enable voting title: Results status: + allow_census_check_before_start: Allow users to check if they can vote before the election starts census: 'Census:' results_availability: after_end: Results available after the election ends @@ -187,6 +190,11 @@ en: update: "%{user_name} updated the %{resource_name} election in %{space_name}" question: update: "%{user_name} updated the questions of the %{resource_name} election" + census_checks: + show: + description: This means that, once the election starts, you can vote in it. + exit_button: Exit the census check + title: You have been successfully verified censuses: census_ready_html: The census data is uploaded and prepared for its use in the %{election_title} election. census_size_html: @@ -251,6 +259,8 @@ en: title: Election questions show: active_voting_until: 'Active voting until: %{end_date}' + check_census_button: Check if I can vote + check_census_explanation: This election has not started yet, but you can check if you are included in the census. edit_vote_button: Edit vote vote_button: Vote voted: You have already voted. You can vote again, only your last vote will be counted. @@ -310,6 +320,9 @@ en: question: back: Back cast_vote: Cast vote + max_choices: 'Max choices: %{count}' + max_choices_alert: You have selected too many options. Please deselect some to continue. + max_choices_exceeded: You cannot select more than %{max} options. Please go back and adjust your selection. next: Next receipt: description: You can vote again at any time while the voting period is open. Your previous vote will be overwritten by the new one. diff --git a/decidim-elections/config/locales/es.yml b/decidim-elections/config/locales/es.yml index e4f4064882c2a..d6a036ec22b3d 100644 --- a/decidim-elections/config/locales/es.yml +++ b/decidim-elections/config/locales/es.yml @@ -2,6 +2,8 @@ es: activemodel: attributes: + elections_question: + max_choices: Número máximo de opciones token_csv: file: Archivo remove_all: Eliminar todos los datos del censo actual @@ -35,8 +37,8 @@ es: announcement: Aviso elections: actions: - confirm_delete_election: '¿Seguro que quieres eliminar esta elección?' - confirm_unpublish_election: '¿Seguro que quieres eliminar esta elección?' + confirm_delete_election: "¿Seguro que quieres eliminar esta elección?" + confirm_unpublish_election: "¿Seguro que quieres eliminar esta elección?" deleted_election_info: Las elecciones eliminadas no se muestran en la lista. Puedes verlas haciendo clic en el botón "Ver las elecciones eliminadas" que encontrarás más abajo. edit: Editar la elección new: Nueva elección @@ -76,7 +78,7 @@ es: results: Disponibilidad de los resultados title: Título title: Principal - publish_confirm: '¿Seguro que quieres publicar esta elección?' + publish_confirm: "¿Seguro que quieres publicar esta elección?" questions: labels: answers: Respuestas @@ -101,6 +103,7 @@ es: start_question_button: Activar la votación title: Resultados status: + allow_census_check_before_start: Permitir que las usuarias comprueben si pueden votar antes de que empiece la elección census: 'Censo:' results_availability: after_end: Resultados disponibles tras la finalización de las elecciones @@ -154,7 +157,7 @@ es: questions: edit_questions: new_question: Nueva pregunta - remove_question_confirm: '¿Está seguro de que desea eliminar esta pregunta?' + remove_question_confirm: "¿Está seguro de que desea eliminar esta pregunta?" title: Preguntas form: errors: @@ -179,24 +182,30 @@ es: unknown: Estado desconocido admin_log: election: - create: "%{user_name} ha creado la elección \"%{resource_name}\" en %{space_name}" - publish: "%{user_name} publicó la elección \"%{resource_name}\" en %{space_name}" - restore: "%{user_name} restauró la elección \"%{resource_name}\" en %{space_name}" - soft_delete: "%{user_name} ha movido la elección \"%{resource_name}\" de %{space_name} a la papelera" - unpublish: "%{user_name} despublicó la elección \"%{resource_name}\" en %{space_name}" - update: "%{user_name} ha actualizado la elección \"%{resource_name}\" de %{space_name}" + create: '%{user_name} ha creado la elección "%{resource_name}" en %{space_name}' + publish: '%{user_name} publicó la elección "%{resource_name}" en %{space_name}' + restore: '%{user_name} restauró la elección "%{resource_name}" en %{space_name}' + soft_delete: '%{user_name} ha movido la elección "%{resource_name}" de %{space_name} a la papelera' + unpublish: '%{user_name} despublicó la elección "%{resource_name}" en %{space_name}' + update: '%{user_name} ha actualizado la elección "%{resource_name}" de %{space_name}' question: - update: "%{user_name} actualizó las preguntas de la elección \"%{resource_name}\"" + update: '%{user_name} actualizó las preguntas de la elección "%{resource_name}"' + census_checks: + show: + description: Esto significa que, una vez que empiece la elección, podrás votar en ella. + exit_button: Salir de la comprobación del censo + title: Te has verificado correctamente censuses: census_ready_html: Se han cargado los datos censales y están listos para su uso en la elección "%{election_title}". census_size_html: one: Actualmente hay 1 persona con derecho a voto en estas elecciones (esto podría cambiar en un censo dinámico). other: Actualmente hay %{count} personas con derecho a voto en estas elecciones (esto podría cambiar en un censo dinámico). internal_users: - already_have_an_account?: '¿Ya tienes una cuenta?' - are_you_new?: '¿Aún no eres participante?' - info_html: | - Puedes restringir la participación en la elección a las participantes que tengan una autorización.
      Ten en cuenta que las participantes obtener la autorización seleccionada para poder votar. Si dejas todas las casillas de verificación vacías, cualquier persona registrada podrá votar. + already_have_an_account?: "¿Ya tienes una cuenta?" + are_you_new?: "¿Aún no eres participante?" + info_html: 'Puedes restringir la participación en la elección a las participantes que tengan una autorización.
      Ten en cuenta que las participantes obtener la autorización seleccionada para poder votar. Si dejas todas las casillas de verificación vacías, cualquier persona registrada podrá votar. + + ' internal_type_title: Autorizaciones adicionales requeridas para votar (opcional) label: Participantes registradas (dinámico) sign_in_description: Inicia tu sesión para votar en estas elecciones @@ -212,8 +221,9 @@ es: email;token user@example.org;123456 user2@example.org;ABCXYZ - info_html: | - Debe ser un archivo en formato CSV con solo dos columnas, una con la dirección de correo electrónico y otra con el valor del autentificador (token). Los campos deben estar separados con punto y coma (;). + info_html: 'Debe ser un archivo en formato CSV con solo dos columnas, una con la dirección de correo electrónico y otra con el valor del autentificador (token). Los campos deben estar separados con punto y coma (;). + + ' label: Participantes no registrados con autentificador/token (fijado) remove_before_upload: Si quieres subir un nuevo censo, primero tienes que eliminar el que ya existe. upload_file: Subir un archivo @@ -249,13 +259,15 @@ es: title: Preguntas de la elección show: active_voting_until: 'Votación activa hasta: %{end_date}' + check_census_button: Comprobar si puedo votar + check_census_explanation: Esta elección todavía no ha empezado, pero puedes comprobar si estás incluida en el censo. edit_vote_button: Editar el voto vote_button: Votar voted: Ya has votado. Puedes votar de nuevo, esto borrará tu voto anterior y, solo se contará tu última votación. votes_count: one: 1 voto other: "%{count} votos" - voting_began: 'La votación empezó el %{start_date}' + voting_began: La votación empezó el %{start_date} vote_results: subtitle: after_end: Las elecciones han terminado. Ahora puedes ver los resultados. @@ -308,6 +320,9 @@ es: question: back: Volver cast_vote: Enviar el voto + max_choices: 'Máximo de opciones: %{count}' + max_choices_alert: Has seleccionado demasiadas opciones. Por favor, desmarca algunas para continuar. + max_choices_exceeded: No puedes seleccionar más de %{max} opciones. Vuelve atrás y ajusta tu selección. next: Siguiente receipt: description: Puedes votar de nuevo en cualquier momento mientras el período de votación esté abierto. Tu voto anterior será sustituido por el nuevo. diff --git a/decidim-elections/config/locales/eu.yml b/decidim-elections/config/locales/eu.yml index 175fd7ecc63af..25dded457ca1a 100644 --- a/decidim-elections/config/locales/eu.yml +++ b/decidim-elections/config/locales/eu.yml @@ -42,7 +42,7 @@ eu: new: Beste hauteskunde bat preview: Aurrebistaratu title: Ekintzak - view: Hauteskundeak ikusi + view: Ikusi hauteskundeak view_deleted_elections: Ikusi ezabatutako hauteskundeak admin: census: @@ -188,7 +188,7 @@ eu: question: update: "%{user_name} parte-hartzaileak eguneratu ditu %{resource_name} aukerako galderak" censuses: - census_ready_html: Erroldako datuak kargatuta daude eta prest daude % %{election_title}{@eleccion_title} bozketan erabiltzeko. + census_ready_html: Erroldako datuak kargatuta eta prest daude % {eleccion_title} bozketan erabiltzeko. census_size_html: one: Gaur egun bat pertsona dago hautesleku honetan botoa jasotzeko gai dena (hau errolda dinamiko batean alda daiteke). other: Gaur egun bat pertsona daude hautesleku honetan botoa jasotzeko gai deirnak (hau errolda dinamiko batean alda daiteke). @@ -210,7 +210,7 @@ eu: verify_with_method: Egiaztatu %{name} izenaz token_csv: example: | - e-maila: + e-maila: user@example.org;123456 user2@example.org;ABCXYZ info_html: | @@ -255,7 +255,7 @@ eu: vote_button: Eman babesa voted: Bozkatu duzu. Berriz bozkatu dezakezu, zure azken botoa baino ez da kontuan hartuko. votes_count: - one: 1 boto + one: Boto 1 other: "%{count} boto" voting_began: 'Bozketa hasi zen: %{start_date}' vote_results: @@ -280,7 +280,7 @@ eu: waiting: description: Hemen itxaron dezakezu hurrengo galdera egin arte. Automatikoki hurrengo galderara itzuliko zara prest dagoenean. edit_vote: Zure botoa editau - exit_button: Itxarongelatik irten + exit_button: Irten itxarongelatik title: Hurrengo galderaren zain status: active: Aktibo @@ -313,7 +313,7 @@ eu: next: Hurrengoa receipt: description: Bozkatzeko epea zabalik dagoen bitartean edozein unetan eman daiteke berriro botoa. Zure aurreko botoa berriaz gainidatziko da. - edit_vote: Zure botoa editau + edit_vote: Editatu zure botoa exit_button: Irten bozkatzeko kabinatik title: Zure botoak zuzen eman dira metadata: diff --git a/decidim-elections/config/locales/fr-CA.yml b/decidim-elections/config/locales/fr-CA.yml index a611c8bf34c9d..053a69b5e92db 100644 --- a/decidim-elections/config/locales/fr-CA.yml +++ b/decidim-elections/config/locales/fr-CA.yml @@ -150,6 +150,7 @@ fr-CA: statuses: publish_results: invalid: Un problème est survenu lors de la publication des résultats. + success: Résultats publiés avec succès. unknown: État Inconnu admin_log: election: diff --git a/decidim-elections/config/locales/fr.yml b/decidim-elections/config/locales/fr.yml index 1760bf989b82e..a6ab6702592eb 100644 --- a/decidim-elections/config/locales/fr.yml +++ b/decidim-elections/config/locales/fr.yml @@ -150,6 +150,7 @@ fr: statuses: publish_results: invalid: Un problème est survenu lors de la publication des résultats. + success: Résultats publiés avec succès. unknown: État Inconnu admin_log: election: diff --git a/decidim-elections/db/migrate/20251007113417_add_max_choices_to_decidim_elections_questions.rb b/decidim-elections/db/migrate/20251007113417_add_max_choices_to_decidim_elections_questions.rb new file mode 100644 index 0000000000000..4e2d8aadcac24 --- /dev/null +++ b/decidim-elections/db/migrate/20251007113417_add_max_choices_to_decidim_elections_questions.rb @@ -0,0 +1,7 @@ +# frozen_string_literal: true + +class AddMaxChoicesToDecidimElectionsQuestions < ActiveRecord::Migration[7.2] + def change + add_column :decidim_elections_questions, :max_choices, :integer + end +end diff --git a/decidim-elections/db/migrate/20251020130630_add_allow_census_check_before_start_to_decidim_elections_elections.rb b/decidim-elections/db/migrate/20251020130630_add_allow_census_check_before_start_to_decidim_elections_elections.rb new file mode 100644 index 0000000000000..354a9dba62227 --- /dev/null +++ b/decidim-elections/db/migrate/20251020130630_add_allow_census_check_before_start_to_decidim_elections_elections.rb @@ -0,0 +1,7 @@ +# frozen_string_literal: true + +class AddAllowCensusCheckBeforeStartToDecidimElectionsElections < ActiveRecord::Migration[7.0] + def change + add_column :decidim_elections_elections, :allow_census_check_before_start, :boolean, default: false, null: false + end +end diff --git a/decidim-elections/lib/decidim/elections/admin_engine.rb b/decidim-elections/lib/decidim/elections/admin_engine.rb index c58193fe20f55..edd00079d286c 100644 --- a/decidim-elections/lib/decidim/elections/admin_engine.rb +++ b/decidim-elections/lib/decidim/elections/admin_engine.rb @@ -19,6 +19,7 @@ class AdminEngine < ::Rails::Engine patch :soft_delete patch :restore put :update_status + patch :toggle_census_check get "edit_questions", to: "questions#edit_questions" put "update_questions", to: "questions#update" diff --git a/decidim-elections/lib/decidim/elections/engine.rb b/decidim-elections/lib/decidim/elections/engine.rb index bd94df98ad746..16e6480196764 100644 --- a/decidim-elections/lib/decidim/elections/engine.rb +++ b/decidim-elections/lib/decidim/elections/engine.rb @@ -7,6 +7,7 @@ class Engine < ::Rails::Engine routes do resources :elections, except: [:destroy] do + resource :census_check, only: [:new, :create, :show], controller: :census_checks resources :votes, except: [:edit, :destroy] do collection do get :confirm diff --git a/decidim-elections/lib/decidim/elections/test/factories.rb b/decidim-elections/lib/decidim/elections/test/factories.rb index 50ae7c6bd5cac..c50e57fc0fe00 100644 --- a/decidim-elections/lib/decidim/elections/test/factories.rb +++ b/decidim-elections/lib/decidim/elections/test/factories.rb @@ -69,8 +69,8 @@ end trait :with_questions do - after :create do |election, _evaluator| - create_list(:election_question, 2, :with_response_options, :voting_enabled, election:) + after :create do |election, evaluator| + create_list(:election_question, 2, :with_response_options, :voting_enabled, election:, skip_injection: evaluator.skip_injection) end end @@ -95,8 +95,12 @@ end factory :election_question, class: "Decidim::Elections::Question" do + transient do + skip_injection { false } + end + association :election - body { generate_localized_title(:question_body) } + body { generate_localized_title(:question_body, skip_injection:) } description { generate_localized_description(:question_description) } question_type { "multiple_option" } sequence(:position) { |n| n } diff --git a/decidim-elections/lib/decidim/elections/version.rb b/decidim-elections/lib/decidim/elections/version.rb index 784175cc4af25..22728adc7df45 100644 --- a/decidim-elections/lib/decidim/elections/version.rb +++ b/decidim-elections/lib/decidim/elections/version.rb @@ -3,7 +3,7 @@ module Decidim module Elections def self.version - "0.31.4" + "0.31.7" end end end diff --git a/decidim-elections/spec/commands/decidim/elections/admin/create_election_spec.rb b/decidim-elections/spec/commands/decidim/elections/admin/create_election_spec.rb index 50fcb122e611b..3d3a79f5d45f7 100644 --- a/decidim-elections/spec/commands/decidim/elections/admin/create_election_spec.rb +++ b/decidim-elections/spec/commands/decidim/elections/admin/create_election_spec.rb @@ -17,8 +17,8 @@ module Admin let(:start_at) { 1.day.from_now } let(:end_at) { 2.days.from_now } let(:manual_start) { false } - let(:uploaded_photos) { [] } - let(:photos) { [] } + let(:uploaded_attachments) { [] } + let(:attachments) { [] } let(:invalid) { false } let(:form) do @@ -34,8 +34,8 @@ module Admin end_at:, manual_start:, results_availability: "after_end", - photos:, - add_photos: uploaded_photos + attachments:, + add_attachments: uploaded_attachments ) end diff --git a/decidim-elections/spec/commands/decidim/elections/admin/update_election_spec.rb b/decidim-elections/spec/commands/decidim/elections/admin/update_election_spec.rb index a1431b9a9f919..c4c3c27ac8e45 100644 --- a/decidim-elections/spec/commands/decidim/elections/admin/update_election_spec.rb +++ b/decidim-elections/spec/commands/decidim/elections/admin/update_election_spec.rb @@ -19,8 +19,8 @@ module Admin let(:start_at) { 1.day.from_now } let(:end_at) { 2.days.from_now } let(:manual_start) { false } - let(:uploaded_photos) { [] } - let(:current_photos) { [] } + let(:uploaded_attachments) { [] } + let(:current_attachments) { [] } let(:invalid) { false } let(:form) do @@ -35,8 +35,8 @@ module Admin end_at:, manual_start:, results_availability: "after_end", - photos: current_photos, - add_photos: uploaded_photos + attachments: current_attachments, + add_attachments: uploaded_attachments ) end diff --git a/decidim-elections/spec/commands/decidim/elections/admin/update_questions_spec.rb b/decidim-elections/spec/commands/decidim/elections/admin/update_questions_spec.rb index 4d0d6369ec37b..b1d35796b0490 100644 --- a/decidim-elections/spec/commands/decidim/elections/admin/update_questions_spec.rb +++ b/decidim-elections/spec/commands/decidim/elections/admin/update_questions_spec.rb @@ -190,6 +190,67 @@ module Admin end end + context "when updating max_choices" do + let(:update_max_choices_params) do + { + "questions" => [ + { + "id" => first_question.id, + "body" => first_question.body, + "description" => first_question.description, + "question_type" => "multiple_option", + "max_choices" => 2, + "response_options" => [ + { "id" => first_question_first_option.id, "body" => first_question_first_option.body }, + { "id" => first_question_second_option.id, "body" => first_question_second_option.body } + ] + } + ] + } + end + + let(:form) { Decidim::Elections::Admin::QuestionsForm.from_params(update_max_choices_params).with_context(context_params) } + let(:command) { described_class.new(form, election) } + + it "updates max_choices field" do + command.call + updated = election.reload.questions.find_by(id: first_question.id) + expect(updated.max_choices).to eq(2) + end + end + + context "when adding a new question with max_choices" do + let(:add_with_max_choices_params) do + { + "questions" => [ + { + "body" => { en: "Q with max choices" }, + "description" => { en: "Description" }, + "question_type" => "multiple_option", + "max_choices" => 3, + "response_options" => [ + { "body" => { en: "Option 1" } }, + { "body" => { en: "Option 2" } }, + { "body" => { en: "Option 3" } }, + { "body" => { en: "Option 4" } } + ] + } + ] + } + end + + let(:form) { Decidim::Elections::Admin::QuestionsForm.from_params(add_with_max_choices_params).with_context(context_params) } + let(:command) { described_class.new(form, election) } + + it "creates a new question with max_choices" do + expect { command.call } + .to change { election.reload.questions.count }.by(1) + new_question = election.reload.questions.last + expect(new_question.max_choices).to eq(3) + expect(new_question.response_options.size).to eq(4) + end + end + context "when updating, deleting, and adding at once" do let(:combo_params) do { diff --git a/decidim-elections/spec/controllers/decidim/elections/admin/elections_controller_spec.rb b/decidim-elections/spec/controllers/decidim/elections/admin/elections_controller_spec.rb index 44f37ec769ed2..d864bc6608892 100644 --- a/decidim-elections/spec/controllers/decidim/elections/admin/elections_controller_spec.rb +++ b/decidim-elections/spec/controllers/decidim/elections/admin/elections_controller_spec.rb @@ -176,6 +176,34 @@ def dashboard_path(election) end end + describe "PATCH #toggle_census_check" do + it "updates the setting and returns JSON" do + expect(election.allow_census_check_before_start).to be(false) + + patch :toggle_census_check, params: { id: election.id, allow_census_check_before_start: true }, format: :json + + expect(response).to have_http_status(:ok) + expect(JSON.parse(response.body)).to include( + "success" => true, + "allow_census_check_before_start" => true + ) + expect(election.reload.allow_census_check_before_start).to be(true) + end + + it "returns error on invalid update" do + allow(controller).to receive(:election).and_return(election) + allow(election).to receive(:update!).and_raise(StandardError, "Database error") + + patch :toggle_census_check, params: { id: election.id, allow_census_check_before_start: true }, format: :json + + expect(response).to have_http_status(:unprocessable_entity) + expect(JSON.parse(response.body)).to include( + "success" => false, + "error" => "Database error" + ) + end + end + it_behaves_like "a soft-deletable resource", resource_name: :election, resource_path: :elections_path, diff --git a/decidim-elections/spec/controllers/decidim/elections/census_checks_controller_spec.rb b/decidim-elections/spec/controllers/decidim/elections/census_checks_controller_spec.rb new file mode 100644 index 0000000000000..531918bf2bda7 --- /dev/null +++ b/decidim-elections/spec/controllers/decidim/elections/census_checks_controller_spec.rb @@ -0,0 +1,90 @@ +# frozen_string_literal: true + +require "spec_helper" + +module Decidim + module Elections + describe CensusChecksController do + let(:component) { create(:elections_component) } + let(:organization) { component.organization } + let(:election) { create(:election, :published, :scheduled, :with_token_csv_census, component:, allow_census_check_before_start: true) } + let(:params) { { component_id: component.id, election_id: election.id } } + let(:main_proxy) { Decidim::EngineRouter.main_proxy(component) } + let(:new_census_check_path) { main_proxy.new_election_census_check_path(election) } + let(:census_check_path) { main_proxy.election_census_check_path(election) } + let(:election_path) { main_proxy.election_path(election) } + let(:voter_data) { election.voters.first.data } + + before do + request.env["decidim.current_organization"] = organization + request.env["decidim.current_participatory_space"] = component.participatory_space + request.env["decidim.current_component"] = component + allow(controller).to receive(:current_participatory_space).and_return(component.participatory_space) + allow(controller).to receive(:current_component).and_return(component) + allow(controller).to receive(:election_census_check_path).and_return(census_check_path) + allow(controller).to receive(:new_election_census_check_path).and_return(new_census_check_path) + allow(controller).to receive(:election_path).and_return(election_path) + end + + describe "GET new" do + it "renders the census check form" do + get :new, params: params + + expect(response).to have_http_status(:ok) + expect(assigns(:form)).to be_present + end + + context "when already authenticated" do + before do + session[:session_attributes] = voter_data.slice("email", "token") + end + + it "redirects to the success page" do + get :new, params: params + + expect(response).to redirect_to(census_check_path) + end + end + end + + describe "POST create" do + it "stores the session attributes and redirects to the success page" do + post :create, params: params.merge(token_csv: voter_data.slice("email", "token")) + + expect(session[:session_attributes]).to include(voter_data.slice("email", "token").stringify_keys) + expect(response).to redirect_to(census_check_path) + end + + it "displays the form when the data is invalid" do + post :create, params: params.merge(token_csv: { email: "wrong@example.com", token: "invalid" }) + + expect(session[:session_attributes]).to be_blank + expect(response).to redirect_to(new_census_check_path) + expect(flash[:alert]).to eq(I18n.t("decidim.elections.censuses.token_csv_form.invalid")) + end + end + + describe "GET show" do + it "redirects to the form when the session is not authenticated" do + get :show, params: params + + expect(response).to redirect_to(new_census_check_path) + expect(flash[:alert]).to eq(I18n.t("decidim.elections.votes.check_census.failed")) + end + + context "when the session is authenticated" do + before do + session[:session_attributes] = voter_data.slice("email", "token") + end + + it "renders the success page" do + get :show, params: params + + expect(response).to have_http_status(:ok) + expect(subject).to render_template(:show) + end + end + end + end + end +end diff --git a/decidim-elections/spec/controllers/decidim/elections/votes_controller_spec.rb b/decidim-elections/spec/controllers/decidim/elections/votes_controller_spec.rb index 90f97390bdd24..c086c74b3366b 100644 --- a/decidim-elections/spec/controllers/decidim/elections/votes_controller_spec.rb +++ b/decidim-elections/spec/controllers/decidim/elections/votes_controller_spec.rb @@ -96,6 +96,56 @@ module Elections expect(session[:votes_buffer]).to eq({ question.id.to_s => nil, second_question.id.to_s => nil }) expect(response).to redirect_to(confirm_election_votes_path) end + + context "when question has max_choices limit" do + let!(:question_with_limit) do + create(:election_question, :voting_enabled, election:, question_type: "multiple_option", max_choices: 2) + end + let!(:option1) { create(:election_response_option, question: question_with_limit) } + let!(:option2) { create(:election_response_option, question: question_with_limit) } + let!(:option3) { create(:election_response_option, question: question_with_limit) } + + it "rejects vote when exceeding max_choices" do + patch :update, params: params.merge( + id: question_with_limit.id, + response: { + question_with_limit.id.to_s => [option1.id, option2.id, option3.id] + } + ) + + expect(response).to have_http_status(:ok) + expect(flash[:alert]).to match(/cannot select more than 2/) + expect(subject).to render_template(:show) + end + + it "accepts vote when within max_choices limit" do + session[:votes_buffer] = { question.id.to_s => nil, second_question.id.to_s => nil } + + patch :update, params: params.merge( + id: question_with_limit.id, + response: { + question_with_limit.id.to_s => [option1.id, option2.id] + } + ) + + expect(session[:votes_buffer][question_with_limit.id.to_s]).to eq([option1.id.to_s, option2.id.to_s]) + expect(response).to redirect_to(confirm_election_votes_path) + end + + it "accepts vote with less than max_choices" do + session[:votes_buffer] = { question.id.to_s => nil, second_question.id.to_s => nil } + + patch :update, params: params.merge( + id: question_with_limit.id, + response: { + question_with_limit.id.to_s => [option1.id] + } + ) + + expect(session[:votes_buffer][question_with_limit.id.to_s]).to eq([option1.id.to_s]) + expect(response).to redirect_to(confirm_election_votes_path) + end + end end end diff --git a/decidim-elections/spec/forms/decidim/elections/admin/election_form_spec.rb b/decidim-elections/spec/forms/decidim/elections/admin/election_form_spec.rb index b0fd5459b85ae..e805c8d322bfe 100644 --- a/decidim-elections/spec/forms/decidim/elections/admin/election_form_spec.rb +++ b/decidim-elections/spec/forms/decidim/elections/admin/election_form_spec.rb @@ -194,6 +194,34 @@ module Decidim::Elections it { is_expected.to be_valid } end + context "when editing a published election configured for manual start" do + let(:election) { create(:election, :published, component:, start_at: nil, end_at: 4.days.from_now) } + let(:manual_start) { true } + let(:start_at) { nil } + + context "and end_at is valid (in the future)" do + let(:end_at) { 2.days.from_now } + + it { is_expected.to be_valid } + + it "does not validate start_at when it is nil" do + expect(subject.valid?).to be true + expect(subject.errors[:start_at]).to be_empty + end + end + + context "and end_at is set in the past" do + let(:end_at) { 1.day.ago } + + it { is_expected.not_to be_valid } + + it "still validates end_at to prevent moving the election into a finished state" do + subject.valid? + expect(subject.errors[:end_at]).not_to be_empty + end + end + end + context "when election is not published" do let(:election) { create(:election, component:, start_at: 3.days.from_now, end_at: 4.days.from_now) } diff --git a/decidim-elections/spec/forms/decidim/elections/admin/question_form_spec.rb b/decidim-elections/spec/forms/decidim/elections/admin/question_form_spec.rb index f5a0349884b82..75e3f42235347 100644 --- a/decidim-elections/spec/forms/decidim/elections/admin/question_form_spec.rb +++ b/decidim-elections/spec/forms/decidim/elections/admin/question_form_spec.rb @@ -55,6 +55,72 @@ module Admin it { is_expected.not_to be_valid } end + describe "max_choices validation" do + let(:attributes) do + { + body_en: body_en, + description_en: description_en, + question_type: question_type, + response_options: response_options, + max_choices: max_choices + } + end + + context "when max_choices is valid" do + let(:max_choices) { 2 } + + it { is_expected.to be_valid } + end + + context "when max_choices is greater than number of options" do + let(:max_choices) { 10 } + + it { is_expected.not_to be_valid } + + it "adds an error on max_choices" do + subject.valid? + expect(subject.errors[:max_choices]).not_to be_empty + end + end + + context "when max_choices is 1" do + let(:max_choices) { 1 } + + it { is_expected.not_to be_valid } + + it "adds an error on max_choices" do + subject.valid? + expect(subject.errors[:max_choices]).not_to be_empty + end + end + + context "when max_choices is nil" do + let(:max_choices) { nil } + + it { is_expected.to be_valid } + end + + context "when max_choices is blank string" do + let(:max_choices) { "" } + + it { is_expected.to be_valid } + end + end + + describe "#number_of_options" do + it "returns the count of response options" do + expect(subject.number_of_options).to eq(2) + end + + context "when there are no response options" do + let(:response_options) { {} } + + it "returns 0" do + expect(subject.number_of_options).to eq(0) + end + end + end + it_behaves_like "form to param", default_id: "questionnaire-question-id" end end diff --git a/decidim-elections/spec/helpers/decidim/elections/application_helper_spec.rb b/decidim-elections/spec/helpers/decidim/elections/application_helper_spec.rb index 50e226cef44d1..3ee81cb3cd9b6 100644 --- a/decidim-elections/spec/helpers/decidim/elections/application_helper_spec.rb +++ b/decidim-elections/spec/helpers/decidim/elections/application_helper_spec.rb @@ -9,7 +9,6 @@ module Elections before do allow(helper).to receive(:current_organization).and_return(organization) - allow(helper).to receive(:rich_text_editor_in_public_views?).and_return(true) end describe "#question_description" do @@ -24,14 +23,14 @@ module Elections context "when the description has plain text" do let(:question) { create(:election_question, description: { "en" => "More info" }) } - it { is_expected.to eq("More info") } + it { is_expected.to eq('
      More info
      ') } end context "when the description includes markup" do let(:question) { build(:election_question, description: { "en" => "Intro" }) } it "keeps the allowed tags" do - expect(rendered_description).to eq("Intro") + expect(rendered_description).to eq('
      Intro
      ') end end diff --git a/decidim-elections/spec/models/decidim/elections/question_spec.rb b/decidim-elections/spec/models/decidim/elections/question_spec.rb index 3f33d9493f9e4..fad27465bc732 100644 --- a/decidim-elections/spec/models/decidim/elections/question_spec.rb +++ b/decidim-elections/spec/models/decidim/elections/question_spec.rb @@ -155,6 +155,22 @@ module Elections it "returns the count of response options" do expect(subject.max_votable_options).to eq(2) end + + context "when max_choices is set" do + let(:question) { create(:election_question, :with_response_options, question_type: "multiple_option", max_choices: 1) } + + it "returns the max_choices value" do + expect(subject.max_votable_options).to eq(1) + end + end + + context "when max_choices is nil" do + let(:question) { create(:election_question, :with_response_options, question_type: "multiple_option", max_choices: nil) } + + it "returns the count of response options" do + expect(subject.max_votable_options).to eq(2) + end + end end end @@ -182,6 +198,15 @@ module Elections expect(question.safe_responses(response_ids)).to be_empty end end + + context "when max_choices is set" do + let(:question) { create(:election_question, :with_response_options, question_type: "multiple_option", max_choices: 1) } + + it "returns only max_choices number of responses" do + response_ids = question.response_options.pluck(:id) + expect(question.safe_responses(response_ids).count).to eq(1) + end + end end describe "#sibling_questions" do diff --git a/decidim-elections/spec/permissions/decidim/elections/permissions_spec.rb b/decidim-elections/spec/permissions/decidim/elections/permissions_spec.rb index 37affd1278d5c..32e72adb9c425 100644 --- a/decidim-elections/spec/permissions/decidim/elections/permissions_spec.rb +++ b/decidim-elections/spec/permissions/decidim/elections/permissions_spec.rb @@ -72,4 +72,62 @@ it { is_expected.to be true } end end + + context "when creating or reading a census_check" do + let(:action) do + { scope: :public, action: :create, subject: :census_check } + end + + it_behaves_like "permission is not set" + + context "when election is not published" do + let(:election) { create(:election, :scheduled, :with_token_csv_census, component:) } + + it_behaves_like "permission is not set" + + context "when user is admin" do + let(:user) { create(:user, :admin, organization: component.organization) } + + it { is_expected.to be true } + end + end + + context "when election is published and scheduled" do + let(:election) { create(:election, :published, :scheduled, :with_token_csv_census, component:) } + + context "when allow_census_check_before_start is false" do + before do + election.update!(allow_census_check_before_start: false) + end + + it_behaves_like "permission is not set" + end + + context "when allow_census_check_before_start is true" do + before do + election.update!(allow_census_check_before_start: true) + end + + it { is_expected.to be true } + end + end + + context "when election is published but census is not ready" do + let(:election) { create(:election, :published, :scheduled, component:, allow_census_check_before_start: true) } + + it_behaves_like "permission is not set" + end + + context "when reading census_check" do + let(:action) do + { scope: :public, action: :read, subject: :census_check } + end + + context "when election is scheduled with census ready and checkbox enabled" do + let(:election) { create(:election, :published, :scheduled, :with_token_csv_census, component:, allow_census_check_before_start: true) } + + it { is_expected.to be true } + end + end + end end diff --git a/decidim-elections/spec/system/admin/admin_manages_election_questions_spec.rb b/decidim-elections/spec/system/admin/admin_manages_election_questions_spec.rb index 1966b147cec60..55ce9ad9fe408 100644 --- a/decidim-elections/spec/system/admin/admin_manages_election_questions_spec.rb +++ b/decidim-elections/spec/system/admin/admin_manages_election_questions_spec.rb @@ -240,6 +240,74 @@ end end + context "when admin user sets max_choices for multiple_option question" do + it "creates a question with max_choices" do + visit questions_edit_path + + click_on "Add question" + expand_all_questions + + within "form.edit_questions" do + within page.all(".questionnaire-question").first do + fill_in find_nested_form_field_locator("body_en"), with: "Select up to 2 options" + select "Multiple option", from: "Type" + + 3.times { click_on "Add response option" } + + page.all(".questionnaire-question-response-option").each_with_index do |option, idx| + within option do + fill_in find_nested_form_field_locator("body_en"), with: "Option #{idx + 1}" + end + end + + select "2", from: "Maximum number of choices" + end + end + + click_on "Save and continue" + + expect(page).to have_admin_callout("successfully") + + visit questions_edit_path + expand_all_questions + + expect(page).to have_css("input[value='Select up to 2 options']") + expect(election.questions.last.max_choices).to eq(2) + end + + it "updates max_choices on existing question" do + question = create(:election_question, :with_response_options, + election:, + question_type: "multiple_option", + max_choices: nil) + + visit questions_edit_path + find("#questionnaire_question_#{question.id}-button").click + + within "#accordion-questionnaire_question_#{question.id}-field" do + select "2", from: "Maximum number of choices" + end + + click_on "Save and continue" + + expect(page).to have_admin_callout("successfully") + expect(question.reload.max_choices).to eq(2) + end + + it "shows 'Any' option for max_choices when unset" do + question = create(:election_question, :with_response_options, + election:, + question_type: "multiple_option") + + visit questions_edit_path + find("#questionnaire_question_#{question.id}-button").click + + within "#accordion-questionnaire_question_#{question.id}-field" do + expect(page).to have_select("Maximum number of choices", selected: "Any") + end + end + end + private def find_nested_form_field_locator(attribute, visible: :visible) diff --git a/decidim-elections/spec/system/admin/admin_manages_elections_spec.rb b/decidim-elections/spec/system/admin/admin_manages_elections_spec.rb index cd7c83fd53f58..01efd6b7249ad 100644 --- a/decidim-elections/spec/system/admin/admin_manages_elections_spec.rb +++ b/decidim-elections/spec/system/admin/admin_manages_elections_spec.rb @@ -145,7 +145,7 @@ expect(page).to have_field("election_end_at_date", disabled: true) expect(page).to have_field("election_end_at_time", disabled: true) end - dynamically_attach_file(:election_photos, Decidim::Dev.asset("city2.jpeg")) + dynamically_attach_file(:election_attachments, Decidim::Dev.asset("city2.jpeg")) click_on "Save and continue" expect(page).to have_admin_callout "Election updated successfully" @@ -301,4 +301,79 @@ end end end + + context "when the election has an attachment" do + let!(:election_with_attachment) do + create(:election, component: current_component) + end + + let!(:document) { create(:attachment, :with_image, attached_to: election_with_attachment) } + + before do + visit_component_admin + + within "tr", text: translated(election_with_attachment.title) do + find("button[data-controller='dropdown']").click + end + end + + it "can remove an attachment" do + click_on translated(election_with_attachment.title) + + click_on("Edit attachments") + + within "li[data-filename='#{document.file.blob.filename}']" do + click_on("Remove") + end + + click_on("Save") + + expect(page).to have_no_css("img[src*='#{document.file.blob.filename}']") + end + + it "can attach a file" do + click_on translated(election_with_attachment.title) + + click_on("Edit attachments") + + filename = document.file.blob.filename.to_s + within ".upload-modal" do + find("input[type='file']", visible: :all).attach_file(Decidim::Dev.asset(filename)) + within "li[data-filename='#{filename}']:not([data-attachment-id])" do + expect(page).to have_css("progress[value='100']") + end + expect(page).to have_css("button[data-dropzone-save]:not([disabled])") + click_on("Save") + end + + expect(page).to have_no_css(".upload-modal") + + click_on("Save and continue") + expect(page).to have_text("Election updated successfully") + + click_on("Main") + expect(page).to have_css("img[src*='#{document.file.blob.filename}']") + end + + it "can edit an election with an attachment" do + click_on translated(election_with_attachment.title) + + expect(page.html).to include(document.file.blob.filename.to_s) + + fill_in_i18n(:election_title, "#election-title-tabs", en: "Updated election title with attachments") + click_on "Save and continue" + + expect(page).to have_content "Election updated successfully" + + visit_component_admin + + within "tr", text: "Updated election title with attachments" do + find("button[data-controller='dropdown']").click + click_on "Edit election" + end + + expect(page.html).to include(document.file.blob.filename.to_s) + expect(page).to have_field("election_title_en", with: "Updated election title with attachments") + end + end end diff --git a/decidim-elections/spec/system/election_results_spec.rb b/decidim-elections/spec/system/election_results_spec.rb index 0152090066d0d..db988ea0edb09 100644 --- a/decidim-elections/spec/system/election_results_spec.rb +++ b/decidim-elections/spec/system/election_results_spec.rb @@ -4,7 +4,7 @@ require "decidim/elections/test/vote_examples" describe "Dashboard" do - let(:election) { create(:election, :published, :ongoing, :real_time, :with_internal_users_census, :with_questions) } + let(:election) { create(:election, :published, :ongoing, :real_time, :with_internal_users_census, :with_questions, skip_injection: true) } let(:question1) { election.questions.first } let(:question2) { election.questions.second } let(:option11) { question1.response_options.first } @@ -79,8 +79,8 @@ def expect_total_votes(question, count) context "when the election is per question" do let(:election) { create(:election, :published, :ongoing, :per_question, :with_internal_users_census) } - let!(:question1) { create(:election_question, :with_response_options, :voting_enabled, election:) } - let!(:question2) { create(:election_question, :with_response_options, election:) } + let!(:question1) { create(:election_question, :with_response_options, :voting_enabled, election:, skip_injection: true) } + let!(:question2) { create(:election_question, :with_response_options, election:, skip_injection: true) } let(:option11) { question1.response_options.first } let(:option12) { question1.response_options.second } let(:option21) { question2.response_options.first } @@ -93,7 +93,7 @@ def expect_total_votes(question, count) end context "when all questions are enabled" do - let!(:question2) { create(:election_question, :with_response_options, :voting_enabled, election:) } + let!(:question2) { create(:election_question, :with_response_options, :voting_enabled, election:, skip_injection: true) } it_behaves_like "shows questions in an election" end diff --git a/decidim-elections/spec/system/user_checks_election_census_spec.rb b/decidim-elections/spec/system/user_checks_election_census_spec.rb new file mode 100644 index 0000000000000..26590a7f40c26 --- /dev/null +++ b/decidim-elections/spec/system/user_checks_election_census_spec.rb @@ -0,0 +1,217 @@ +# frozen_string_literal: true + +require "spec_helper" + +describe "Election census check" do + let(:component) { create(:elections_component) } + let(:organization) { component.organization } + + before do + switch_to_host(organization.host) + end + + context "when the election is scheduled" do + let(:election_path) { Decidim::EngineRouter.main_proxy(component).election_path(election) } + let(:new_census_check_path) { Decidim::EngineRouter.main_proxy(component).new_election_census_check_path(election) } + let(:census_check_path) { Decidim::EngineRouter.main_proxy(component).election_census_check_path(election) } + let(:voter_data) { election.voters.first.data } + + context "when allow_census_check_before_start is enabled" do + let!(:election) { create(:election, :published, :scheduled, :with_token_csv_census, component:, allow_census_check_before_start: true) } + + context "when user is a guest" do + it "displays the census check button" do + visit election_path + + expect(page).to have_link("Check if I can vote") + end + + it "allows the user to validate they are in the census" do + visit election_path + + click_link "Check if I can vote" + + expect(page).to have_current_path(new_census_check_path) + + fill_in "Email", with: voter_data["email"] + fill_in "Token", with: voter_data["token"] + click_button "Access" + + expect(page).to have_current_path(census_check_path) + expect(page).to have_content("You have been successfully verified") + expect(page).to have_content("This means that, once the election starts, you can vote in it.") + + click_link "Exit the census check" + + expect(page).to have_current_path(election_path) + end + end + + context "when user is logged in" do + let(:user) { create(:user, :confirmed, organization:) } + + before do + login_as user, scope: :user + end + + it "displays the census check button" do + visit election_path + + expect(page).to have_link("Check if I can vote") + end + end + + context "when user is an admin" do + let(:admin) { create(:user, :admin, :confirmed, organization:) } + + before do + login_as admin, scope: :user + end + + it "displays the census check button" do + visit election_path + + expect(page).to have_link("Check if I can vote") + end + end + end + + context "when allow_census_check_before_start is disabled" do + let!(:election) { create(:election, :published, :scheduled, :with_token_csv_census, component:, allow_census_check_before_start: false) } + + context "when user is a guest" do + it "does not display the census check button" do + visit election_path + + expect(page).to have_no_link("Check if I can vote") + end + end + + context "when user is logged in" do + let(:user) { create(:user, :confirmed, organization:) } + + before do + login_as user, scope: :user + end + + it "does not display the census check button" do + visit election_path + + expect(page).to have_no_link("Check if I can vote") + end + end + + context "when user is an admin" do + let(:admin) { create(:user, :admin, :confirmed, organization:) } + + before do + login_as admin, scope: :user + end + + it "does not display the census check button" do + visit election_path + + expect(page).to have_no_link("Check if I can vote") + end + end + end + end + + context "when the election is not published" do + let!(:election) { create(:election, :scheduled, :with_token_csv_census, component:) } + let(:election_path) { Decidim::EngineRouter.main_proxy(component).election_path(election) } + let(:new_census_check_path) { Decidim::EngineRouter.main_proxy(component).new_election_census_check_path(election) } + let(:census_check_path) { Decidim::EngineRouter.main_proxy(component).election_census_check_path(election) } + let(:voter_data) { election.voters.first.data } + let(:admin) { create(:user, :admin, :confirmed, organization:) } + + before do + login_as admin, scope: :user + end + + it "displays the census check button for admin preview" do + visit election_path + + expect(page).to have_link("Check if I can vote") + end + + it "allows the admin to preview the census check" do + visit election_path + + click_link "Check if I can vote" + + expect(page).to have_current_path(new_census_check_path) + + fill_in "Email", with: voter_data["email"] + fill_in "Token", with: voter_data["token"] + click_button "Access" + + expect(page).to have_current_path(census_check_path) + expect(page).to have_content("You have been successfully verified") + end + end + + context "when the election uses the internal users census" do + let(:authorization_handlers) { { "dummy_authorization_handler" => { "options" => { "allowed_postal_codes" => "08002" } } } } + let(:election) { create(:election, :published, :scheduled, component:, census_manifest: "internal_users", census_settings: { "authorization_handlers" => authorization_handlers }, allow_census_check_before_start: true) } + let(:election_path) { Decidim::EngineRouter.main_proxy(component).election_path(election) } + let(:new_census_check_path) { Decidim::EngineRouter.main_proxy(component).new_election_census_check_path(election) } + let(:census_check_path) { Decidim::EngineRouter.main_proxy(component).election_census_check_path(election) } + + context "with an authorized participant" do + let(:user) { create(:user, :confirmed, organization:) } + + before do + create(:authorization, user:, name: "dummy_authorization_handler", metadata: { "postal_code" => "08002" }) + login_as user, scope: :user + end + + it "confirms they will be able to vote" do + visit election_path + + click_link "Check if I can vote" + + expect(page).to have_current_path(census_check_path) + expect(page).to have_content("You have been successfully verified") + expect(page).to have_content("This means that, once the election starts, you can vote in it.") + + click_link "Exit the census check" + + expect(page).to have_current_path(election_path) + end + end + + context "with a participant without the required authorizations" do + let(:user) { create(:user, :confirmed, organization:) } + + before do + login_as user, scope: :user + end + + it "blocks the access" do + visit election_path + + click_link "Check if I can vote" + + expect(page).to have_current_path(new_census_check_path) + expect(page).to have_content("Verify your identity") + + click_button "Access" + + expect(page).to have_current_path(new_census_check_path) + expect(page).to have_content("You are not authorized to vote in this election.") + end + end + end + + context "when the election is ongoing" do + let!(:election) { create(:election, :published, :ongoing, :with_token_csv_census, component:) } + let(:election_path) { Decidim::EngineRouter.main_proxy(component).election_path(election) } + + it "does not display the census check button" do + visit election_path + + expect(page).to have_no_link("Check if I can vote") + end + end +end diff --git a/decidim-elections/spec/system/user_votes_in_an_election_spec.rb b/decidim-elections/spec/system/user_votes_in_an_election_spec.rb index 21df699d1f098..f0262fe5b9047 100644 --- a/decidim-elections/spec/system/user_votes_in_an_election_spec.rb +++ b/decidim-elections/spec/system/user_votes_in_an_election_spec.rb @@ -6,8 +6,8 @@ describe "Dashboard" do let(:user) { create(:user, :confirmed, organization:) } let!(:election) { create(:election, :published, :ongoing, :with_internal_users_census, census_settings:) } - let!(:question1) { create(:election_question, :with_response_options, election:, question_type: "single_option") } - let!(:question2) { create(:election_question, :with_response_options, election:, question_type: "multiple_option") } + let!(:question1) { create(:election_question, :with_response_options, skip_injection: true, election:, question_type: "single_option") } + let!(:question2) { create(:election_question, :with_response_options, skip_injection: true, election:, question_type: "multiple_option") } let(:organization) { election.organization } let(:census_settings) do { @@ -104,6 +104,62 @@ def election_vote_path(question) end end + context "when question has max_choices limit", :js do + let(:election_with_limit) { create(:election, :published, :ongoing, :with_internal_users_census, component: election.component) } + let!(:question_with_limit) { create(:election_question, election: election_with_limit, question_type: "multiple_option", max_choices: 2, body: { en: "Choose your options" }) } + let!(:option1) { create(:election_response_option, question: question_with_limit, body: { en: "Option 1" }) } + let!(:option2) { create(:election_response_option, question: question_with_limit, body: { en: "Option 2" }) } + let!(:option3) { create(:election_response_option, question: question_with_limit, body: { en: "Option 3" }) } + let(:new_election_with_limit_vote_path) { Decidim::EngineRouter.main_proxy(election.component).new_election_vote_path(election_id: election_with_limit.id) } + + before do + login_as user, scope: :user + visit new_election_with_limit_vote_path + end + + it "shows max_choices in question title" do + expect(page).to have_content("Choose your options (Max choices: 2)") + end + + it "shows alert when selecting more than max_choices" do + check "Option 1" + check "Option 2" + check "Option 3" + + expect(page).to have_css(".max-choices-alert", visible: :visible) + end + + it "hides alert when deselecting options" do + check "Option 1" + check "Option 2" + check "Option 3" + + expect(page).to have_css(".max-choices-alert", visible: :visible) + + uncheck "Option 3" + + expect(page).to have_css(".max-choices-alert", visible: :hidden) + end + + it "shows server-side validation error when exceeding limit" do + check "Option 1" + check "Option 2" + check "Option 3" + + click_on "Next" + + expect(page).to have_content("You cannot select more than 2 options") + end + + context "when question is single_option" do + let!(:single_question) { create(:election_question, election: election_with_limit, question_type: "single_option", body: { en: "Choose one option" }) } + + it "does not show max_choices for single_option questions" do + expect(page).to have_no_content("Choose one option (Max choices:") + end + end + end + context "when the election is per_question" do let(:election) { create(:election, :published, :ongoing, :with_internal_users_census, :per_question) } diff --git a/decidim-elections/spec/system/user_votes_in_an_per_question_election_spec.rb b/decidim-elections/spec/system/user_votes_in_an_per_question_election_spec.rb index 1cebb4374f344..a54419ca5a15b 100644 --- a/decidim-elections/spec/system/user_votes_in_an_per_question_election_spec.rb +++ b/decidim-elections/spec/system/user_votes_in_an_per_question_election_spec.rb @@ -21,8 +21,8 @@ let(:receipt_election_votes_path) { Decidim::EngineRouter.main_proxy(election.component).receipt_election_per_question_votes_path(election_id: election.id) } let(:confirm_election_votes_path) { Decidim::EngineRouter.main_proxy(election.component).confirm_election_per_question_votes_path(election_id: election.id) } let(:new_election_normal_vote_path) { Decidim::EngineRouter.main_proxy(election.component).new_election_vote_path(election_id: election.id) } - let!(:question1) { create(:election_question, :with_response_options, :voting_enabled, question_type: "single_option", election:, position: 1) } - let!(:question2) { create(:election_question, :with_response_options, election:, position: 2) } + let!(:question1) { create(:election_question, :with_response_options, :voting_enabled, skip_injection: true, question_type: "single_option", election:, position: 1) } + let!(:question2) { create(:election_question, :with_response_options, election:, skip_injection: true, position: 2) } let(:voter_uid) { user.to_global_id.to_s } def election_vote_path(question) @@ -62,8 +62,8 @@ def election_vote_path(question) end context "when navigating through already voted questions" do - let!(:question2) { create(:election_question, :with_response_options, :voting_enabled, election:, position: 2) } - let!(:question3) { create(:election_question, :with_response_options, election:, position: 3) } + let!(:question2) { create(:election_question, :with_response_options, :voting_enabled, election:, skip_injection: true, position: 2) } + let!(:question3) { create(:election_question, :with_response_options, election:, skip_injection: true, position: 3) } before do login_as user, scope: :user @@ -74,8 +74,8 @@ def election_vote_path(question) end context "when editing votes from receipt page" do - let!(:question1) { create(:election_question, :with_response_options, :voting_enabled, question_type: "single_option", election:, position: 1) } - let!(:question2) { create(:election_question, :with_response_options, :voting_enabled, election:, position: 2) } + let!(:question1) { create(:election_question, :with_response_options, :voting_enabled, skip_injection: true, question_type: "single_option", election:, position: 1) } + let!(:question2) { create(:election_question, :with_response_options, :voting_enabled, skip_injection: true, election:, position: 2) } before do login_as user, scope: :user diff --git a/decidim-forms/app/commands/decidim/forms/response_questionnaire.rb b/decidim-forms/app/commands/decidim/forms/response_questionnaire.rb index 6f0046c414fe2..a90b9f57854ed 100644 --- a/decidim-forms/app/commands/decidim/forms/response_questionnaire.rb +++ b/decidim-forms/app/commands/decidim/forms/response_questionnaire.rb @@ -59,7 +59,7 @@ def event_arguments # of this problem. def reset_form_attachments @form.responses.each do |response| - response.errors.add(:add_documents, :needs_to_be_reattached) if response.has_attachments? || response.has_error_in_attachments? + response.errors.add(:add_attachments, :needs_to_be_reattached) if response.has_attachments? || response.has_error_in_attachments? end end @@ -116,7 +116,7 @@ def response_questionnaire end create_attachments if process_attachments? - document_cleanup! + attachment_cleanup! end @form = @main_form diff --git a/decidim-forms/app/forms/decidim/forms/questionnaire_form.rb b/decidim-forms/app/forms/decidim/forms/questionnaire_form.rb index 5832dce44011a..f8c40ed500ed1 100644 --- a/decidim-forms/app/forms/decidim/forms/questionnaire_form.rb +++ b/decidim-forms/app/forms/decidim/forms/questionnaire_form.rb @@ -30,7 +30,7 @@ def map_model(model) def add_responses!(questionnaire:, session_token:, ip_hash:) self.responses = questionnaire.questions.map do |question| - ResponseForm.from_model(Decidim::Forms::Response.where(question:, user: current_user, session_token:, ip_hash:).first_or_initialize) + ResponseForm.from_model(Decidim::Forms::Response.where(question:, user: current_user, session_token:, ip_hash:).first_or_initialize).with_context(context) end end diff --git a/decidim-forms/app/forms/decidim/forms/response_form.rb b/decidim-forms/app/forms/decidim/forms/response_form.rb index 8da91883d050d..ed213a2856bc4 100644 --- a/decidim-forms/app/forms/decidim/forms/response_form.rb +++ b/decidim-forms/app/forms/decidim/forms/response_form.rb @@ -12,7 +12,7 @@ class ResponseForm < Decidim::Form attribute :choices, Array[ResponseChoiceForm] attribute :matrix_choices, Array[ResponseChoiceForm] - attachments_attribute :documents + attachments_attribute :attachments validates :body, presence: true, if: :mandatory_body? validates :selected_choices, presence: true, if: :mandatory_choices? @@ -20,7 +20,7 @@ class ResponseForm < Decidim::Form validate :max_choices, if: -> { question.max_choices } validate :all_choices, if: :sorting? validate :min_choices, if: -> { question.matrix? && question.mandatory? } - validate :documents_present, if: -> { question.question_type == "files" && question.mandatory? } + validate :attachments_present, if: -> { question.question_type == "files" && question.mandatory? } validate :max_characters, if: -> { question.max_characters.positive? } delegate :mandatory_body?, :mandatory_choices?, :matrix?, to: :question @@ -44,7 +44,7 @@ def label def map_model(model) self.question_id = model.decidim_question_id self.question = model.question - self.documents = model.attachments + self.attachments = model.attachments self.choices = model.choices.map do |choice| ResponseChoiceForm.from_model(choice) @@ -82,11 +82,11 @@ def optional_conditions_fulfilled? end def has_attachments? - question.has_attachments? && errors[:add_documents].empty? && add_documents.present? + question.has_attachments? && errors[:add_attachments].empty? && add_attachments.present? end def has_error_in_attachments? - errors[:add_documents].present? + errors[:add_attachments].present? end def sorting? @@ -141,8 +141,8 @@ def max_choices_label I18n.t("questionnaires.question.max_choices", scope: "decidim.forms", n: question.max_choices) end - def documents_present - errors.add(:add_documents, :blank) if add_documents.empty? && errors[:add_documents].empty? + def attachments_present + errors.add(:add_attachments, :blank) if add_attachments.empty? && errors[:add_attachments].empty? end end end diff --git a/decidim-forms/app/views/decidim/forms/questionnaires/_questionnaire.html.erb b/decidim-forms/app/views/decidim/forms/questionnaires/_questionnaire.html.erb index aae37dde3aeda..363d3c4eba4d4 100644 --- a/decidim-forms/app/views/decidim/forms/questionnaires/_questionnaire.html.erb +++ b/decidim-forms/app/views/decidim/forms/questionnaires/_questionnaire.html.erb @@ -18,7 +18,7 @@ <%= invisible_captcha %> <% response_idx = 0 %> <% @form.responses_by_step.each_with_index do |step_responses, step_index| %> -
      > +
      > <% if @form.total_steps > 1 %>

      diff --git a/decidim-forms/app/views/decidim/forms/questionnaires/responses/_files.html.erb b/decidim-forms/app/views/decidim/forms/questionnaires/responses/_files.html.erb index 3613d3c53f706..298845835d75c 100644 --- a/decidim-forms/app/views/decidim/forms/questionnaires/responses/_files.html.erb +++ b/decidim-forms/app/views/decidim/forms/questionnaires/responses/_files.html.erb @@ -1 +1 @@ -<%= response_form.upload :add_documents, attachments: response.documents, label: false, multiple: true, id: field_id, disabled:, button_class: "button button__lg button__transparent-secondary w-full" %> +<%= response_form.upload :add_attachments, attachments: response.attachments, label: false, multiple: true, id: field_id, disabled:, button_class: "button button__lg button__transparent-secondary w-full" %> diff --git a/decidim-forms/config/locales/ca-IT.yml b/decidim-forms/config/locales/ca-IT.yml index 005f67db43306..d821faf067d44 100644 --- a/decidim-forms/config/locales/ca-IT.yml +++ b/decidim-forms/config/locales/ca-IT.yml @@ -188,10 +188,10 @@ ca-IT: of_total_steps: de %{total_steps} questionnaire_closed: body: El formulari està tancat i no es pot respondre. - title: S'ha tancat el formulari + title: Formulari tancat questionnaire_for_private_users: body: El formulari només està disponible per a participants privades - title: S'ha tancat el formulari + title: Formulari tancat questionnaire_js_disabled: body: Algunes de les característiques d'aquest formulari es deshabilitaran. Per millorar la teva experiència, si us plau, habilita JavaScript al teu navegador. title: JavaScript està desactivat diff --git a/decidim-forms/config/locales/eu.yml b/decidim-forms/config/locales/eu.yml index afc94eaa0324e..42f749111033e 100644 --- a/decidim-forms/config/locales/eu.yml +++ b/decidim-forms/config/locales/eu.yml @@ -140,7 +140,7 @@ eu: remove: Kendu separator: Bereizlea title_and_description: - collapse: Tolestu + collapse: Kolapsoa description: Deskribapena expand: Zabaldu remove: Kendu diff --git a/decidim-forms/config/locales/fr-CA.yml b/decidim-forms/config/locales/fr-CA.yml index aab6fdff3d7be..890ffa3fc968b 100644 --- a/decidim-forms/config/locales/fr-CA.yml +++ b/decidim-forms/config/locales/fr-CA.yml @@ -177,7 +177,9 @@ fr-CA: question: max_choices: 'Choix maximum: %{n}' response: + invalid: Une erreur s'est produite lors de l'envoi du formulaire. max_choices_alert: Il y a trop de choix sélectionnés + success: Le formulaire a bien été envoyé. show: current_step: Étape %{step} empty: Aucune question configurée pour ce formulaire pour le moment. diff --git a/decidim-forms/config/locales/fr.yml b/decidim-forms/config/locales/fr.yml index 0c3cc7d4cd85a..e531fcb3c20db 100644 --- a/decidim-forms/config/locales/fr.yml +++ b/decidim-forms/config/locales/fr.yml @@ -177,7 +177,9 @@ fr: question: max_choices: 'Choix maximum: %{n}' response: + invalid: Une erreur s'est produite lors de l'envoi du formulaire. max_choices_alert: Il y a trop de choix sélectionnés + success: Le formulaire a bien été envoyé. show: current_step: Étape %{step} empty: Aucune question configurée pour ce formulaire pour le moment. diff --git a/decidim-forms/db/data/20260616144141_rename_answers_to_responses.rb b/decidim-forms/db/data/20260616144141_rename_answers_to_responses.rb new file mode 100644 index 0000000000000..66a762c906e9d --- /dev/null +++ b/decidim-forms/db/data/20260616144141_rename_answers_to_responses.rb @@ -0,0 +1,31 @@ +# frozen_string_literal: true + +class RenameAnswersToResponses < ActiveRecord::Migration[7.2] + class Attachment < ApplicationRecord + self.table_name = "decidim_attachments" + end + + class ActionLog < ApplicationRecord + self.table_name = "decidim_action_logs" + end + + class Version < ApplicationRecord + self.table_name = "versions" + end + + def up + # rubocop:disable Rails/SkipsModelValidations + Attachment.where(attached_to_type: "Decidim::Forms::Answer").update_all(attached_to_type: "Decidim::Forms::Response") + ActionLog.where(resource_type: "Decidim::Forms::Answer").update_all(resource_type: "Decidim::Forms::Response") + Version.where(item_type: "Decidim::Forms::Answer").update_all(item_type: "Decidim::Forms::Response") + # rubocop:enable Rails/SkipsModelValidations + end + + def down + # rubocop:disable Rails/SkipsModelValidations + Attachment.where(attached_to_type: "Decidim::Forms::Response").update_all(attached_to_type: "Decidim::Forms::Answer") + ActionLog.where(resource_type: "Decidim::Forms::Response").update_all(resource_type: "Decidim::Forms::Answer") + Version.where(item_type: "Decidim::Forms::Response").update_all(item_type: "Decidim::Forms::Answer") + # rubocop:enable Rails/SkipsModelValidations + end +end diff --git a/decidim-forms/lib/decidim/forms/version.rb b/decidim-forms/lib/decidim/forms/version.rb index 2195c3b71606a..58a4de9110f80 100644 --- a/decidim-forms/lib/decidim/forms/version.rb +++ b/decidim-forms/lib/decidim/forms/version.rb @@ -4,7 +4,7 @@ module Decidim # This holds the decidim-forms version. module Forms def self.version - "0.31.4" + "0.31.7" end end end diff --git a/decidim-forms/spec/commands/decidim/forms/response_questionnaire_spec.rb b/decidim-forms/spec/commands/decidim/forms/response_questionnaire_spec.rb index 282683846f990..2a84d0966d5f1 100644 --- a/decidim-forms/spec/commands/decidim/forms/response_questionnaire_spec.rb +++ b/decidim-forms/spec/commands/decidim/forms/response_questionnaire_spec.rb @@ -144,7 +144,7 @@ def tokenize(id) { "responses" => [ { - "add_documents" => uploaded_files, + "add_attachments" => uploaded_files, "question_id" => question1.id } ], diff --git a/decidim-forms/spec/db/data/rename_answers_to_responses_spec.rb b/decidim-forms/spec/db/data/rename_answers_to_responses_spec.rb new file mode 100644 index 0000000000000..6ab746efdaa8a --- /dev/null +++ b/decidim-forms/spec/db/data/rename_answers_to_responses_spec.rb @@ -0,0 +1,128 @@ +# frozen_string_literal: true + +require "spec_helper" + +require "./db/data/20260616144141_rename_answers_to_responses" + +describe RenameAnswersToResponses do + let(:migrator) do + described_class.new.tap do |m| + m.verbose = false + end + end + + let(:organization) { create(:organization) } + let!(:participatory_process) { create(:participatory_process, organization:) } + let(:user) { create(:user, organization:) } + let!(:questionnaire) { create(:questionnaire, questionnaire_for: participatory_process) } + let(:response) { create(:response, questionnaire:) } + let!(:action_logs_with_other_types) do + create_list(:action_log, 2, resource: create(:dummy_resource, organization:)) + end + let!(:action_logs_with_old_type) do + # rubocop:disable Rails/SkipsModelValidations + Decidim::ActionLog.insert_all([ + { + decidim_organization_id: organization.id, + user_id: user.id, + user_type: "Decidim::User", + resource_type: "Decidim::Forms::Questionnaire", + resource_id: questionnaire.id, + action: "create", + visibility: "public-only", + extra: { + "user" => { + "ip" => "127.0.0.1", + "name" => "Dummy user", + "nickname" => "dummy" + }, + "resource" => {}, + "component" => {}, + "participatory_space" => {} + }, + created_at: Time.current, + updated_at: Time.current + }, + { + decidim_organization_id: organization.id, + user_id: user.id, + user_type: "Decidim::User", + resource_type: "Decidim::Forms::Answer", + resource_id: response.id, + action: "create", + visibility: "public-only", + extra: { + "user" => { + "ip" => "127.0.0.1", + "name" => "Dummy user", + "nickname" => "dummy" + }, + "resource" => {}, + "component" => {}, + "participatory_space" => {} + }, + created_at: Time.current, + updated_at: Time.current + } + ]) + # rubocop:enable Rails/SkipsModelValidations + end + + it "updates properly the action logs" do + expect(Decidim::ActionLog.where(resource_type: "Decidim::Forms::Questionnaire").first.resource).to eq(questionnaire) + expect(Decidim::ActionLog.where(resource_type: "Decidim::Forms::Response").first).to be_nil + + migrator.migrate(:up) + expect(Decidim::ActionLog.where(resource_type: "Decidim::Forms::Questionnaire").first.resource).to eq(questionnaire) + expect(Decidim::ActionLog.where(resource_type: "Decidim::Forms::Response").first.resource).to eq(response) + + migrator.migrate(:down) + expect(Decidim::ActionLog.where(resource_type: "Decidim::Forms::Questionnaire").first.resource).to eq(questionnaire) + expect(Decidim::ActionLog.where(resource_type: "Decidim::Forms::Response").first).to be_nil + end + + class Version < ApplicationRecord + self.table_name = "versions" + end + + it "updates properly the paper trail versions" do + Version.create!( + item_type: "Decidim::Forms::Answer", + item_id: response.id, + event: "update", + whodunnit: user.id.to_s, + object: "{}", + object_changes: "{}", + created_at: Time.current + ) + + expect(Version.where(item_type: "Decidim::Forms::Response").first).to be_nil + + migrator.migrate(:up) + expect(Version.where(item_type: "Decidim::Forms::Response").first.item_id).to eq(response.id) + + migrator.migrate(:down) + expect(Version.where(item_type: "Decidim::Forms::Response").first).to be_nil + end + + context "when having attachments" do + let!(:response) { create(:response, :with_attachments, questionnaire:) } + let!(:other_attachment) { create(:attachment, attached_to: participatory_process) } + + it "updates properly the attachments" do + # rubocop:disable Rails/SkipsModelValidations + Decidim::Attachment.where(attached_to_type: "Decidim::Forms::Response").update_all(attached_to_type: "Decidim::Forms::Answer") + # rubocop:enable Rails/SkipsModelValidations + + expect(Decidim::Attachment.where(attached_to_type: "Decidim::Forms::Answer").first).to be_present + + migrator.migrate(:up) + expect(Decidim::Attachment.where(attached_to_type: "Decidim::Forms::Response").first).to eq(response.attachments.first) + expect(Decidim::Attachment.where(attached_to_type: "Decidim::ParticipatoryProcess").first).to eq(other_attachment) + + migrator.migrate(:down) + expect(Decidim::Attachment.where(attached_to_type: "Decidim::Forms::Answer").first).to be_present + expect(Decidim::Attachment.where(attached_to_type: "Decidim::ParticipatoryProcess").first).to eq(other_attachment) + end + end +end diff --git a/decidim-forms/spec/forms/decidim/forms/response_form_spec.rb b/decidim-forms/spec/forms/decidim/forms/response_form_spec.rb index 0528b2b2dc32d..4b7d0c5a59e31 100644 --- a/decidim-forms/spec/forms/decidim/forms/response_form_spec.rb +++ b/decidim-forms/spec/forms/decidim/forms/response_form_spec.rb @@ -87,7 +87,7 @@ module Forms context "when the body is empty" do before do subject.body = nil - subject.add_documents = uploaded_files + subject.add_attachments = uploaded_files end it "is valid" do @@ -97,7 +97,7 @@ module Forms context "when there are no uploaded files" do before do - subject.add_documents = nil + subject.add_attachments = nil end it "is not valid if there are no files" do diff --git a/decidim-generators/Gemfile.lock b/decidim-generators/Gemfile.lock index 00d5991e469b5..8cf7d7e9d9549 100644 --- a/decidim-generators/Gemfile.lock +++ b/decidim-generators/Gemfile.lock @@ -1,62 +1,62 @@ PATH remote: .. specs: - decidim (0.31.4) - decidim-accountability (= 0.31.4) - decidim-admin (= 0.31.4) - decidim-api (= 0.31.4) - decidim-assemblies (= 0.31.4) - decidim-blogs (= 0.31.4) - decidim-budgets (= 0.31.4) - decidim-comments (= 0.31.4) - decidim-core (= 0.31.4) - decidim-debates (= 0.31.4) - decidim-forms (= 0.31.4) - decidim-generators (= 0.31.4) - decidim-meetings (= 0.31.4) - decidim-pages (= 0.31.4) - decidim-participatory_processes (= 0.31.4) - decidim-proposals (= 0.31.4) - decidim-sortitions (= 0.31.4) - decidim-surveys (= 0.31.4) - decidim-system (= 0.31.4) - decidim-verifications (= 0.31.4) - decidim-accountability (0.31.4) - decidim-comments (= 0.31.4) - decidim-core (= 0.31.4) - decidim-admin (0.31.4) + decidim (0.31.7) + decidim-accountability (= 0.31.7) + decidim-admin (= 0.31.7) + decidim-api (= 0.31.7) + decidim-assemblies (= 0.31.7) + decidim-blogs (= 0.31.7) + decidim-budgets (= 0.31.7) + decidim-comments (= 0.31.7) + decidim-core (= 0.31.7) + decidim-debates (= 0.31.7) + decidim-forms (= 0.31.7) + decidim-generators (= 0.31.7) + decidim-meetings (= 0.31.7) + decidim-pages (= 0.31.7) + decidim-participatory_processes (= 0.31.7) + decidim-proposals (= 0.31.7) + decidim-sortitions (= 0.31.7) + decidim-surveys (= 0.31.7) + decidim-system (= 0.31.7) + decidim-verifications (= 0.31.7) + decidim-accountability (0.31.7) + decidim-comments (= 0.31.7) + decidim-core (= 0.31.7) + decidim-admin (0.31.7) active_link_to (~> 1.0) - decidim-core (= 0.31.4) + decidim-core (= 0.31.7) devise (~> 4.7) devise-i18n (~> 1.2) devise_invitable (~> 2.0, >= 2.0.9) - decidim-ai (0.31.4) + decidim-ai (0.31.7) classifier-reborn (~> 2.3.0) - decidim-core (= 0.31.4) - decidim-api (0.31.4) - decidim-core (= 0.31.4) + decidim-core (= 0.31.7) + decidim-api (0.31.7) + decidim-core (= 0.31.7) devise-jwt (~> 0.12.1) graphql (~> 2.4.0, >= 2.4.17) graphql-docs (~> 5.0) rack-cors (~> 1.0) - decidim-assemblies (0.31.4) - decidim-core (= 0.31.4) - decidim-blogs (0.31.4) - decidim-admin (= 0.31.4) - decidim-comments (= 0.31.4) - decidim-core (= 0.31.4) - decidim-budgets (0.31.4) - decidim-comments (= 0.31.4) - decidim-core (= 0.31.4) - decidim-collaborative_texts (0.31.4) - decidim-core (= 0.31.4) - decidim-comments (0.31.4) - decidim-core (= 0.31.4) + decidim-assemblies (0.31.7) + decidim-core (= 0.31.7) + decidim-blogs (0.31.7) + decidim-admin (= 0.31.7) + decidim-comments (= 0.31.7) + decidim-core (= 0.31.7) + decidim-budgets (0.31.7) + decidim-comments (= 0.31.7) + decidim-core (= 0.31.7) + decidim-collaborative_texts (0.31.7) + decidim-core (= 0.31.7) + decidim-comments (0.31.7) + decidim-core (= 0.31.7) redcarpet (~> 3.5, >= 3.5.1) - decidim-conferences (0.31.4) - decidim-core (= 0.31.4) - decidim-meetings (= 0.31.4) - decidim-core (0.31.4) + decidim-conferences (0.31.7) + decidim-core (= 0.31.7) + decidim-meetings (= 0.31.7) + decidim-core (0.31.7) active_link_to (~> 1.0) acts_as_list (~> 1.0) batch-loader (~> 2.0) @@ -99,6 +99,7 @@ PATH premailer-rails (~> 1.10) rack (~> 2.2, >= 2.2.8.1) rack-attack (~> 6.0) + rack-proxy (~> 0.8.3, < 1.0) rails (~> 7.2.0, >= 7.2.2.2) rails-i18n (~> 7.0) ransack (~> 4.2.0) @@ -111,24 +112,24 @@ PATH valid_email2 (~> 7.0) web-push (~> 3.0) wisper (~> 3.0) - decidim-debates (0.31.4) - decidim-comments (= 0.31.4) - decidim-core (= 0.31.4) - decidim-demographics (0.31.4) - decidim-core (= 0.31.4) - decidim-forms (= 0.31.4) - decidim-design (0.31.4) - decidim-core (= 0.31.4) - decidim-dev (0.31.4) + decidim-debates (0.31.7) + decidim-comments (= 0.31.7) + decidim-core (= 0.31.7) + decidim-demographics (0.31.7) + decidim-core (= 0.31.7) + decidim-forms (= 0.31.7) + decidim-design (0.31.7) + decidim-core (= 0.31.7) + decidim-dev (0.31.7) bullet (~> 8.0.0) byebug (~> 11.0) capybara (~> 3.39) - decidim-admin (= 0.31.4) - decidim-api (= 0.31.4) - decidim-comments (= 0.31.4) - decidim-core (= 0.31.4) - decidim-generators (= 0.31.4) - decidim-verifications (= 0.31.4) + decidim-admin (= 0.31.7) + decidim-api (= 0.31.7) + decidim-comments (= 0.31.7) + decidim-core (= 0.31.7) + decidim-generators (= 0.31.7) + decidim-verifications (= 0.31.7) erb_lint (~> 0.8.0) factory_bot_rails (~> 6.2) faker (~> 3.2) @@ -161,51 +162,51 @@ PATH w3c_rspec_validators (~> 0.3.0) webmock (~> 3.18) wisper-rspec (~> 1.0) - decidim-elections (0.31.4) - decidim-admin (= 0.31.4) - decidim-core (= 0.31.4) - decidim-forms (= 0.31.4) - decidim-forms (0.31.4) - decidim-core (= 0.31.4) - decidim-generators (0.31.4) - decidim-core (= 0.31.4) - decidim-initiatives (0.31.4) - decidim-admin (= 0.31.4) - decidim-comments (= 0.31.4) - decidim-core (= 0.31.4) - decidim-verifications (= 0.31.4) - decidim-meetings (0.31.4) - decidim-core (= 0.31.4) - decidim-forms (= 0.31.4) + decidim-elections (0.31.7) + decidim-admin (= 0.31.7) + decidim-core (= 0.31.7) + decidim-forms (= 0.31.7) + decidim-forms (0.31.7) + decidim-core (= 0.31.7) + decidim-generators (0.31.7) + decidim-core (= 0.31.7) + decidim-initiatives (0.31.7) + decidim-admin (= 0.31.7) + decidim-comments (= 0.31.7) + decidim-core (= 0.31.7) + decidim-verifications (= 0.31.7) + decidim-meetings (0.31.7) + decidim-core (= 0.31.7) + decidim-forms (= 0.31.7) icalendar (~> 2.5) - decidim-pages (0.31.4) - decidim-core (= 0.31.4) - decidim-participatory_processes (0.31.4) - decidim-core (= 0.31.4) - decidim-proposals (0.31.4) - decidim-comments (= 0.31.4) - decidim-core (= 0.31.4) + decidim-pages (0.31.7) + decidim-core (= 0.31.7) + decidim-participatory_processes (0.31.7) + decidim-core (= 0.31.7) + decidim-proposals (0.31.7) + decidim-comments (= 0.31.7) + decidim-core (= 0.31.7) doc2text (~> 0.4.0, >= 0.4.8) redcarpet (~> 3.5, >= 3.5.1) - decidim-sortitions (0.31.4) - decidim-admin (= 0.31.4) - decidim-comments (= 0.31.4) - decidim-core (= 0.31.4) - decidim-proposals (= 0.31.4) - decidim-surveys (0.31.4) - decidim-core (= 0.31.4) - decidim-forms (= 0.31.4) - decidim-system (0.31.4) + decidim-sortitions (0.31.7) + decidim-admin (= 0.31.7) + decidim-comments (= 0.31.7) + decidim-core (= 0.31.7) + decidim-proposals (= 0.31.7) + decidim-surveys (0.31.7) + decidim-core (= 0.31.7) + decidim-forms (= 0.31.7) + decidim-system (0.31.7) active_link_to (~> 1.0) - decidim-core (= 0.31.4) + decidim-core (= 0.31.7) devise (~> 4.7) devise-i18n (~> 1.2) devise_invitable (~> 2.0, >= 2.0.9) - decidim-templates (0.31.4) - decidim-core (= 0.31.4) - decidim-forms (= 0.31.4) - decidim-verifications (0.31.4) - decidim-core (= 0.31.4) + decidim-templates (0.31.7) + decidim-core (= 0.31.7) + decidim-forms (= 0.31.7) + decidim-verifications (0.31.7) + decidim-core (= 0.31.7) GEM remote: https://rubygems.org/ @@ -652,7 +653,7 @@ GEM rack-protection (3.2.0) base64 (>= 0.1.0) rack (~> 2.2, >= 2.2.4) - rack-proxy (0.7.7) + rack-proxy (0.8.3) rack rack-session (1.0.2) rack (< 3) diff --git a/decidim-generators/lib/decidim/generators/app_generator.rb b/decidim-generators/lib/decidim/generators/app_generator.rb index d9dcaaa69e581..59241036027e0 100644 --- a/decidim-generators/lib/decidim/generators/app_generator.rb +++ b/decidim-generators/lib/decidim/generators/app_generator.rb @@ -218,7 +218,10 @@ def add_storage_provider add_production_gems do gem "aws-sdk-s3", require: false if providers.include?("s3") gem "azure-storage-blob", require: false if providers.include?("azure") - gem "google-cloud-storage", "~> 1.11", require: false if providers.include?("gcs") + if providers.include?("gcs") + gem "google-cloud-storage", "~> 1.11", require: false + gem "multi_json" + end end end diff --git a/decidim-generators/lib/decidim/generators/component_templates/Gemfile.erb b/decidim-generators/lib/decidim/generators/component_templates/Gemfile.erb index 7a664463115f9..7032138bed10e 100644 --- a/decidim-generators/lib/decidim/generators/component_templates/Gemfile.erb +++ b/decidim-generators/lib/decidim/generators/component_templates/Gemfile.erb @@ -5,7 +5,7 @@ source "https://rubygems.org" ruby RUBY_VERSION -gem "decidim", "~> 0.31.4" +gem "decidim", "~> 0.31.7" gem "decidim-<%= component_name %>", path: "." gem "puma", ">= 6.3.1" @@ -14,7 +14,7 @@ gem "bootsnap", "~> 1.4" group :development, :test do gem "byebug", "~> 11.0", platform: :mri - gem "decidim-dev", "~> 0.31.4" + gem "decidim-dev", "~> 0.31.7" end group :development do diff --git a/decidim-generators/lib/decidim/generators/component_templates/github/ci.yml.erb b/decidim-generators/lib/decidim/generators/component_templates/github/ci.yml.erb index e068b31191b8d..0b829d4d4294c 100644 --- a/decidim-generators/lib/decidim/generators/component_templates/github/ci.yml.erb +++ b/decidim-generators/lib/decidim/generators/component_templates/github/ci.yml.erb @@ -21,7 +21,7 @@ concurrency: jobs: main: name: Tests - runs-on: ubuntu-22.04 + runs-on: ubuntu-24.04 timeout-minutes: 30 services: postgres: diff --git a/decidim-generators/lib/decidim/generators/install_generator.rb b/decidim-generators/lib/decidim/generators/install_generator.rb index d872f5f6078cf..c61c081e388a8 100644 --- a/decidim-generators/lib/decidim/generators/install_generator.rb +++ b/decidim-generators/lib/decidim/generators/install_generator.rb @@ -165,7 +165,7 @@ def tweak_spring end def bundle_install - run "bundle install" + Bundler.with_original_env { run "bundle install" } end def copy_migrations diff --git a/decidim-generators/lib/decidim/generators/version.rb b/decidim-generators/lib/decidim/generators/version.rb index f2dff1c7f1b8b..234879f3a7816 100644 --- a/decidim-generators/lib/decidim/generators/version.rb +++ b/decidim-generators/lib/decidim/generators/version.rb @@ -4,7 +4,7 @@ module Decidim module Generators def self.version - "0.31.4" + "0.31.7" end end end diff --git a/decidim-initiatives/app/commands/decidim/initiatives/create_initiative.rb b/decidim-initiatives/app/commands/decidim/initiatives/create_initiative.rb index 251e35d5ec52e..90778a95c5db2 100644 --- a/decidim-initiatives/app/commands/decidim/initiatives/create_initiative.rb +++ b/decidim-initiatives/app/commands/decidim/initiatives/create_initiative.rb @@ -8,7 +8,6 @@ module Initiatives class CreateInitiative < Decidim::Command include CurrentLocale include ::Decidim::MultipleAttachmentsMethods - include ::Decidim::GalleryMethods delegate :current_user, to: :form # Public: Initializes the command. @@ -32,11 +31,6 @@ def call return broadcast(:invalid) if attachments_invalid? end - if process_gallery? - build_gallery - return broadcast(:invalid) if gallery_invalid? - end - initiative = create_initiative if initiative.persisted? @@ -60,7 +54,7 @@ def event_arguments private - attr_reader :form, :attachment, :initiative + attr_reader :form, :attachments, :initiative # Creates the initiative and all default components def create_initiative @@ -72,7 +66,6 @@ def create_initiative @attached_to = initiative create_attachments if process_attachments? - create_gallery if process_gallery? create_components_for(initiative) send_notification(initiative) diff --git a/decidim-initiatives/app/commands/decidim/initiatives/update_initiative.rb b/decidim-initiatives/app/commands/decidim/initiatives/update_initiative.rb index 0b83d0e5e314e..b999fe2536166 100644 --- a/decidim-initiatives/app/commands/decidim/initiatives/update_initiative.rb +++ b/decidim-initiatives/app/commands/decidim/initiatives/update_initiative.rb @@ -6,7 +6,6 @@ module Initiatives # existing initiative. class UpdateInitiative < Decidim::Command include ::Decidim::MultipleAttachmentsMethods - include ::Decidim::GalleryMethods include CurrentLocale delegate :current_user, to: :form @@ -34,11 +33,6 @@ def call return broadcast(:invalid) if attachments_invalid? end - if process_gallery? - build_gallery - return broadcast(:invalid) if gallery_invalid? - end - with_events(with_transaction: true) do @initiative = Decidim.traceability.update!( initiative, @@ -46,10 +40,8 @@ def call attributes ) - photo_cleanup! - document_cleanup! + attachment_cleanup! create_attachments if process_attachments? - create_gallery if process_gallery? end broadcast(:ok, initiative) @@ -71,7 +63,7 @@ def event_arguments private - attr_reader :form, :initiative + attr_reader :form, :initiative, :attachments def attributes attrs = { diff --git a/decidim-initiatives/app/events/decidim/initiatives/approve_membership_request_event.rb b/decidim-initiatives/app/events/decidim/initiatives/approve_membership_request_event.rb index dc75aac70f8fb..9139d7ee66197 100644 --- a/decidim-initiatives/app/events/decidim/initiatives/approve_membership_request_event.rb +++ b/decidim-initiatives/app/events/decidim/initiatives/approve_membership_request_event.rb @@ -8,6 +8,7 @@ def i18n_scope = "decidim.initiatives.events.approve_membership_request" def i18n_options { author_nickname:, + author_name:, author_profile_url:, participatory_space_title:, participatory_space_url:, @@ -24,6 +25,10 @@ def author_nickname author.nickname end + def author_name + author.name + end + def author_profile_url author.profile_url end diff --git a/decidim-initiatives/app/events/decidim/initiatives/revoke_membership_request_event.rb b/decidim-initiatives/app/events/decidim/initiatives/revoke_membership_request_event.rb index efc9a1dd01f59..5a84d19f37454 100644 --- a/decidim-initiatives/app/events/decidim/initiatives/revoke_membership_request_event.rb +++ b/decidim-initiatives/app/events/decidim/initiatives/revoke_membership_request_event.rb @@ -8,6 +8,7 @@ def i18n_scope = "decidim.initiatives.events.revoke_membership_request" def i18n_options { author_nickname:, + author_name:, author_profile_url:, participatory_space_title:, participatory_space_url:, @@ -24,6 +25,10 @@ def author_nickname author.nickname end + def author_name + author.name + end + def author_profile_url author.profile_url end diff --git a/decidim-initiatives/app/events/decidim/initiatives/spawn_committee_request_event.rb b/decidim-initiatives/app/events/decidim/initiatives/spawn_committee_request_event.rb index f0b7d6ba64f69..1b45dcc9c0492 100644 --- a/decidim-initiatives/app/events/decidim/initiatives/spawn_committee_request_event.rb +++ b/decidim-initiatives/app/events/decidim/initiatives/spawn_committee_request_event.rb @@ -8,6 +8,7 @@ def i18n_scope = "decidim.initiatives.events.spawn_committee_request_event" def i18n_options { applicant_nickname:, + applicant_name:, applicant_profile_url:, participatory_space_title:, participatory_space_url:, @@ -24,6 +25,10 @@ def applicant_nickname applicant.nickname end + def applicant_name + applicant.name + end + def applicant_profile_url applicant.profile_url end diff --git a/decidim-initiatives/app/forms/decidim/initiatives/initiative_form.rb b/decidim-initiatives/app/forms/decidim/initiatives/initiative_form.rb index aea38b2586c4c..6da5aec38a523 100644 --- a/decidim-initiatives/app/forms/decidim/initiatives/initiative_form.rb +++ b/decidim-initiatives/app/forms/decidim/initiatives/initiative_form.rb @@ -20,7 +20,7 @@ class InitiativeForm < Form attribute :scope_id, Integer attachments_attribute :photos - attachments_attribute :documents + attachments_attribute :attachments validates :title, :description, presence: true validates :title, length: { maximum: 150 } diff --git a/decidim-initiatives/app/helpers/decidim/initiatives/initiatives_helper.rb b/decidim-initiatives/app/helpers/decidim/initiatives/initiatives_helper.rb index 5c9c89c18acd8..e0b197bf137a1 100644 --- a/decidim-initiatives/app/helpers/decidim/initiatives/initiatives_helper.rb +++ b/decidim-initiatives/app/helpers/decidim/initiatives/initiatives_helper.rb @@ -13,7 +13,7 @@ def initiative_nav_items(participatory_space) components.map do |component| { - name: decidim_escape_translated(component.name), + name: translated_attribute(component.name), url: main_component_path(component), active: is_active_link?(main_component_path(component), :inclusive) } diff --git a/decidim-initiatives/app/models/decidim/initiative.rb b/decidim-initiatives/app/models/decidim/initiative.rb index 9ce1d59fd3d14..ed19712269778 100644 --- a/decidim-initiatives/app/models/decidim/initiative.rb +++ b/decidim-initiatives/app/models/decidim/initiative.rb @@ -388,6 +388,7 @@ def comments_have_votes? # # Returns a Boolean. def has_authorship?(user) + return false unless user return true if author.id == user.id committee_members.approved.where(decidim_users_id: user.id).any? diff --git a/decidim-initiatives/app/views/decidim/initiatives/admin/initiatives/index.html.erb b/decidim-initiatives/app/views/decidim/initiatives/admin/initiatives/index.html.erb index b01f0578c2d49..61b38f6c97933 100644 --- a/decidim-initiatives/app/views/decidim/initiatives/admin/initiatives/index.html.erb +++ b/decidim-initiatives/app/views/decidim/initiatives/admin/initiatives/index.html.erb @@ -74,7 +74,7 @@ <% else %>