diff --git a/app/assets/javascripts/admin/courses.js b/app/assets/javascripts/admin/courses.js new file mode 100644 index 0000000..dee720f --- /dev/null +++ b/app/assets/javascripts/admin/courses.js @@ -0,0 +1,2 @@ +// Place all the behaviors and hooks related to the matching controller here. +// All this logic will automatically be available in application.js. diff --git a/app/assets/stylesheets/admin/courses.css b/app/assets/stylesheets/admin/courses.css new file mode 100644 index 0000000..afad32d --- /dev/null +++ b/app/assets/stylesheets/admin/courses.css @@ -0,0 +1,4 @@ +/* + Place all the styles related to the matching controller here. + They will automatically be included in application.css. +*/ diff --git a/app/assets/stylesheets/sb-admin-2.css b/app/assets/stylesheets/sb-admin-2.css index e6329f5..fde5549 100644 --- a/app/assets/stylesheets/sb-admin-2.css +++ b/app/assets/stylesheets/sb-admin-2.css @@ -217,6 +217,12 @@ table { border-collapse: collapse; } +.table td.fit, +.table th.fit { + white-space: nowrap; + width: 1%; +} + caption { padding-top: 0.75rem; padding-bottom: 0.75rem; diff --git a/app/controllers/admin/courses_controller.rb b/app/controllers/admin/courses_controller.rb new file mode 100644 index 0000000..61beeeb --- /dev/null +++ b/app/controllers/admin/courses_controller.rb @@ -0,0 +1,87 @@ +# frozen_string_literal: true + +module Admin + # Kursy + class CoursesController < ApplicationController + before_action :set_object, only: %i[show edit update destroy] + + # GET /admin/courses + # GET /admin/courses.json + def index + collection + end + + # GET /admin/courses/1 + # GET /admin/courses/1.json + def show; end + + # GET /admin/courses/new + def new + @course = Course.new + end + + # GET /admin/courses/1/edit + def edit; end + + # POST /admin/courses + # POST /admin/courses.json + def create + @course = Course.new(admin_course_params) + + respond_to do |format| + if @course.save + format.js { collection } + format.html { redirect_to [:admin, @course], notice: 'Course was successfully created.' } + format.json { render :show, status: :created, location: @course } + else + format.js { render :new } + format.html { render :new } + format.json { render json: @course.errors, status: :unprocessable_entity } + end + end + end + + # PATCH/PUT /admin/courses/1 + # PATCH/PUT /admin/courses/1.json + def update + respond_to do |format| + if @course.update(admin_course_params) + format.js { collection } + format.html { redirect_to [:admin, @course], notice: 'Course was successfully updated.' } + format.json { render :show, status: :ok, location: @course } + else + format.js { render :edit } + format.html { render :edit } + format.json { render json: @course.errors, status: :unprocessable_entity } + end + end + end + + # DELETE /admin/courses/1 + # DELETE /admin/courses/1.json + def destroy + @course.destroy + respond_to do |format| + format.js { collection } + format.html { redirect_to admin_courses_url, notice: 'Course was successfully destroyed.' } + format.json { head :no_content } + end + end + + private + + # Use callbacks to share common setup or constraints between actions. + def set_object + @course = Course.find(params[:id]) + end + + def collection + @courses = Course.all + end + + # Never trust parameters from the scary internet, only allow the white list through. + def admin_course_params + params.require(:course).permit(:name, :description) + end + end +end diff --git a/app/helpers/admin/courses_helper.rb b/app/helpers/admin/courses_helper.rb new file mode 100644 index 0000000..4d6c57b --- /dev/null +++ b/app/helpers/admin/courses_helper.rb @@ -0,0 +1,2 @@ +module Admin::CoursesHelper +end diff --git a/app/helpers/sidemenu_helper.rb b/app/helpers/sidemenu_helper.rb index 5b43fdd..3a876ad 100644 --- a/app/helpers/sidemenu_helper.rb +++ b/app/helpers/sidemenu_helper.rb @@ -6,6 +6,7 @@ module SidemenuHelper ret = nav_link('home', '/', 'home', 'fa-home') ret += divider ret += heading('Admin') + ret += nav_link('courses', '/admin/courses', 'admin/courses', 'fa-tv') submenu = ['users.user_management', ['users.accounts', '/admin/users', 'admin/users', 'fa-user-circle'], 'users.finance', diff --git a/app/models/course.rb b/app/models/course.rb index 25e8ed7..5c9d422 100644 --- a/app/models/course.rb +++ b/app/models/course.rb @@ -1,2 +1,6 @@ +# frozen_string_literal: true + class Course < ApplicationRecord + has_many :weeks, dependent: :destroy + validates :name, presence: true end diff --git a/app/views/admin/courses/create.js.erb b/app/views/admin/courses/create.js.erb new file mode 100644 index 0000000..2dee7ba --- /dev/null +++ b/app/views/admin/courses/create.js.erb @@ -0,0 +1,2 @@ +$('#ajax_form').slideUp(); +$('#ajax_list').html("<%= escape_javascript(render('/admin/courses/partials/courses')) %>"); diff --git a/app/views/admin/courses/destroy.js.erb b/app/views/admin/courses/destroy.js.erb new file mode 100644 index 0000000..559a772 --- /dev/null +++ b/app/views/admin/courses/destroy.js.erb @@ -0,0 +1 @@ +$('#ajax_list').html("<%= escape_javascript(render('/admin/courses/partials/courses')) %>"); diff --git a/app/views/admin/courses/edit.html.erb b/app/views/admin/courses/edit.html.erb new file mode 100644 index 0000000..270e905 --- /dev/null +++ b/app/views/admin/courses/edit.html.erb @@ -0,0 +1 @@ +<%= render '/admin/courses/partials/edit' %> diff --git a/app/views/admin/courses/edit.js.erb b/app/views/admin/courses/edit.js.erb new file mode 100644 index 0000000..96b5511 --- /dev/null +++ b/app/views/admin/courses/edit.js.erb @@ -0,0 +1,2 @@ +$("#ajax_form").html("<%= escape_javascript(render('admin/courses/partials/edit')) %>"); +$("#ajax_form").slideDown(); diff --git a/app/views/admin/courses/index.html.erb b/app/views/admin/courses/index.html.erb new file mode 100644 index 0000000..5b83097 --- /dev/null +++ b/app/views/admin/courses/index.html.erb @@ -0,0 +1,22 @@ +

