From 18a12afb785b19371e947c5ef72e7e28f8d9383b Mon Sep 17 00:00:00 2001 From: "Jesse C. Fisher" Date: Mon, 6 Nov 2023 17:17:00 +0000 Subject: [PATCH] Add user profiles --- app/assets/javascripts/profiles.coffee | 3 + app/assets/stylesheets/application.css.sass | 5 + app/assets/stylesheets/profiles.scss | 3 + app/controllers/application_controller.rb | 2 +- app/controllers/profiles_controller.rb | 74 ++++++++++ app/helpers/profiles_helper.rb | 2 + app/models/profile.rb | 3 + app/models/user.rb | 1 + app/policies/profile_policy.rb | 55 +++++++ app/views/layouts/_navigation_links.html.erb | 2 +- app/views/profiles/_form.html.haml | 12 ++ app/views/profiles/_profile.json.jbuilder | 2 + app/views/profiles/edit.html.haml | 3 + app/views/profiles/index.html.haml | 31 ++++ app/views/profiles/index.json.jbuilder | 1 + app/views/profiles/new.html.haml | 5 + app/views/profiles/show.html.haml | 14 ++ app/views/profiles/show.json.jbuilder | 1 + .../initializers/postgresql_database_tasks.rb | 22 +-- config/locales/pundit.en.yml | 2 + config/routes.rb | 1 + db/migrate/20231106161052_create_profiles.rb | 12 ++ db/schema.rb | 13 +- spec/factories/profiles.rb | 8 ++ spec/helpers/profiles_helper_spec.rb | 15 ++ spec/models/profile_spec.rb | 5 + spec/requests/profiles_spec.rb | 135 ++++++++++++++++++ spec/routing/profiles_routing_spec.rb | 38 +++++ spec/views/profiles/edit.html.haml_spec.rb | 31 ++++ spec/views/profiles/index.html.haml_spec.rb | 29 ++++ spec/views/profiles/new.html.haml_spec.rb | 27 ++++ spec/views/profiles/show.html.haml_spec.rb | 20 +++ 32 files changed, 563 insertions(+), 14 deletions(-) create mode 100644 app/assets/javascripts/profiles.coffee create mode 100644 app/assets/stylesheets/profiles.scss create mode 100644 app/controllers/profiles_controller.rb create mode 100644 app/helpers/profiles_helper.rb create mode 100644 app/models/profile.rb create mode 100644 app/policies/profile_policy.rb create mode 100644 app/views/profiles/_form.html.haml create mode 100644 app/views/profiles/_profile.json.jbuilder create mode 100644 app/views/profiles/edit.html.haml create mode 100644 app/views/profiles/index.html.haml create mode 100644 app/views/profiles/index.json.jbuilder create mode 100644 app/views/profiles/new.html.haml create mode 100644 app/views/profiles/show.html.haml create mode 100644 app/views/profiles/show.json.jbuilder create mode 100644 db/migrate/20231106161052_create_profiles.rb create mode 100644 spec/factories/profiles.rb create mode 100644 spec/helpers/profiles_helper_spec.rb create mode 100644 spec/models/profile_spec.rb create mode 100644 spec/requests/profiles_spec.rb create mode 100644 spec/routing/profiles_routing_spec.rb create mode 100644 spec/views/profiles/edit.html.haml_spec.rb create mode 100644 spec/views/profiles/index.html.haml_spec.rb create mode 100644 spec/views/profiles/new.html.haml_spec.rb create mode 100644 spec/views/profiles/show.html.haml_spec.rb diff --git a/app/assets/javascripts/profiles.coffee b/app/assets/javascripts/profiles.coffee new file mode 100644 index 00000000..24f83d18 --- /dev/null +++ b/app/assets/javascripts/profiles.coffee @@ -0,0 +1,3 @@ +# Place all the behaviors and hooks related to the matching controller here. +# All this logic will automatically be available in application.js. +# You can use CoffeeScript in this file: http://coffeescript.org/ diff --git a/app/assets/stylesheets/application.css.sass b/app/assets/stylesheets/application.css.sass index 954b31a8..98dbf196 100644 --- a/app/assets/stylesheets/application.css.sass +++ b/app/assets/stylesheets/application.css.sass @@ -207,4 +207,9 @@ textarea background: #00ff0060 border-radius: 0 0 0 79em +.contain + width: 100% + max-width: 1200px + padding: 1em + @import doodads diff --git a/app/assets/stylesheets/profiles.scss b/app/assets/stylesheets/profiles.scss new file mode 100644 index 00000000..4d63f1a3 --- /dev/null +++ b/app/assets/stylesheets/profiles.scss @@ -0,0 +1,3 @@ +// Place all the styles related to the Profiles controller here. +// They will automatically be included in application.css. +// You can use Sass (SCSS) here: https://sass-lang.com/ diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index 58347d6a..0fda6566 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -8,7 +8,7 @@ class ApplicationController < ActionController::Base before_action :get_footer_tokens if (Rails.env.development? || Rails.env.test?) - include Pundit + include Pundit::Authorization after_action :verify_authorized, unless: -> { devise_controller? } # after_action :verify_policy_scoped, only: :index rescue_from Pundit::NotAuthorizedError, with: :user_not_authorized diff --git a/app/controllers/profiles_controller.rb b/app/controllers/profiles_controller.rb new file mode 100644 index 00000000..c790f0a3 --- /dev/null +++ b/app/controllers/profiles_controller.rb @@ -0,0 +1,74 @@ +class ProfilesController < ApplicationController + before_action :set_profile, only: %i[ show edit update destroy ] + + # GET /profiles or /profiles.json + def index + @profiles = policy_scope Profile.all + authorize @profiles + end + + # GET /profiles/1 or /profiles/1.json + def show + authorize @profile + end + + # GET /profiles/new + def new + authorize @profile = current_user.profiles.new + end + + # GET /profiles/1/edit + def edit + authorize @profile + end + + # POST /profiles or /profiles.json + def create + authorize @profile = Profile.new(profile_params) + + respond_to do |format| + if @profile.save + format.html { redirect_to profile_url(@profile), notice: "Profile was successfully created." } + format.json { render :show, status: :created, location: @profile } + else + format.html { render :new, status: :unprocessable_entity } + format.json { render json: @profile.errors, status: :unprocessable_entity } + end + end + end + + # PATCH/PUT /profiles/1 or /profiles/1.json + def update + authorize @profile + respond_to do |format| + if @profile.update(profile_params) + format.html { redirect_to profile_url(@profile), notice: "Profile was successfully updated." } + format.json { render :show, status: :ok, location: @profile } + else + format.html { render :edit, status: :unprocessable_entity } + format.json { render json: @profile.errors, status: :unprocessable_entity } + end + end + end + + # DELETE /profiles/1 or /profiles/1.json + def destroy + @profile.destroy + + respond_to do |format| + format.html { redirect_to profiles_url, notice: "Profile was successfully destroyed." } + format.json { head :no_content } + end + end + + private + # Use callbacks to share common setup or constraints between actions. + def set_profile + @profile = Profile.find(params[:id]) + end + + # Only allow a list of trusted parameters through. + def profile_params + params.require(:profile).permit(:user_id, :name, :summary, :about) + end +end diff --git a/app/helpers/profiles_helper.rb b/app/helpers/profiles_helper.rb new file mode 100644 index 00000000..4e430508 --- /dev/null +++ b/app/helpers/profiles_helper.rb @@ -0,0 +1,2 @@ +module ProfilesHelper +end diff --git a/app/models/profile.rb b/app/models/profile.rb new file mode 100644 index 00000000..9e534f1e --- /dev/null +++ b/app/models/profile.rb @@ -0,0 +1,3 @@ +class Profile < ActiveRecord::Base + belongs_to :user +end diff --git a/app/models/user.rb b/app/models/user.rb index 0941e0b6..bd949a7c 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -6,6 +6,7 @@ class User < ActiveRecord::Base has_many :canisters has_many :doodads has_many :projects + has_many :profiles def icid stp = SoftTokenPrincipal.where(soft_token: self.soft_token).first_or_initialize diff --git a/app/policies/profile_policy.rb b/app/policies/profile_policy.rb new file mode 100644 index 00000000..7b7b9b37 --- /dev/null +++ b/app/policies/profile_policy.rb @@ -0,0 +1,55 @@ +class ProfilePolicy + attr_reader :user, :model + + def initialize(user, model) + @user = user || User.new + @profile = model + end + + class Scope + def initialize(user, scope) + @user = user + @scope = scope + end + + def resolve + if user.admin? + scope.all + else + scope.all + end + end + + private + + attr_reader :user, :scope + end + + def index? + @user.admin? || true + end + + def show? + @user.admin? || true + end + + def new? + @user.signed_in? + end + + def create? + @user.signed_in? + end + + def edit? + update? + end + + def update? + @user.admin? || @user == @profile.user + end + + def destroy? + @user.admin? || @user == @profile.user + end +end diff --git a/app/views/layouts/_navigation_links.html.erb b/app/views/layouts/_navigation_links.html.erb index 90e2af71..6f7cc08c 100644 --- a/app/views/layouts/_navigation_links.html.erb +++ b/app/views/layouts/_navigation_links.html.erb @@ -2,7 +2,7 @@