# HG changeset patch # User Nattee Niparnan # Date 2017-09-16 03:20:15 # Node ID bc0fcfe3abaab2dec7f1568c78de35f3d7f2d79e # Parent 4ce0b8696d06d5dcb0867cc7f6c5f24faaba6efe tag diff --git a/app/assets/javascripts/tags.coffee b/app/assets/javascripts/tags.coffee new file mode 100644 --- /dev/null +++ b/app/assets/javascripts/tags.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/tags.scss b/app/assets/stylesheets/tags.scss new file mode 100644 --- /dev/null +++ b/app/assets/stylesheets/tags.scss @@ -0,0 +1,3 @@ +// Place all the styles related to the tags controller here. +// They will automatically be included in application.css. +// You can use Sass (SCSS) here: http://sass-lang.com/ diff --git a/app/controllers/tags_controller.rb b/app/controllers/tags_controller.rb new file mode 100644 --- /dev/null +++ b/app/controllers/tags_controller.rb @@ -0,0 +1,58 @@ +class TagsController < ApplicationController + before_action :set_tag, only: [:show, :edit, :update, :destroy] + + # GET /tags + def index + @tags = Tag.all + end + + # GET /tags/1 + def show + end + + # GET /tags/new + def new + @tag = Tag.new + end + + # GET /tags/1/edit + def edit + end + + # POST /tags + def create + @tag = Tag.new(tag_params) + + if @tag.save + redirect_to @tag, notice: 'Tag was successfully created.' + else + render :new + end + end + + # PATCH/PUT /tags/1 + def update + if @tag.update(tag_params) + redirect_to @tag, notice: 'Tag was successfully updated.' + else + render :edit + end + end + + # DELETE /tags/1 + def destroy + @tag.destroy + redirect_to tags_url, notice: 'Tag was successfully destroyed.' + end + + private + # Use callbacks to share common setup or constraints between actions. + def set_tag + @tag = Tag.find(params[:id]) + end + + # Only allow a trusted parameter "white list" through. + def tag_params + params.require(:tag).permit(:name, :description, :public) + end +end diff --git a/app/helpers/tags_helper.rb b/app/helpers/tags_helper.rb new file mode 100644 --- /dev/null +++ b/app/helpers/tags_helper.rb @@ -0,0 +1,2 @@ +module TagsHelper +end diff --git a/app/models/group_user.rb b/app/models/group_user.rb --- a/app/models/group_user.rb +++ b/app/models/group_user.rb @@ -1,6 +1,6 @@ class GroupUser < ActiveRecord::Base self.table_name = 'groups_users' - + belongs_to :user belongs_to :group validates_uniqueness_of :user_id, scope: :group_id, message: ->(object, data) { "'#{User.find(data[:value]).full_name}' is already in the group" } diff --git a/app/models/problem.rb b/app/models/problem.rb --- a/app/models/problem.rb +++ b/app/models/problem.rb @@ -7,6 +7,9 @@ has_many :groups_problems, class_name: GroupProblem has_many :groups, :through => :groups_problems + has_many :problems_tags, class_name: ProblemTag + has_many :tags, through: :problems_tags + has_many :test_pairs, :dependent => :delete_all has_many :testcases, :dependent => :destroy diff --git a/app/models/problem_tag.rb b/app/models/problem_tag.rb new file mode 100644 --- /dev/null +++ b/app/models/problem_tag.rb @@ -0,0 +1,8 @@ +class ProblemTag < ActiveRecord::Base + self.table_name = 'problems_tags' + + belongs_to :problem + belongs_to :tag + + validates_uniqueness_of :problem_id, scope: :tag_id, message: ->(object, data) { "'#{Problem.find(data[:value]).full_name}' is already has this tag" } +end diff --git a/app/models/tag.rb b/app/models/tag.rb new file mode 100644 --- /dev/null +++ b/app/models/tag.rb @@ -0,0 +1,4 @@ +class Tag < ActiveRecord::Base + has_many :problems_tags, class_name: ProblemTag + has_many :problems, through: :problems_tags +end diff --git a/app/views/tags/_form.html.haml b/app/views/tags/_form.html.haml new file mode 100644 --- /dev/null +++ b/app/views/tags/_form.html.haml @@ -0,0 +1,22 @@ += form_for @tag do |f| + - if @tag.errors.any? + #error_explanation + %h2= "#{pluralize(@tag.errors.count, "error")} prohibited this tag from being saved:" + %ul + - @tag.errors.full_messages.each do |msg| + %li= msg + + .row + .col-md-6 + .form-group.field + = f.label :name + = f.text_field :name, class: 'form-control' + .form-group.field + = f.label :description + = f.text_area :description, class: 'form-control' + .form-group.field + = f.label :public + = f.text_field :public, class: 'form-control' + .actions + = f.submit 'Save', class: 'btn btn-primary' + .col-md-6 diff --git a/app/views/tags/edit.html.haml b/app/views/tags/edit.html.haml new file mode 100644 --- /dev/null +++ b/app/views/tags/edit.html.haml @@ -0,0 +1,7 @@ +%h1 Editing tag + += render 'form' + += link_to 'Show', @tag +\| += link_to 'Back', tags_path diff --git a/app/views/tags/index.html.haml b/app/views/tags/index.html.haml new file mode 100644 --- /dev/null +++ b/app/views/tags/index.html.haml @@ -0,0 +1,26 @@ +%h1 Tags + += link_to 'New Tag', new_tag_path, class: 'btn btn-success' + +%table.table.table-hover + %thead + %tr + %th Name + %th Description + %th Public + %th + %th + %th + + %tbody + - @tags.each do |tag| + %tr + %td= tag.name + %td= tag.description + %td= tag.public + %td= link_to 'Show', tag + %td= link_to 'Edit', edit_tag_path(tag) + %td= link_to 'Destroy', tag, :method => :delete, :data => { :confirm => 'Are you sure?' } + +%br + diff --git a/app/views/tags/new.html.haml b/app/views/tags/new.html.haml new file mode 100644 --- /dev/null +++ b/app/views/tags/new.html.haml @@ -0,0 +1,5 @@ +%h1 New tag + += render 'form' + += link_to 'Back', tags_path diff --git a/app/views/tags/show.html.haml b/app/views/tags/show.html.haml new file mode 100644 --- /dev/null +++ b/app/views/tags/show.html.haml @@ -0,0 +1,15 @@ +%p#notice= notice + +%p + %b Name: + = @tag.name +%p + %b Description: + = @tag.description +%p + %b Public: + = @tag.public + += link_to 'Edit', edit_tag_path(@tag) +\| += link_to 'Back', tags_path diff --git a/config/initializers/assets.rb b/config/initializers/assets.rb --- a/config/initializers/assets.rb +++ b/config/initializers/assets.rb @@ -18,6 +18,6 @@ Rails.application.config.assets.precompile += ['local_jquery.js','tablesorter-theme.cafe.css'] %w( announcements submissions configurations contests contest_management graders heartbeat login main messages problems report site sites sources tasks groups - test user_admin users ).each do |controller| + test user_admin users tags).each do |controller| Rails.application.config.assets.precompile += ["#{controller}.js", "#{controller}.css"] end diff --git a/config/routes.rb b/config/routes.rb --- a/config/routes.rb +++ b/config/routes.rb @@ -1,4 +1,5 @@ CafeGrader::Application.routes.draw do + resources :tags get "sources/direct_edit" root :to => 'main#login' diff --git a/db/migrate/20170914150545_create_tags.rb b/db/migrate/20170914150545_create_tags.rb new file mode 100644 --- /dev/null +++ b/db/migrate/20170914150545_create_tags.rb @@ -0,0 +1,11 @@ +class CreateTags < ActiveRecord::Migration + def change + create_table :tags do |t| + t.string :name, null: false + t.text :description + t.boolean :public + + t.timestamps null: false + end + end +end diff --git a/db/migrate/20170914150742_create_problem_tags.rb b/db/migrate/20170914150742_create_problem_tags.rb new file mode 100644 --- /dev/null +++ b/db/migrate/20170914150742_create_problem_tags.rb @@ -0,0 +1,10 @@ +class CreateProblemTags < ActiveRecord::Migration + def change + create_table :problems_tags do |t| + t.references :problem, index: true, foreign_key: true + t.references :tag, index: true, foreign_key: true + + t.index [:problem_id,:tag_id], unique: true + end + end +end diff --git a/db/schema.rb b/db/schema.rb --- a/db/schema.rb +++ b/db/schema.rb @@ -11,7 +11,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema.define(version: 20170911091143) do +ActiveRecord::Schema.define(version: 20170914150742) do create_table "announcements", force: :cascade do |t| t.string "author", limit: 255 @@ -146,6 +146,15 @@ t.boolean "view_testcase" end + create_table "problems_tags", force: :cascade do |t| + t.integer "problem_id", limit: 4 + t.integer "tag_id", limit: 4 + end + + add_index "problems_tags", ["problem_id", "tag_id"], name: "index_problems_tags_on_problem_id_and_tag_id", unique: true, using: :btree + add_index "problems_tags", ["problem_id"], name: "index_problems_tags_on_problem_id", using: :btree + add_index "problems_tags", ["tag_id"], name: "index_problems_tags_on_tag_id", using: :btree + create_table "rights", force: :cascade do |t| t.string "name", limit: 255 t.string "controller", limit: 255 @@ -219,6 +228,14 @@ add_index "submissions", ["user_id", "problem_id", "number"], name: "index_submissions_on_user_id_and_problem_id_and_number", unique: true, using: :btree add_index "submissions", ["user_id", "problem_id"], name: "index_submissions_on_user_id_and_problem_id", using: :btree + create_table "tags", force: :cascade do |t| + t.string "name", limit: 255, null: false + t.text "description", limit: 65535 + t.boolean "public" + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + end + create_table "tasks", force: :cascade do |t| t.integer "submission_id", limit: 4 t.datetime "created_at" @@ -299,4 +316,6 @@ add_index "users", ["login"], name: "index_users_on_login", unique: true, using: :btree + add_foreign_key "problems_tags", "problems" + add_foreign_key "problems_tags", "tags" end diff --git a/test/controllers/tags_controller_test.rb b/test/controllers/tags_controller_test.rb new file mode 100644 --- /dev/null +++ b/test/controllers/tags_controller_test.rb @@ -0,0 +1,49 @@ +require 'test_helper' + +class TagsControllerTest < ActionController::TestCase + setup do + @tag = tags(:one) + end + + test "should get index" do + get :index + assert_response :success + assert_not_nil assigns(:tags) + end + + test "should get new" do + get :new + assert_response :success + end + + test "should create tag" do + assert_difference('Tag.count') do + post :create, tag: { description: @tag.description, name: @tag.name, public: @tag.public } + end + + assert_redirected_to tag_path(assigns(:tag)) + end + + test "should show tag" do + get :show, id: @tag + assert_response :success + end + + test "should get edit" do + get :edit, id: @tag + assert_response :success + end + + test "should update tag" do + patch :update, id: @tag, tag: { description: @tag.description, name: @tag.name, public: @tag.public } + assert_redirected_to tag_path(assigns(:tag)) + end + + test "should destroy tag" do + assert_difference('Tag.count', -1) do + delete :destroy, id: @tag + end + + assert_redirected_to tags_path + end +end diff --git a/test/fixtures/problem_tags.yml b/test/fixtures/problem_tags.yml new file mode 100644 --- /dev/null +++ b/test/fixtures/problem_tags.yml @@ -0,0 +1,9 @@ +# Read about fixtures at http://api.rubyonrails.org/classes/ActiveRecord/FixtureSet.html + +one: + problem_id: + tag_id: + +two: + problem_id: + tag_id: diff --git a/test/fixtures/tags.yml b/test/fixtures/tags.yml new file mode 100644 --- /dev/null +++ b/test/fixtures/tags.yml @@ -0,0 +1,11 @@ +# Read about fixtures at http://api.rubyonrails.org/classes/ActiveRecord/FixtureSet.html + +one: + name: MyString + description: MyString + public: + +two: + name: MyString + description: MyString + public: diff --git a/test/models/problem_tag_test.rb b/test/models/problem_tag_test.rb new file mode 100644 --- /dev/null +++ b/test/models/problem_tag_test.rb @@ -0,0 +1,7 @@ +require 'test_helper' + +class ProblemTagTest < ActiveSupport::TestCase + # test "the truth" do + # assert true + # end +end diff --git a/test/models/tag_test.rb b/test/models/tag_test.rb new file mode 100644 --- /dev/null +++ b/test/models/tag_test.rb @@ -0,0 +1,7 @@ +require 'test_helper' + +class TagTest < ActiveSupport::TestCase + # test "the truth" do + # assert true + # end +end