Kursy

+

Tutaj jakiś opis.

+

<%= notice %>

+
+
+ +
+
+
Lista kursów
+ <%= link_to raw(' Dodaj Nowy Kurs'), new_admin_course_path, { remote: true, class: 'btn btn-sm btn-primary float-right' } %> +
+
+
+
+ <%= render partial: '/admin/courses/partials/courses' %> +
+
+ +
+ +
+
diff --git a/app/views/admin/courses/index.json.jbuilder b/app/views/admin/courses/index.json.jbuilder new file mode 100644 index 0000000..560e921 --- /dev/null +++ b/app/views/admin/courses/index.json.jbuilder @@ -0,0 +1 @@ +json.array! @courses, partial: '/admin/courses/partials/admin_course', as: :course diff --git a/app/views/admin/courses/new.html.erb b/app/views/admin/courses/new.html.erb new file mode 100644 index 0000000..2e0ce29 --- /dev/null +++ b/app/views/admin/courses/new.html.erb @@ -0,0 +1 @@ +<%= render partial: '/admin/courses/partials/form' %> diff --git a/app/views/admin/courses/new.js.erb b/app/views/admin/courses/new.js.erb new file mode 100644 index 0000000..d73a0b8 --- /dev/null +++ b/app/views/admin/courses/new.js.erb @@ -0,0 +1,2 @@ +$("#ajax_form").html("<%= escape_javascript(render('admin/courses/partials/new')) %>"); +$("#ajax_form").slideDown(); diff --git a/app/views/admin/courses/partials/_admin_course.json.jbuilder b/app/views/admin/courses/partials/_admin_course.json.jbuilder new file mode 100644 index 0000000..6c395cb --- /dev/null +++ b/app/views/admin/courses/partials/_admin_course.json.jbuilder @@ -0,0 +1,2 @@ +json.extract! course, :id, :name, :description, :created_at, :updated_at +json.url admin_course_url(course, format: :json) diff --git a/app/views/admin/courses/partials/_courses.html.erb b/app/views/admin/courses/partials/_courses.html.erb new file mode 100644 index 0000000..5199ec9 --- /dev/null +++ b/app/views/admin/courses/partials/_courses.html.erb @@ -0,0 +1,21 @@ + + + + + + + + + + <% @courses.each do |course| %> + + + + + + <% end %> + +
NazwaOpisAkcje
<%= link_to course.name, [:admin, course] %><%= course.description %> + <%= link_to raw(''), edit_admin_course_path(course), { remote: true, class: 'btn btn-sm btn-info', title: t('edit') } %> + <%= link_to raw(''), [:admin, course], { remote: true, class: 'btn btn-sm btn-danger', method: :delete, data:{ confirm: t('confirm_delete') }, title: t('delete')} %> +
diff --git a/app/views/admin/courses/partials/_edit.html.erb b/app/views/admin/courses/partials/_edit.html.erb new file mode 100644 index 0000000..b0cfce7 --- /dev/null +++ b/app/views/admin/courses/partials/_edit.html.erb @@ -0,0 +1,13 @@ +
+
+ +
+
+
Edycja kursu
+
+
+ <%= render '/admin/courses/partials/form', course: @course %> +
+
+
+
diff --git a/app/views/admin/courses/partials/_form.html.erb b/app/views/admin/courses/partials/_form.html.erb new file mode 100644 index 0000000..44621d2 --- /dev/null +++ b/app/views/admin/courses/partials/_form.html.erb @@ -0,0 +1,25 @@ +<%= form_with(model: [:admin, course]) do |form| %> + <% if course.errors.any? %> +
+

