diff --git a/app/controllers/pages_controller.rb b/app/controllers/pages_controller.rb index e7d2507..8c31aa6 100644 --- a/app/controllers/pages_controller.rb +++ b/app/controllers/pages_controller.rb @@ -37,10 +37,15 @@ def home # Allows for the user to give a module code and minutes and get the time quickly logged def quick_log + minutes = params[:minutes].to_i + if minutes.nil? || minutes <= 0 + redirect_to root_path, alert: 'Time logged must be positive.' + return + end + # Strip input and find module - raw_input = params[:module_code].to_s.strip.upcase - code_number = raw_input[/\d+/] - @uni_module = UniModule.where('code LIKE ?', "%#{code_number}").first + code = params[:module_code].to_s.strip.upcase + @uni_module = UniModule.where('code LIKE ?', "%#{code}%").first # TODO: what if somebody takes like COM101 and MAT101?? diff --git a/app/controllers/users_controller.rb b/app/controllers/users_controller.rb index 335fe01..bf1eca4 100644 --- a/app/controllers/users_controller.rb +++ b/app/controllers/users_controller.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true class UsersController < ApplicationController - before_action :set_user, only: %i[show edit update destroy] + before_action :set_user, only: %i[show] authorize_resource # GET /users or /users.json @@ -27,52 +27,6 @@ def show .sum('exams.weight * uni_modules.credits / 100') end - # GET /users/new - def new - @user = User.new - end - - # GET /users/1/edit - def edit; end - - # POST /users or /users.json - def create - @user = User.new(user_params) - - respond_to do |format| - if @user.save - format.html { redirect_to @user, notice: 'User was successfully created.' } - format.json { render :show, status: :created, location: @user } - else - format.html { render :new, status: :unprocessable_entity } - format.json { render json: @user.errors, status: :unprocessable_entity } - end - end - end - - # PATCH/PUT /users/1 or /users/1.json - def update - respond_to do |format| - if @user.update(user_params) - format.html { redirect_to @user, notice: 'User was successfully updated.' } - format.json { render :show, status: :ok, location: @user } - else - format.html { render :edit, status: :unprocessable_entity } - format.json { render json: @user.errors, status: :unprocessable_entity } - end - end - end - - # DELETE /users/1 or /users/1.json - def destroy - @user.destroy! - - respond_to do |format| - format.html { redirect_to users_path, status: :see_other, notice: 'User was successfully destroyed.' } - format.json { head :no_content } - end - end - private # Use callbacks to share common setup or constraints between actions. diff --git a/app/views/semesters/show.html.haml b/app/views/semesters/show.html.haml index 2a1c2fc..fd40d80 100644 --- a/app/views/semesters/show.html.haml +++ b/app/views/semesters/show.html.haml @@ -9,7 +9,7 @@ = link_to edit_semester_path(@semester) do %i.fa-solid.fa-pen-to-square - %button#copy-share-link.icon-button{ type: 'button', 'data-clipboard-text' => share_semester_url(@semester.share_token) } + %button#copy-share-link.icon-button{ type: 'button', title: 'Copy share link', 'data-clipboard-text' => share_semester_url(@semester.share_token) } %i.fa-solid.fa-share %span#copy-success{ style: 'display:none;' } Copied! diff --git a/app/views/uni_modules/_timelogs.html.haml b/app/views/uni_modules/_timelogs.html.haml index 69f0e59..9993450 100644 --- a/app/views/uni_modules/_timelogs.html.haml +++ b/app/views/uni_modules/_timelogs.html.haml @@ -2,7 +2,7 @@ .card-heading %h2 Timelog .icon-button - = link_to new_uni_module_timelog_path(@uni_module) do + = link_to new_uni_module_timelog_path(@uni_module), title: 'Log time' do %i.fa-solid.fa-plus %table.gt-table.mt-0 %thead diff --git a/spec/factories/semester.rb b/spec/factories/semester.rb index 970da62..d4cc5d7 100644 --- a/spec/factories/semester.rb +++ b/spec/factories/semester.rb @@ -1,6 +1,11 @@ FactoryBot.define do factory :semester do + transient do + user { create(:user) } + end + name { "Semester 1" } - year + + year { create(:year, user: user) } end end \ No newline at end of file diff --git a/spec/factories/uni_module.rb b/spec/factories/uni_module.rb index 0033eac..afd4395 100644 --- a/spec/factories/uni_module.rb +++ b/spec/factories/uni_module.rb @@ -1,12 +1,12 @@ FactoryBot.define do factory :uni_module do - transient do user { create(:user) } end name { "Introduction to Software Engineering" } code { "COM1001" } - semester { create(:semester, year: create(:year, user: user)) } + + semester { create(:semester, user: user) } end -end +end \ No newline at end of file diff --git a/spec/factories/year.rb b/spec/factories/year.rb index 0d47a7b..033a3ce 100644 --- a/spec/factories/year.rb +++ b/spec/factories/year.rb @@ -1,6 +1,6 @@ FactoryBot.define do factory :year do name { "First Year" } - user + association :user end end \ No newline at end of file diff --git a/spec/system/account_spec.rb b/spec/system/account_spec.rb new file mode 100644 index 0000000..3e2d775 --- /dev/null +++ b/spec/system/account_spec.rb @@ -0,0 +1,95 @@ +require 'rails_helper' + +RSpec.describe 'Account', type: :system do + let(:user) { create(:user) } + + context 'registration' do + before(:each) do + visit new_user_registration_path + end + + it 'signs up with valid details' do + fill_in 'Email', with: "test@account.com" + fill_in 'Password', with: "Test_Password123" + fill_in 'Password confirmation', with: "Test_Password123" + + click_on 'Sign up' + + expect(page).to have_content 'Dashboard' + end + + it 'errors if an invalid email is entered' do + fill_in 'Email', with: "notanemail" + fill_in 'Password', with: "Test_Password123" + fill_in 'Password confirmation', with: "Test_Password123" + + click_on 'Sign up' + + expect(page).not_to have_content 'Dashboard' + end + + it 'errors if a password is too short' do + fill_in 'Email', with: "test@account.com" + fill_in 'Password', with: "123" + fill_in 'Password confirmation', with: "123" + + click_on 'Sign up' + + expect(page).to have_content 'Password is too short' + end + + it 'errors if confirmation does not match password' do + fill_in 'Email', with: "test@account.com" + fill_in 'Password', with: "Test_Password123" + fill_in 'Password confirmation', with: "Test_Password12345" + + click_on 'Sign up' + + expect(page).to have_content 'Password confirmation doesn' + end + end + + context 'management' do + it 'can view account details' do + login_as user + + visit user_path(user) + + expect(page).to have_content user.email + end + + it 'can edit account details' do + login_as user + + visit user_path(user) + + expect(page).to have_content user.email + + visit edit_user_registration_path + + fill_in 'Email', with: "changed@account.com" + fill_in 'Current password', with: "password" + + click_on 'Update' + + expect(page).to have_content "changed@account.com" + end + + it 'can delete account' do + login_as user + + visit edit_user_registration_path + + accept_confirm "Are you sure?" do + click_on 'Cancel my account' + end + + visit '/' + + fill_in 'Email', with: 'test@example.com' + fill_in 'Password', with: 'password' + + expect(page).not_to have_content 'Dashboard' + end + end +end \ No newline at end of file diff --git a/spec/system/log_time_spec.rb b/spec/system/log_time_spec.rb new file mode 100644 index 0000000..1b1ba1b --- /dev/null +++ b/spec/system/log_time_spec.rb @@ -0,0 +1,76 @@ +require 'rails_helper' + +RSpec.describe 'Logging time', type: :system do + let(:user) { create(:user) } + + context 'when quicklogging time from the homepage' do + it 'correctly logs minutes if the code matches a module' do + login_as user + + uni_module = create(:uni_module, user: user) + + visit '/' + + fill_in 'module_code', with: uni_module.code + fill_in 'minutes', with: 10 + + click_on 'Add Time' + + visit uni_module_path(uni_module) + + expect(page).to have_content '10' + end + + it 'informs the user if it cannot match the module code' do + login_as user + + uni_module = create(:uni_module, user: user) + + visit '/' + + fill_in 'module_code', with: uni_module.code + "123456" + fill_in 'minutes', with: 10 + + click_on 'Add Time' + + expect(page).to have_content 'Module not found.' + end + + it 'does not let the user log negative minutes' do + login_as user + + uni_module = create(:uni_module, user: user) + + visit '/' + + fill_in 'module_code', with: uni_module.code + fill_in 'minutes', with: -1 + + click_on 'Add Time' + + expect(page).to have_content 'Time logged must be positive.' + end + end + + context 'when logging time on the module page' do + it 'lets the user add a timelog with a description' do + login_as user + + uni_module = create(:uni_module, user: user) + + visit uni_module_path(uni_module) + + find('a[title="Log time"]').click + + within '#new_timelog' do + fill_in 'Minutes', with: 28 + fill_in 'Description', with: 'Working on some stuff' + end + + click_on 'Save' + + expect(page).to have_content '28' + expect(page).to have_content 'Working on some stuff' + end + end +end \ No newline at end of file diff --git a/spec/system/sharing_setup_spec.rb b/spec/system/sharing_setup_spec.rb new file mode 100644 index 0000000..ae05428 --- /dev/null +++ b/spec/system/sharing_setup_spec.rb @@ -0,0 +1,41 @@ +require 'rails_helper' + +RSpec.describe 'Sharing setup', type: :system do + let(:user) { create(:user) } + + context 'when you click the share button on semester' do + it 'copies a shareable link to the semester' do + login_as user + + semester = create(:semester, user: user) + + visit semester_path(semester) + + expect(page).to have_selector('button[title="Copy share link"]') + find('button[title="Copy share link"]').click + + expect(page).to have_content 'Copied!' + end + end + + context 'when you follow the given link' do + it 'lets you import the semester to a new year' do + login_as user + + year = create(:year, user: user) + semester = create(:semester, year: year) + + visit share_semester_path(semester.share_token) + + click_on 'Import this Semester to My Account' + + select 'Create New Year...', from: 'year-select' + + click_on 'Import' + + visit year_path(year) + + expect(page).to have_content semester.name + end + end +end \ No newline at end of file