The server cannot process the request due to a client error. Please check the request and try again. If you’re the application owner check the logs for more information.
+diff --git a/.env.template b/.env.template index 1c995ecc..59891b2b 100644 --- a/.env.template +++ b/.env.template @@ -3,4 +3,9 @@ DATABASE_DEV_PASSWORD=postgres_password GITHUB_ID=github_client_id GITHUB_SECRET=github_client_secret GOOGLE_ID=google_client_id -GOOGLE_SECRET=google_secret_key \ No newline at end of file +GOOGLE_SECRET=google_secret_key +FACEBOOK_ID=facebook_app_id +FACEBOOK_SECRET=facebook_app_secret +TWITTER_ID=twitter_app_id +TWITTER_SECRET=twitter_app_secret +TZ=America/Sao_Paulo \ No newline at end of file diff --git a/.ruby-version b/.ruby-version index ef538c28..4f5e6973 100644 --- a/.ruby-version +++ b/.ruby-version @@ -1 +1 @@ -3.1.2 +3.4.5 diff --git a/.tool-versions b/.tool-versions new file mode 100644 index 00000000..27a8619d --- /dev/null +++ b/.tool-versions @@ -0,0 +1 @@ +ruby 3.4.5 diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 00000000..bc51ec86 --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,166 @@ +# CLAUDE.md + +This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. + +## Development Environment + +### Ruby and Rails Versions +- Ruby: 3.4.5 (managed via asdf) +- Rails: 8.0.3 +- Node: 22.x +- Bundler: 2.7.2 + +### Essential Commands + +#### Development Server +```bash +bin/dev # Start Rails server with CSS watching (uses Procfile.dev) +rails server # Start Rails server only +yarn build:css --watch # Watch and compile CSS changes +``` + +#### Database +```bash +rails db:create # Create database +rails db:migrate # Run migrations +rails db:seed # Seed database with sample data +rails db:drop # Drop database (careful!) +rails db:reset # Drop, create, migrate, and seed +``` + +#### Testing +```bash +# Run all RSpec tests +bundle exec rspec + +# Run specific test categories +bundle exec rspec spec/features +bundle exec rspec spec/models +bundle exec rspec spec/requests +bundle exec rspec spec/integration + +# Run Rails tests +rails test test/models +rails test test/controllers +rails test test/integration +rails test test/system + +# Run a single test file +bundle exec rspec path/to/spec_file.rb +rails test path/to/test_file.rb + +# Run tests with specific line number +bundle exec rspec path/to/spec_file.rb:42 +``` + +#### Linting and Code Quality +```bash +bundle exec rubocop # Run Rubocop linter +bundle exec rubocop -a # Auto-fix Rubocop offenses +bundle exec rubocop path/to/file.rb # Check specific file +``` + +#### API Documentation +```bash +bundle exec rake rswag # Generate Swagger/OpenAPI documentation +# Access at: http://localhost:3000/api-docs/index.html +``` + +#### Background Jobs +```bash +bundle exec sidekiq # Start Sidekiq worker +redis-server # Start Redis (required for Sidekiq) +``` + +#### Asset Compilation +```bash +yarn build:css # Build CSS with Bulma +rails assets:precompile # Precompile all assets for production +rails assets:clobber # Remove compiled assets +``` + +## Architecture Overview + +### Core Models and Relationships + +The application centers around **Member** (User) with Devise authentication: +- **Member** → has many **Posts** (blog posts) +- **Post** → has many **Comments** and **Likes** +- Complex analytics system tracking visitors, browsers, and user interactions + +### Authentication & Authorization +- **Devise** handles authentication with OAuth support (GitHub, Google) +- **CanCanCan** manages authorization through `app/models/ability.rb` +- **JWT** tokens for API authentication (`app/models/json_web_token.rb`) +- API login endpoint: `POST /api/v1/auth/login` + +### API Structure +- Versioned API under `app/controllers/api/v1/` +- JWT-based authentication for API endpoints +- Swagger documentation auto-generated from tests +- API responses use Jbuilder templates in `app/views/api/v1/` + +### Real-time Features +- **Turbo Streams** for live updates without page refresh +- **Stimulus controllers** in `app/javascript/controllers/` +- **Action Cable** broadcasts analytics updates to dashboards +- Chart controller manages real-time analytics visualization + +### Background Processing +- **Sidekiq** jobs in `app/jobs/` process analytics asynchronously +- Jobs: AddCounterJob, AddBrowserJob, AddUniqueJob, AddLengthJob +- Redis required for job queue management + +### Frontend Stack +- **Turbo Rails** for SPA-like navigation +- **Stimulus** for JavaScript behavior +- **Bulma CSS** framework (compiled via cssbundling-rails) +- **Chartkick** for analytics charts +- **Pagy** for pagination + +### Testing Approach +- **RSpec** for API and integration tests (`spec/`) +- **Rails Test** for models and controllers (`test/`) +- **Factory Bot** for test data generation +- **Capybara** with Selenium for system tests +- Tests generate API documentation via Rswag + +### Key Technical Patterns + +1. **Counter Caches**: Automatic count maintenance + - `posts_count` on Member + - `comments_count` and `likes_count` on Post + +2. **FriendlyId**: SEO-friendly URLs for members + - Uses slug field on Member model + +3. **Active Storage**: Avatar uploads with validation + - Image processing for variants + +4. **Analytics System**: + - Visitor tracking with browser fingerprinting + - Multiple analytics models for different metrics + - MemberBrowser class implements visitor pattern + +5. **Broadcasting Pattern**: + - CounterAnalytic broadcasts updates to member-specific channels + - Real-time dashboard updates via Turbo Streams + +### Database Considerations +- PostgreSQL with multiple extensions enabled +- Counter caches maintain denormalized counts +- Indexes on foreign keys and frequently queried fields +- Bullet gem monitors N+1 queries in development + +### Environment Variables +Required in `.env` for development: +- `DATABASE_DEV_USERNAME` - PostgreSQL username +- `DATABASE_DEV_PASSWORD` - PostgreSQL password +- `GITHUB_ID` & `GITHUB_SECRET` - GitHub OAuth +- `GOOGLE_ID` & `GOOGLE_SECRET` - Google OAuth + +### Deployment +- Configured for Render.com deployment +- Dockerfile uses Ruby 3.4.5 and Node 22.x +- Production uses PostgreSQL and Redis +- Assets precompiled during Docker build \ No newline at end of file diff --git a/Dockerfile b/Dockerfile index ead0afa0..612d559b 100755 --- a/Dockerfile +++ b/Dockerfile @@ -11,19 +11,13 @@ ####################################################################### -# Learn more about the chosen Ruby stack, Fullstaq Ruby, here: -# https://github.com/evilmartians/fullstaq-ruby-docker. -# -# We recommend using the highest patch level for better security and -# performance. - -ARG RUBY_VERSION=3.1.2 -ARG VARIANT=jemalloc-bullseye-slim -FROM quay.io/evl.ms/fullstaq-ruby:${RUBY_VERSION}-${VARIANT} as base +# Using official Ruby image for Ruby 3.4.5 support +ARG RUBY_VERSION=3.4.5 +FROM ruby:${RUBY_VERSION}-slim as base LABEL fly_launch_runtime="rails" -ARG BUNDLER_VERSION=2.3.22 +ARG BUNDLER_VERSION=2.7.2 ARG RAILS_ENV=production ENV RAILS_ENV=${RAILS_ENV} @@ -49,23 +43,30 @@ RUN gem update --system --no-document && \ FROM base as build_deps -ARG BUILD_PACKAGES="git build-essential libpq-dev wget vim curl gzip xz-utils libsqlite3-dev" +ARG BUILD_PACKAGES="git build-essential libpq-dev wget vim curl gzip xz-utils libsqlite3-dev nodejs npm" ENV BUILD_PACKAGES ${BUILD_PACKAGES} +# Install Node.js 22.x RUN --mount=type=cache,id=dev-apt-cache,sharing=locked,target=/var/cache/apt \ --mount=type=cache,id=dev-apt-lib,sharing=locked,target=/var/lib/apt \ apt-get update -qq && \ + apt-get install -y curl && \ + curl -fsSL https://deb.nodesource.com/setup_22.x | bash - && \ apt-get install --no-install-recommends -y ${BUILD_PACKAGES} \ && rm -rf /var/lib/apt/lists /var/cache/apt/archives ####################################################################### -# install gems +# install gems and node modules FROM build_deps as gems COPY Gemfile* ./ -RUN bundle install && rm -rf vendor/bundle/ruby/*/cache +RUN bundle install && rm -rf vendor/bundle/ruby/*/cache + +# Copy package.json and install node modules for asset compilation +COPY package.json ./ +RUN npm install ####################################################################### @@ -73,19 +74,21 @@ RUN bundle install && rm -rf vendor/bundle/ruby/*/cache FROM base -ARG DEPLOY_PACKAGES="postgresql-client file vim curl gzip libsqlite3-0" +ARG DEPLOY_PACKAGES="postgresql-client file vim curl gzip libsqlite3-0 nodejs" ENV DEPLOY_PACKAGES=${DEPLOY_PACKAGES} +# Install Node.js 22.x for runtime (needed for execjs) RUN --mount=type=cache,id=prod-apt-cache,sharing=locked,target=/var/cache/apt \ --mount=type=cache,id=prod-apt-lib,sharing=locked,target=/var/lib/apt \ apt-get update -qq && \ + apt-get install -y curl && \ + curl -fsSL https://deb.nodesource.com/setup_22.x | bash - && \ apt-get install --no-install-recommends -y \ ${DEPLOY_PACKAGES} \ && rm -rf /var/lib/apt/lists /var/cache/apt/archives -# copy installed gems +# copy installed gems and node modules COPY --from=gems /app /app -COPY --from=gems /usr/lib/fullstaq-ruby/versions /usr/lib/fullstaq-ruby/versions COPY --from=gems /usr/local/bundle /usr/local/bundle ####################################################################### @@ -113,4 +116,4 @@ RUN ${BUILD_COMMAND} ENV PORT 8080 ARG SERVER_COMMAND="bin/rails fly:server" ENV SERVER_COMMAND ${SERVER_COMMAND} -CMD ${SERVER_COMMAND} +CMD ${SERVER_COMMAND} \ No newline at end of file diff --git a/Gemfile b/Gemfile index 790b8fbf..b167967a 100644 --- a/Gemfile +++ b/Gemfile @@ -1,12 +1,12 @@ source 'https://rubygems.org' git_source(:github) { |repo| "https://github.com/#{repo}.git" } -ruby '3.1.2' +ruby '3.4.5' -gem 'rubocop', '>= 1.0', '< 2.0' +gem 'rubocop', '>= 1.58', '< 2.0' # Bundle edge Rails instead: gem "rails", github: "rails/rails", branch: "main" -gem 'rails', '~> 7.0.4' +gem 'rails', '~> 8.0.0' # The original asset pipeline for Rails [https://github.com/rails/sprockets-rails] gem 'sprockets-rails' @@ -27,7 +27,7 @@ gem 'rspec' gem 'jwt' # Use the Puma web server [https://github.com/puma/puma] -gem 'puma', '~> 5.0' +gem 'puma', '~> 6.0' # Use JavaScript with ESM import maps [https://github.com/rails/importmap-rails] gem 'importmap-rails' @@ -42,7 +42,7 @@ gem 'stimulus-rails' gem 'jbuilder' # Use Redis adapter to run Action Cable in production -gem 'redis', '~> 4.0' +gem 'redis', '~> 5.0' # Use Kredis to get higher-level data types in Redis [https://github.com/rails/kredis] # gem "kredis" diff --git a/Gemfile.lock b/Gemfile.lock index 5e53e2a2..901ce6a2 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -13,79 +13,86 @@ GIT GEM remote: https://rubygems.org/ specs: - actioncable (7.0.6) - actionpack (= 7.0.6) - activesupport (= 7.0.6) + actioncable (8.0.3) + actionpack (= 8.0.3) + activesupport (= 8.0.3) nio4r (~> 2.0) websocket-driver (>= 0.6.1) - actionmailbox (7.0.6) - actionpack (= 7.0.6) - activejob (= 7.0.6) - activerecord (= 7.0.6) - activestorage (= 7.0.6) - activesupport (= 7.0.6) - mail (>= 2.7.1) - net-imap - net-pop - net-smtp - actionmailer (7.0.6) - actionpack (= 7.0.6) - actionview (= 7.0.6) - activejob (= 7.0.6) - activesupport (= 7.0.6) - mail (~> 2.5, >= 2.5.4) - net-imap - net-pop - net-smtp - rails-dom-testing (~> 2.0) - actionpack (7.0.6) - actionview (= 7.0.6) - activesupport (= 7.0.6) - rack (~> 2.0, >= 2.2.4) + zeitwerk (~> 2.6) + actionmailbox (8.0.3) + actionpack (= 8.0.3) + activejob (= 8.0.3) + activerecord (= 8.0.3) + activestorage (= 8.0.3) + activesupport (= 8.0.3) + mail (>= 2.8.0) + actionmailer (8.0.3) + actionpack (= 8.0.3) + actionview (= 8.0.3) + activejob (= 8.0.3) + activesupport (= 8.0.3) + mail (>= 2.8.0) + rails-dom-testing (~> 2.2) + actionpack (8.0.3) + actionview (= 8.0.3) + activesupport (= 8.0.3) + nokogiri (>= 1.8.5) + rack (>= 2.2.4) + rack-session (>= 1.0.1) rack-test (>= 0.6.3) - rails-dom-testing (~> 2.0) - rails-html-sanitizer (~> 1.0, >= 1.2.0) - actiontext (7.0.6) - actionpack (= 7.0.6) - activerecord (= 7.0.6) - activestorage (= 7.0.6) - activesupport (= 7.0.6) + rails-dom-testing (~> 2.2) + rails-html-sanitizer (~> 1.6) + useragent (~> 0.16) + actiontext (8.0.3) + actionpack (= 8.0.3) + activerecord (= 8.0.3) + activestorage (= 8.0.3) + activesupport (= 8.0.3) globalid (>= 0.6.0) nokogiri (>= 1.8.5) - actionview (7.0.6) - activesupport (= 7.0.6) + actionview (8.0.3) + activesupport (= 8.0.3) builder (~> 3.1) - erubi (~> 1.4) - rails-dom-testing (~> 2.0) - rails-html-sanitizer (~> 1.1, >= 1.2.0) - active_storage_validations (1.0.4) - activejob (>= 5.2.0) - activemodel (>= 5.2.0) - activestorage (>= 5.2.0) - activesupport (>= 5.2.0) - activejob (7.0.6) - activesupport (= 7.0.6) + erubi (~> 1.11) + rails-dom-testing (~> 2.2) + rails-html-sanitizer (~> 1.6) + active_storage_validations (3.0.2) + activejob (>= 6.1.4) + activemodel (>= 6.1.4) + activestorage (>= 6.1.4) + activesupport (>= 6.1.4) + marcel (>= 1.0.3) + activejob (8.0.3) + activesupport (= 8.0.3) globalid (>= 0.3.6) - activemodel (7.0.6) - activesupport (= 7.0.6) - activerecord (7.0.6) - activemodel (= 7.0.6) - activesupport (= 7.0.6) - activestorage (7.0.6) - actionpack (= 7.0.6) - activejob (= 7.0.6) - activerecord (= 7.0.6) - activesupport (= 7.0.6) + activemodel (8.0.3) + activesupport (= 8.0.3) + activerecord (8.0.3) + activemodel (= 8.0.3) + activesupport (= 8.0.3) + timeout (>= 0.4.0) + activestorage (8.0.3) + actionpack (= 8.0.3) + activejob (= 8.0.3) + activerecord (= 8.0.3) + activesupport (= 8.0.3) marcel (~> 1.0) - mini_mime (>= 1.1.0) - activesupport (7.0.6) - concurrent-ruby (~> 1.0, >= 1.0.2) + activesupport (8.0.3) + base64 + benchmark (>= 0.3) + bigdecimal + concurrent-ruby (~> 1.0, >= 1.3.1) + connection_pool (>= 2.2.5) + drb i18n (>= 1.6, < 2) + logger (>= 1.4.2) minitest (>= 5.1) - tzinfo (~> 2.0) + securerandom (>= 0.3) + tzinfo (~> 2.0, >= 2.0.5) + uri (>= 0.13.1) addressable (2.8.4) public_suffix (>= 2.0.2, < 6.0) - ast (2.4.2) + ast (2.4.3) aws-eventstream (1.2.0) aws-partitions (1.785.0) aws-sdk-core (3.177.0) @@ -102,52 +109,57 @@ GEM aws-sigv4 (~> 1.6) aws-sigv4 (1.6.0) aws-eventstream (~> 1, >= 1.0.2) + base64 (0.3.0) bcrypt (3.1.19) + benchmark (0.4.1) + bigdecimal (3.2.3) bindex (0.8.1) bootsnap (1.16.0) msgpack (~> 1.2) browser (5.3.1) - builder (3.2.4) - bullet (7.0.7) + builder (3.3.0) + bullet (8.0.8) activesupport (>= 3.0.0) uniform_notifier (~> 1.11) cancancan (3.5.0) - capybara (3.39.2) + capybara (3.40.0) addressable matrix mini_mime (>= 0.1.3) - nokogiri (~> 1.8) + nokogiri (~> 1.11) rack (>= 1.6.0) rack-test (>= 0.6.3) regexp_parser (>= 1.5, < 3.0) xpath (~> 3.2) chartkick (5.0.4) - concurrent-ruby (1.2.2) + concurrent-ruby (1.3.5) connection_pool (2.4.1) crass (1.0.6) cssbundling-rails (1.2.0) railties (>= 6.0.0) - database_cleaner (2.0.2) + database_cleaner (2.1.0) database_cleaner-active_record (>= 2, < 3) - database_cleaner-active_record (2.1.0) + database_cleaner-active_record (2.2.2) activerecord (>= 5.a) - database_cleaner-core (~> 2.0.0) + database_cleaner-core (~> 2.0) database_cleaner-core (2.0.1) - date (3.3.3) - debug (1.8.0) - irb (>= 1.5.0) - reline (>= 0.3.1) + date (3.4.1) + debug (1.11.0) + irb (~> 1.10) + reline (>= 0.3.8) diff-lcs (1.5.0) dotenv (2.8.1) dotenv-rails (2.8.1) dotenv (= 2.8.1) railties (>= 3.2) - erubi (1.12.0) - factory_bot (6.2.1) - activesupport (>= 5.0.0) - factory_bot_rails (6.2.0) - factory_bot (~> 6.2.0) - railties (>= 5.0.0) + drb (2.2.3) + erb (5.0.2) + erubi (1.13.1) + factory_bot (6.5.5) + activesupport (>= 6.1.0) + factory_bot_rails (6.5.1) + factory_bot (~> 6.5) + railties (>= 6.1.0) faker (3.2.0) i18n (>= 1.8.11, < 2) faraday (2.7.10) @@ -157,36 +169,41 @@ GEM ffi (1.15.5) friendly_id (5.4.2) activerecord (>= 4.0.0) - globalid (1.1.0) - activesupport (>= 5.0) + globalid (1.2.1) + activesupport (>= 6.1) hashie (5.0.0) - i18n (1.14.1) + i18n (1.14.7) concurrent-ruby (~> 1.0) image_processing (1.12.2) mini_magick (>= 4.9.5, < 5) ruby-vips (>= 2.0.17, < 3) - importmap-rails (1.2.1) + importmap-rails (2.2.2) actionpack (>= 6.0.0) + activesupport (>= 6.0.0) railties (>= 6.0.0) io-console (0.6.0) - irb (1.7.1) - reline (>= 0.3.0) - jbuilder (2.11.5) - actionview (>= 5.0.0) - activesupport (>= 5.0.0) + irb (1.15.2) + pp (>= 0.6.0) + rdoc (>= 4.0.0) + reline (>= 0.4.2) + jbuilder (2.14.1) + actionview (>= 7.0.0) + activesupport (>= 7.0.0) jmespath (1.6.2) - json (2.6.3) + json (2.15.0) json-schema (3.0.0) addressable (>= 2.8) jwt (2.7.1) kramdown (2.4.0) rexml - language_server-protocol (3.17.0.3) + language_server-protocol (3.17.0.5) launchy (2.5.2) addressable (~> 2.8) letter_opener (1.8.1) launchy (>= 2.2, < 3) - loofah (2.21.3) + lint_roller (1.1.0) + logger (1.7.0) + loofah (2.24.1) crass (~> 1.0.2) nokogiri (>= 1.12.0) mail (2.8.1) @@ -194,31 +211,30 @@ GEM net-imap net-pop net-smtp - marcel (1.0.2) + marcel (1.1.0) matrix (0.4.2) - method_source (1.0.0) mini_magick (4.12.0) - mini_mime (1.1.2) - mini_portile2 (2.8.5) - minitest (5.18.1) + mini_mime (1.1.5) + mini_portile2 (2.8.9) + minitest (5.25.5) msgpack (1.7.1) multi_xml (0.6.0) - net-imap (0.3.6) + net-imap (0.5.10) date net-protocol net-pop (0.1.2) net-protocol - net-protocol (0.2.1) + net-protocol (0.2.2) timeout - net-smtp (0.3.3) + net-smtp (0.5.1) net-protocol - nio4r (2.5.9) - nokogiri (1.15.3) + nio4r (2.7.4) + nokogiri (1.18.10) mini_portile2 (~> 2.8.2) racc (~> 1.4) - nokogiri (1.15.3-x86_64-darwin) + nokogiri (1.18.10-x86_64-darwin) racc (~> 1.4) - nokogiri (1.15.3-x86_64-linux) + nokogiri (1.18.10-x86_64-linux-gnu) racc (~> 1.4) oauth2 (2.0.9) faraday (>= 0.17.3, < 3.0) @@ -242,82 +258,100 @@ GEM omniauth-oauth2 (1.8.0) oauth2 (>= 1.4, < 3) omniauth (~> 2.0) - omniauth-rails_csrf_protection (1.0.1) + omniauth-rails_csrf_protection (1.0.2) actionpack (>= 4.2) omniauth (~> 2.0) orm_adapter (0.5.0) pagy (6.0.4) - parallel (1.23.0) - parser (3.2.2.3) + parallel (1.27.0) + parser (3.3.9.0) ast (~> 2.4.1) racc pg (1.5.3) + pp (0.6.2) + prettyprint + prettyprint (0.2.0) + prism (1.5.1) + psych (5.2.6) + date + stringio public_suffix (5.0.1) - puma (5.6.6) + puma (6.6.1) nio4r (~> 2.0) - racc (1.7.1) - rack (2.2.7) + racc (1.8.1) + rack (3.2.1) rack-protection (3.0.6) rack - rack-test (2.1.0) + rack-session (2.1.1) + base64 (>= 0.1.0) + rack (>= 3.0.0) + rack-test (2.2.0) rack (>= 1.3) - rails (7.0.6) - actioncable (= 7.0.6) - actionmailbox (= 7.0.6) - actionmailer (= 7.0.6) - actionpack (= 7.0.6) - actiontext (= 7.0.6) - actionview (= 7.0.6) - activejob (= 7.0.6) - activemodel (= 7.0.6) - activerecord (= 7.0.6) - activestorage (= 7.0.6) - activesupport (= 7.0.6) + rackup (2.2.1) + rack (>= 3) + rails (8.0.3) + actioncable (= 8.0.3) + actionmailbox (= 8.0.3) + actionmailer (= 8.0.3) + actionpack (= 8.0.3) + actiontext (= 8.0.3) + actionview (= 8.0.3) + activejob (= 8.0.3) + activemodel (= 8.0.3) + activerecord (= 8.0.3) + activestorage (= 8.0.3) + activesupport (= 8.0.3) bundler (>= 1.15.0) - railties (= 7.0.6) + railties (= 8.0.3) rails-controller-testing (1.0.5) actionpack (>= 5.0.1.rc1) actionview (>= 5.0.1.rc1) activesupport (>= 5.0.1.rc1) - rails-dom-testing (2.1.1) + rails-dom-testing (2.3.0) activesupport (>= 5.0.0) minitest nokogiri (>= 1.6) - rails-html-sanitizer (1.6.0) + rails-html-sanitizer (1.6.2) loofah (~> 2.21) - nokogiri (~> 1.14) - railties (7.0.6) - actionpack (= 7.0.6) - activesupport (= 7.0.6) - method_source + 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) + railties (8.0.3) + actionpack (= 8.0.3) + activesupport (= 8.0.3) + irb (~> 1.13) + rackup (>= 1.0.0) rake (>= 12.2) - thor (~> 1.0) - zeitwerk (~> 2.5) + thor (~> 1.0, >= 1.2.2) + tsort (>= 0.2) + zeitwerk (~> 2.6) rainbow (3.1.1) - rake (13.0.6) - redis (4.8.1) - redis-client (0.18.0) + rake (13.3.0) + rdoc (6.14.2) + erb + psych (>= 4.0.0) + redis (5.4.1) + redis-client (>= 0.22.0) + redis-client (0.25.3) connection_pool - regexp_parser (2.8.1) - reline (0.3.6) + regexp_parser (2.11.3) + reline (0.6.2) io-console (~> 0.5) - responders (3.1.0) + responders (3.1.1) actionpack (>= 5.2) railties (>= 5.2) - rexml (3.2.5) + rexml (3.4.4) rspec (3.12.0) rspec-core (~> 3.12.0) rspec-expectations (~> 3.12.0) rspec-mocks (~> 3.12.0) - rspec-core (3.12.2) + rspec-core (3.12.3) rspec-support (~> 3.12.0) - rspec-expectations (3.12.3) + rspec-expectations (3.12.4) diff-lcs (>= 1.2.0, < 2.0) rspec-support (~> 3.12.0) rspec-mocks (3.12.5) diff-lcs (>= 1.2.0, < 2.0) rspec-support (~> 3.12.0) - rspec-rails (6.0.3) + rspec-rails (6.1.1) actionpack (>= 6.1) activesupport (>= 6.1) railties (>= 6.1) @@ -326,73 +360,82 @@ GEM rspec-mocks (~> 3.12) rspec-support (~> 3.12) rspec-support (3.12.1) - rswag (2.9.0) - rswag-api (= 2.9.0) - rswag-specs (= 2.9.0) - rswag-ui (= 2.9.0) - rswag-api (2.9.0) - railties (>= 3.1, < 7.1) - rswag-specs (2.9.0) - activesupport (>= 3.1, < 7.1) - json-schema (>= 2.2, < 4.0) - railties (>= 3.1, < 7.1) + rswag (2.16.0) + rswag-api (= 2.16.0) + rswag-specs (= 2.16.0) + rswag-ui (= 2.16.0) + rswag-api (2.16.0) + activesupport (>= 5.2, < 8.1) + railties (>= 5.2, < 8.1) + rswag-specs (2.16.0) + activesupport (>= 5.2, < 8.1) + json-schema (>= 2.2, < 6.0) + railties (>= 5.2, < 8.1) rspec-core (>= 2.14) - rswag-ui (2.9.0) - actionpack (>= 3.1, < 7.1) - railties (>= 3.1, < 7.1) - rubocop (1.54.1) + rswag-ui (2.16.0) + actionpack (>= 5.2, < 8.1) + railties (>= 5.2, < 8.1) + rubocop (1.80.2) json (~> 2.3) - language_server-protocol (>= 3.17.0) + language_server-protocol (~> 3.17.0.2) + lint_roller (~> 1.1.0) parallel (~> 1.10) - parser (>= 3.2.2.3) + parser (>= 3.3.0.2) rainbow (>= 2.2.2, < 4.0) - regexp_parser (>= 1.8, < 3.0) - rexml (>= 3.2.5, < 4.0) - rubocop-ast (>= 1.28.0, < 2.0) + regexp_parser (>= 2.9.3, < 3.0) + rubocop-ast (>= 1.46.0, < 2.0) ruby-progressbar (~> 1.7) - unicode-display_width (>= 2.4.0, < 3.0) - rubocop-ast (1.29.0) - parser (>= 3.2.1.0) + unicode-display_width (>= 2.4.0, < 4.0) + rubocop-ast (1.47.1) + parser (>= 3.3.7.2) + prism (~> 1.4) ruby-progressbar (1.13.0) ruby-vips (2.1.4) ffi (~> 1.12) ruby2_keywords (0.0.5) rubyzip (2.3.2) + securerandom (0.4.1) selenium-webdriver (4.10.0) rexml (~> 3.2, >= 3.2.5) rubyzip (>= 1.2.2, < 3.0) websocket (~> 1.0) - sidekiq (7.2.0) - concurrent-ruby (< 2) + sidekiq (7.3.9) + base64 connection_pool (>= 2.3.0) + logger rack (>= 2.2.4) - redis-client (>= 0.14.0) + redis-client (>= 0.22.2) snaky_hash (2.0.1) hashie version_gem (~> 1.1, >= 1.1.1) sprockets (4.2.0) concurrent-ruby (~> 1.0) rack (>= 2.2.4, < 4) - sprockets-rails (3.4.2) - actionpack (>= 5.2) - activesupport (>= 5.2) + sprockets-rails (3.5.2) + actionpack (>= 6.1) + activesupport (>= 6.1) sprockets (>= 3.0.0) stimulus-rails (1.2.1) railties (>= 6.0.0) - thor (1.2.2) - timeout (0.4.0) - turbo-rails (1.4.0) - actionpack (>= 6.0.0) - activejob (>= 6.0.0) - railties (>= 6.0.0) + stringio (3.1.7) + thor (1.4.0) + timeout (0.4.3) + tsort (0.2.0) + turbo-rails (2.0.16) + actionpack (>= 7.1.0) + railties (>= 7.1.0) tzinfo (2.0.6) concurrent-ruby (~> 1.0) - unicode-display_width (2.4.2) + unicode-display_width (3.2.0) + unicode-emoji (~> 4.1) + unicode-emoji (4.1.0) uniform_notifier (1.16.0) + uri (1.0.3) + useragent (0.16.11) version_gem (1.1.3) warden (1.2.9) rack (>= 2.0.9) - web-console (4.2.0) + web-console (4.2.1) actionview (>= 6.0.0) activemodel (>= 6.0.0) bindex (>= 0.4.0) @@ -402,12 +445,13 @@ GEM rubyzip (>= 1.3.0) selenium-webdriver (~> 4.0) websocket (1.2.9) - websocket-driver (0.7.5) + websocket-driver (0.8.0) + base64 websocket-extensions (>= 0.1.0) websocket-extensions (0.1.5) xpath (3.2.0) nokogiri (~> 1.8) - zeitwerk (2.6.8) + zeitwerk (2.7.3) PLATFORMS ruby @@ -442,15 +486,15 @@ DEPENDENCIES omniauth-rails_csrf_protection pagy (~> 6.0) pg (~> 1.1) - puma (~> 5.0) - rails (~> 7.0.4) + puma (~> 6.0) + rails (~> 8.0.0) rails-controller-testing rake - redis (~> 4.0) + redis (~> 5.0) rspec rspec-rails rswag - rubocop (>= 1.0, < 2.0) + rubocop (>= 1.58, < 2.0) selenium-webdriver sidekiq sprockets-rails @@ -461,7 +505,7 @@ DEPENDENCIES webdrivers RUBY VERSION - ruby 3.1.2p20 + ruby 3.4.5p51 BUNDLED WITH 2.3.25 diff --git a/Procfile.dev b/Procfile.dev index cb7c9aa8..0a6f1f08 100644 --- a/Procfile.dev +++ b/Procfile.dev @@ -1,2 +1,3 @@ web: unset PORT && bin/rails server css: yarn build:css --watch +worker: bundle exec sidekiq diff --git a/app/controllers/analytics_controller.rb b/app/controllers/analytics_controller.rb index 660984f7..60cc600f 100644 --- a/app/controllers/analytics_controller.rb +++ b/app/controllers/analytics_controller.rb @@ -2,14 +2,19 @@ class AnalyticsController < ApplicationController before_action :authenticate_member! def index - @start_date = params[:start_date] || (Date.today - 6.days).to_s - @end_date = params[:end_date] || Date.today.to_s + # Use Time.current for timezone-aware dates + today = Time.current.to_date + @start_date = params[:start_date] || (today - 6.days).to_s + @end_date = params[:end_date] || today.to_s + + # Convert string dates to timezone-aware datetime objects + start_datetime = Time.zone.parse(@start_date).beginning_of_day + end_datetime = Time.zone.parse(@end_date).end_of_day + %w[counter_analytics length_analytics unique_analytics browser_analytics].each do |analytics| instance_variable_set("@#{analytics}", current_user .send(analytics) - .where('created_at BETWEEN ? AND ?', - "#{@start_date} 00:00:00", - "#{@end_date} 23:59:59") + .where(created_at: start_datetime..end_datetime) .order(created_at: :desc)) end end diff --git a/app/controllers/api/v1/comments_controller.rb b/app/controllers/api/v1/comments_controller.rb index ece4d5db..634cfda9 100644 --- a/app/controllers/api/v1/comments_controller.rb +++ b/app/controllers/api/v1/comments_controller.rb @@ -1,5 +1,6 @@ class Api::V1::CommentsController < ApplicationController include TrackEvent + before_action :authorize_request before_action :find_member_post after_action :track_event, only: %i[create] diff --git a/app/controllers/comments_controller.rb b/app/controllers/comments_controller.rb index 82faf8e4..c03c60c5 100644 --- a/app/controllers/comments_controller.rb +++ b/app/controllers/comments_controller.rb @@ -1,5 +1,6 @@ class CommentsController < ApplicationController include TrackEvent + before_action :authenticate_member! before_action :set_post, only: %i[index new create] before_action :set_comment, only: %i[edit update destroy] diff --git a/app/controllers/posts_controller.rb b/app/controllers/posts_controller.rb index ce42b4bd..7fd604a3 100644 --- a/app/controllers/posts_controller.rb +++ b/app/controllers/posts_controller.rb @@ -13,6 +13,10 @@ def index end end + def show + # The @post and @member are already set by before_action callbacks + end + def new @post = Post.new end diff --git a/app/models/member.rb b/app/models/member.rb index 63a86055..b6bcf6b2 100644 --- a/app/models/member.rb +++ b/app/models/member.rb @@ -22,6 +22,7 @@ class Member < ApplicationRecord } extend FriendlyId + friendly_id :name, use: %i[slugged finders history] def is?(requested_role) @@ -41,7 +42,12 @@ def self.from_omniauth(access_token) member ||= Member.create(name: access_token.info.name, email: access_token.info.email, - password: Devise.friendly_token[0, 20]) + password: Devise.friendly_token[0, 20], + provider: access_token.provider, + uid: access_token.uid) + + # Update provider and uid if not set + member.update(provider: access_token.provider, uid: access_token.uid) if member.provider.blank? || member.uid.blank? if !member.avatar.attached? && !access_token.info.image.empty? filename = File.basename(URI.parse(access_token.info.image).path) @@ -51,4 +57,8 @@ def self.from_omniauth(access_token) end member end + + def oauth_user? + provider.present? && uid.present? + end end diff --git a/app/views/analytics/index.html.erb b/app/views/analytics/index.html.erb index 3e4ed272..c8a5c2d7 100644 --- a/app/views/analytics/index.html.erb +++ b/app/views/analytics/index.html.erb @@ -1,4 +1,14 @@ -
Track comments, visitors, and engagement on posts authored by <%= current_member.name %>
+📊 What's shown here:
+You signed up using <%= resource.provider.humanize %>. You cannot change your password or email here.
+To update your profile information, please do so through your <%= resource.provider.humanize %> account.
+Unhappy?
+ <%= link_to 'Cancel my account', registration_path(resource_name), data: { turbo_confirm: 'Are you sure?', turbo_method: :delete }, class:'button is-danger' %>