<%= pluralize(course.errors.count, "error") %> prohibited this admin_course from being saved:

+ + +
+ <% end %> +
+
+ <%= form.label :name %> + <%= form.text_field :name, class: 'form-control' %> +
+ +
+ <%= form.label :description %> + <%= form.text_area :description, class: 'form-control' %> +
+
+ <%= form.submit 'Zapisz', class: 'btn btn-primary' %> +<% end %> diff --git a/app/views/admin/courses/partials/_new.html.erb b/app/views/admin/courses/partials/_new.html.erb new file mode 100644 index 0000000..8358323 --- /dev/null +++ b/app/views/admin/courses/partials/_new.html.erb @@ -0,0 +1,13 @@ +
+
+ +
+
+
Nowy kurs
+
+
+ <%= render '/admin/courses/partials/form', course: @course %> +
+
+
+
diff --git a/app/views/admin/courses/show.html.erb b/app/views/admin/courses/show.html.erb new file mode 100644 index 0000000..27cc5fa --- /dev/null +++ b/app/views/admin/courses/show.html.erb @@ -0,0 +1,6 @@ +

Kurs: <%= @course.name %>

+

<%= @course.description %>

+ + + +<%= link_to 'Back', admin_courses_path %> diff --git a/app/views/admin/courses/show.json.jbuilder b/app/views/admin/courses/show.json.jbuilder new file mode 100644 index 0000000..f3bf1c8 --- /dev/null +++ b/app/views/admin/courses/show.json.jbuilder @@ -0,0 +1 @@ +json.partial! "/admin/courses/partials/admin_course", course: @course diff --git a/app/views/admin/courses/update.js.erb b/app/views/admin/courses/update.js.erb new file mode 100644 index 0000000..2dee7ba --- /dev/null +++ b/app/views/admin/courses/update.js.erb @@ -0,0 +1,2 @@ +$('#ajax_form').slideUp(); +$('#ajax_list').html("<%= escape_javascript(render('/admin/courses/partials/courses')) %>"); diff --git a/app/views/layouts/application.html.erb b/app/views/layouts/application.html.erb index 6442e5a..0742f49 100644 --- a/app/views/layouts/application.html.erb +++ b/app/views/layouts/application.html.erb @@ -123,7 +123,7 @@ Activity Log - <%= link_to(raw(" #{t('logout')}"), destroy_user_session_path, method: :delete, class: "dropdown-item") %> + <%= link_to(raw(" #{t('logout')}"), destroy_user_session_path, method: :delete, class: "dropdown-item") %> @@ -134,7 +134,9 @@ - <%= yield %> +
+ <%= yield %> +
diff --git a/config/locales/pl/menu.yml b/config/locales/pl/menu.yml index e695641..697741a 100644 --- a/config/locales/pl/menu.yml +++ b/config/locales/pl/menu.yml @@ -10,4 +10,5 @@ pl: admin: 'Admin' settings: 'Ustawienia' configuration: 'Konfiguracja' + courses: 'Kursy' placeholder: 'plac' diff --git a/config/routes.rb b/config/routes.rb index 3c41a74..0ec8d75 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -1,4 +1,7 @@ Rails.application.routes.draw do + namespace :admin do + resources :courses + end get 'tests/index' get 'tests/test' namespace :admin do diff --git a/spec/controllers/admin/courses_controller_spec.rb b/spec/controllers/admin/courses_controller_spec.rb new file mode 100644 index 0000000..06735b0 --- /dev/null +++ b/spec/controllers/admin/courses_controller_spec.rb @@ -0,0 +1,141 @@ +require 'rails_helper' + +# This spec was generated by rspec-rails when you ran the scaffold generator. +# It demonstrates how one might use RSpec to specify the controller code that +# was generated by Rails when you ran the scaffold generator. +# +# It assumes that the implementation code is generated by the rails scaffold +# generator. If you are using any extension libraries to generate different +# controller code, this generated spec may or may not pass. +# +# It only uses APIs available in rails and/or rspec-rails. There are a number +# of tools you can use to make these specs even more expressive, but we're +# sticking to rails and rspec-rails APIs to keep things simple and stable. +# +# Compared to earlier versions of this generator, there is very limited use of +# stubs and message expectations in this spec. Stubs are only used when there +# is no simpler way to get a handle on the object needed for the example. +# Message expectations are only used when there is no simpler way to specify +# that an instance is receiving a specific message. +# +# Also compared to earlier versions of this generator, there are no longer any +# expectations of assigns and templates rendered. These features have been +# removed from Rails core in Rails 5, but can be added back in via the +# `rails-controller-testing` gem. + +RSpec.describe Admin::CoursesController, type: :controller do + + # This should return the minimal set of attributes required to create a valid + # Admin::Course. As you add validations to Admin::Course, be sure to + # adjust the attributes here as well. + let(:valid_attributes) { + skip("Add a hash of attributes valid for your model") + } + + let(:invalid_attributes) { + skip("Add a hash of attributes invalid for your model") + } + + # This should return the minimal set of values that should be in the session + # in order to pass any filters (e.g. authentication) defined in + # Admin::CoursesController. Be sure to keep this updated too. + let(:valid_session) { {} } + + describe "GET #index" do + it "returns a success response" do + Admin::Course.create! valid_attributes + get :index, params: {}, session: valid_session + expect(response).to be_successful + end + end + + describe "GET #show" do + it "returns a success response" do + course = Admin::Course.create! valid_attributes + get :show, params: {id: course.to_param}, session: valid_session + expect(response).to be_successful + end + end + + describe "GET #new" do + it "returns a success response" do + get :new, params: {}, session: valid_session + expect(response).to be_successful + end + end + + describe "GET #edit" do + it "returns a success response" do + course = Admin::Course.create! valid_attributes + get :edit, params: {id: course.to_param}, session: valid_session + expect(response).to be_successful + end + end + + describe "POST #create" do + context "with valid params" do + it "creates a new Admin::Course" do + expect { + post :create, params: {admin_course: valid_attributes}, session: valid_session + }.to change(Admin::Course, :count).by(1) + end + + it "redirects to the created admin_course" do + post :create, params: {admin_course: valid_attributes}, session: valid_session + expect(response).to redirect_to(Admin::Course.last) + end + end + + context "with invalid params" do + it "returns a success response (i.e. to display the 'new' template)" do + post :create, params: {admin_course: invalid_attributes}, session: valid_session + expect(response).to be_successful + end + end + end + + describe "PUT #update" do + context "with valid params" do + let(:new_attributes) { + skip("Add a hash of attributes valid for your model") + } + + it "updates the requested admin_course" do + course = Admin::Course.create! valid_attributes + put :update, params: {id: course.to_param, admin_course: new_attributes}, session: valid_session + course.reload + skip("Add assertions for updated state") + end + + it "redirects to the admin_course" do + course = Admin::Course.create! valid_attributes + put :update, params: {id: course.to_param, admin_course: valid_attributes}, session: valid_session + expect(response).to redirect_to(course) + end + end + + context "with invalid params" do + it "returns a success response (i.e. to display the 'edit' template)" do + course = Admin::Course.create! valid_attributes + put :update, params: {id: course.to_param, admin_course: invalid_attributes}, session: valid_session + expect(response).to be_successful + end + end + end + + describe "DELETE #destroy" do + it "destroys the requested admin_course" do + course = Admin::Course.create! valid_attributes + expect { + delete :destroy, params: {id: course.to_param}, session: valid_session + }.to change(Admin::Course, :count).by(-1) + end + + it "redirects to the admin_courses list" do + course = Admin::Course.create! valid_attributes + delete :destroy, params: {id: course.to_param}, session: valid_session + expect(response).to redirect_to(admin_courses_url) + end + end + +end diff --git a/spec/factories/admin/courses.rb b/spec/factories/admin/courses.rb new file mode 100644 index 0000000..870f999 --- /dev/null +++ b/spec/factories/admin/courses.rb @@ -0,0 +1,6 @@ +FactoryBot.define do + factory :admin_course, class: 'Admin::Course' do + name { "MyString" } + description { "MyText" } + end +end diff --git a/spec/helpers/admin/courses_helper_spec.rb b/spec/helpers/admin/courses_helper_spec.rb new file mode 100644 index 0000000..201a7c9 --- /dev/null +++ b/spec/helpers/admin/courses_helper_spec.rb @@ -0,0 +1,15 @@ +require 'rails_helper' + +# Specs in this file have access to a helper object that includes +# the Admin::CoursesHelper. For example: +# +# describe Admin::CoursesHelper do +# describe "string concat" do +# it "concats two strings with spaces" do +# expect(helper.concat_strings("this","that")).to eq("this that") +# end +# end +# end +RSpec.describe Admin::CoursesHelper, type: :helper do + pending "add some examples to (or delete) #{__FILE__}" +end diff --git a/spec/models/admin/course_spec.rb b/spec/models/admin/course_spec.rb new file mode 100644 index 0000000..bc3f1c6 --- /dev/null +++ b/spec/models/admin/course_spec.rb @@ -0,0 +1,5 @@ +require 'rails_helper' + +RSpec.describe Admin::Course, type: :model do + pending "add some examples to (or delete) #{__FILE__}" +end diff --git a/spec/requests/admin/courses_spec.rb b/spec/requests/admin/courses_spec.rb new file mode 100644 index 0000000..bc23862 --- /dev/null +++ b/spec/requests/admin/courses_spec.rb @@ -0,0 +1,10 @@ +require 'rails_helper' + +RSpec.describe "Admin::Courses", type: :request do + describe "GET /admin/courses" do + it "works! (now write some real specs)" do + get admin_courses_path + expect(response).to have_http_status(200) + end + end +end diff --git a/spec/routing/admin/courses_routing_spec.rb b/spec/routing/admin/courses_routing_spec.rb new file mode 100644 index 0000000..8a60182 --- /dev/null +++ b/spec/routing/admin/courses_routing_spec.rb @@ -0,0 +1,38 @@ +require "rails_helper" + +RSpec.describe Admin::CoursesController, type: :routing do + describe "routing" do + it "routes to #index" do + expect(:get => "/admin/courses").to route_to("admin/courses#index") + end + + it "routes to #new" do + expect(:get => "/admin/courses/new").to route_to("admin/courses#new") + end + + it "routes to #show" do + expect(:get => "/admin/courses/1").to route_to("admin/courses#show", :id => "1") + end + + it "routes to #edit" do + expect(:get => "/admin/courses/1/edit").to route_to("admin/courses#edit", :id => "1") + end + + + it "routes to #create" do + expect(:post => "/admin/courses").to route_to("admin/courses#create") + end + + it "routes to #update via PUT" do + expect(:put => "/admin/courses/1").to route_to("admin/courses#update", :id => "1") + end + + it "routes to #update via PATCH" do + expect(:patch => "/admin/courses/1").to route_to("admin/courses#update", :id => "1") + end + + it "routes to #destroy" do + expect(:delete => "/admin/courses/1").to route_to("admin/courses#destroy", :id => "1") + end + end +end diff --git a/spec/views/admin/courses/edit.html.erb_spec.rb b/spec/views/admin/courses/edit.html.erb_spec.rb new file mode 100644 index 0000000..2547ee4 --- /dev/null +++ b/spec/views/admin/courses/edit.html.erb_spec.rb @@ -0,0 +1,21 @@ +require 'rails_helper' + +RSpec.describe "admin/courses/edit", type: :view do + before(:each) do + @admin_course = assign(:admin_course, Admin::Course.create!( + :name => "MyString", + :description => "MyText" + )) + end + + it "renders the edit admin_course form" do + render + + assert_select "form[action=?][method=?]", admin_course_path(@admin_course), "post" do + + assert_select "input[name=?]", "admin_course[name]" + + assert_select "textarea[name=?]", "admin_course[description]" + end + end +end diff --git a/spec/views/admin/courses/index.html.erb_spec.rb b/spec/views/admin/courses/index.html.erb_spec.rb new file mode 100644 index 0000000..2b15056 --- /dev/null +++ b/spec/views/admin/courses/index.html.erb_spec.rb @@ -0,0 +1,22 @@ +require 'rails_helper' + +RSpec.describe "admin/courses/index", type: :view do + before(:each) do + assign(:admin_courses, [ + Admin::Course.create!( + :name => "Name", + :description => "MyText" + ), + Admin::Course.create!( + :name => "Name", + :description => "MyText" + ) + ]) + end + + it "renders a list of admin/courses" do + render + assert_select "tr>td", :text => "Name".to_s, :count => 2 + assert_select "tr>td", :text => "MyText".to_s, :count => 2 + end +end diff --git a/spec/views/admin/courses/new.html.erb_spec.rb b/spec/views/admin/courses/new.html.erb_spec.rb new file mode 100644 index 0000000..165a297 --- /dev/null +++ b/spec/views/admin/courses/new.html.erb_spec.rb @@ -0,0 +1,21 @@ +require 'rails_helper' + +RSpec.describe "admin/courses/new", type: :view do + before(:each) do + assign(:admin_course, Admin::Course.new( + :name => "MyString", + :description => "MyText" + )) + end + + it "renders new admin_course form" do + render + + assert_select "form[action=?][method=?]", admin_courses_path, "post" do + + assert_select "input[name=?]", "admin_course[name]" + + assert_select "textarea[name=?]", "admin_course[description]" + end + end +end diff --git a/spec/views/admin/courses/show.html.erb_spec.rb b/spec/views/admin/courses/show.html.erb_spec.rb new file mode 100644 index 0000000..316d1eb --- /dev/null +++ b/spec/views/admin/courses/show.html.erb_spec.rb @@ -0,0 +1,16 @@ +require 'rails_helper' + +RSpec.describe "admin/courses/show", type: :view do + before(:each) do + @admin_course = assign(:admin_course, Admin::Course.create!( + :name => "Name", + :description => "MyText" + )) + end + + it "renders attributes in

" do + render + expect(rendered).to match(/Name/) + expect(rendered).to match(/MyText/) + end +end