Description:
[web] added announcement git-svn-id: http://theory.cpe.ku.ac.th/grader/web/trunk@185 6386c4cd-e34a-4fa8-8920-d93eb39b512e
Commit status:
[Not Reviewed]
References:
Comments:
0 Commit comments 0 Inline Comments
Unresolved TODOs:
There are no unresolved TODOs
Add another comment

r97:bd747ee8a498 - - 18 files changed: 336 inserted, 1 deleted

@@ -0,0 +1,91
1 + class AnnouncementsController < ApplicationController
2 +
3 + before_filter :authenticate
4 + before_filter { |controller| controller.authorization_by_roles(['admin'])}
5 +
6 + in_place_edit_for :announcement, :published
7 +
8 + # GET /announcements
9 + # GET /announcements.xml
10 + def index
11 + @announcements = Announcement.find(:all)
12 +
13 + respond_to do |format|
14 + format.html # index.html.erb
15 + format.xml { render :xml => @announcements }
16 + end
17 + end
18 +
19 + # GET /announcements/1
20 + # GET /announcements/1.xml
21 + def show
22 + @announcement = Announcement.find(params[:id])
23 +
24 + respond_to do |format|
25 + format.html # show.html.erb
26 + format.xml { render :xml => @announcement }
27 + end
28 + end
29 +
30 + # GET /announcements/new
31 + # GET /announcements/new.xml
32 + def new
33 + @announcement = Announcement.new
34 +
35 + respond_to do |format|
36 + format.html # new.html.erb
37 + format.xml { render :xml => @announcement }
38 + end
39 + end
40 +
41 + # GET /announcements/1/edit
42 + def edit
43 + @announcement = Announcement.find(params[:id])
44 + end
45 +
46 + # POST /announcements
47 + # POST /announcements.xml
48 + def create
49 + @announcement = Announcement.new(params[:announcement])
50 +
51 + respond_to do |format|
52 + if @announcement.save
53 + flash[:notice] = 'Announcement was successfully created.'
54 + format.html { redirect_to(@announcement) }
55 + format.xml { render :xml => @announcement, :status => :created, :location => @announcement }
56 + else
57 + format.html { render :action => "new" }
58 + format.xml { render :xml => @announcement.errors, :status => :unprocessable_entity }
59 + end
60 + end
61 + end
62 +
63 + # PUT /announcements/1
64 + # PUT /announcements/1.xml
65 + def update
66 + @announcement = Announcement.find(params[:id])
67 +
68 + respond_to do |format|
69 + if @announcement.update_attributes(params[:announcement])
70 + flash[:notice] = 'Announcement was successfully updated.'
71 + format.html { redirect_to(@announcement) }
72 + format.xml { head :ok }
73 + else
74 + format.html { render :action => "edit" }
75 + format.xml { render :xml => @announcement.errors, :status => :unprocessable_entity }
76 + end
77 + end
78 + end
79 +
80 + # DELETE /announcements/1
81 + # DELETE /announcements/1.xml
82 + def destroy
83 + @announcement = Announcement.find(params[:id])
84 + @announcement.destroy
85 +
86 + respond_to do |format|
87 + format.html { redirect_to(announcements_url) }
88 + format.xml { head :ok }
89 + end
90 + end
91 + end
@@ -0,0 +1,2
1 + module AnnouncementsHelper
2 + end
@@ -0,0 +1,2
1 + class Announcement < ActiveRecord::Base
2 + end
@@ -0,0 +1,27
1 + <h1>Editing announcement</h1>
2 +
3 + <%= error_messages_for :announcement %>
4 +
5 + <% form_for(@announcement) do |f| %>
6 + <p>
7 + <b>Body</b><br />
8 + <%= f.text_area :body %>
9 + </p>
10 +
11 + <p>
12 + <b>Author</b><br />
13 + <%= f.text_field :author %>
14 + </p>
15 +
16 + <p>
17 + <b>Published</b><br />
18 + <%= f.check_box :published %>
19 + </p>
20 +
21 + <p>
22 + <%= f.submit "Update" %>
23 + </p>
24 + <% end %>
25 +
26 + <%= link_to 'Show', @announcement %> |
27 + <%= link_to 'Back', announcements_path %>
@@ -0,0 +1,30
1 + <% content_for :head do %>
2 + <%= stylesheet_link_tag 'scaffold' %>
3 + <%= javascript_include_tag :defaults %>
4 + <% end %>
5 +
6 + <h1>Listing announcements</h1>
7 +
8 + <table>
9 + <tr>
10 + <th>Body</th>
11 + <th>Author</th>
12 + <th>Published</th>
13 + </tr>
14 +
15 + <% for announcement in @announcements %>
16 + <tr>
17 + <% @announcement = announcement %>
18 + <td><%=h announcement.body %></td>
19 + <td><%=h announcement.author %></td>
20 + <td><%= in_place_editor_field :announcement, :published, {}, :rows => 1 %></td>
21 + <td><%= link_to 'Show', announcement %></td>
22 + <td><%= link_to 'Edit', edit_announcement_path(announcement) %></td>
23 + <td><%= link_to 'Destroy', announcement, :confirm => 'Are you sure?', :method => :delete %></td>
24 + </tr>
25 + <% end %>
26 + </table>
27 +
28 + <br />
29 +
30 + <%= link_to 'New announcement', new_announcement_path %>
@@ -0,0 +1,26
1 + <h1>New announcement</h1>
2 +
3 + <%= error_messages_for :announcement %>
4 +
5 + <% form_for(@announcement) do |f| %>
6 + <p>
7 + <b>Body</b><br />
8 + <%= f.text_area :body %>
9 + </p>
10 +
11 + <p>
12 + <b>Author</b><br />
13 + <%= f.text_field :author %>
14 + </p>
15 +
16 + <p>
17 + <b>Published</b><br />
18 + <%= f.check_box :published %>
19 + </p>
20 +
21 + <p>
22 + <%= f.submit "Create" %>
23 + </p>
24 + <% end %>
25 +
26 + <%= link_to 'Back', announcements_path %>
@@ -0,0 +1,18
1 + <p>
2 + <b>Author:</b>
3 + <%=h @announcement.author %>
4 + </p>
5 +
6 + <p>
7 + <b>Body:</b>
8 + <%=h @announcement.body %>
9 + </p>
10 +
11 + <p>
12 + <b>Published:</b>
13 + <%=h @announcement.published %>
14 + </p>
15 +
16 +
17 + <%= link_to 'Edit', edit_announcement_path(@announcement) %> |
18 + <%= link_to 'Back', announcements_path %>
@@ -0,0 +1,4
1 + .announcement
2 + = markdown(announcement.body)
3 + .pub-info
4 + %p= "#{announcement.author} #{announcement.created_at}"
@@ -0,0 +1,15
1 + class CreateAnnouncements < ActiveRecord::Migration
2 + def self.up
3 + create_table :announcements do |t|
4 + t.string :author
5 + t.text :body
6 + t.boolean :published
7 +
8 + t.timestamps
9 + end
10 + end
11 +
12 + def self.down
13 + drop_table :announcements
14 + end
15 + end
@@ -0,0 +1,11
1 + # Read about fixtures at http://ar.rubyonrails.org/classes/Fixtures.html
2 +
3 + one:
4 + author: MyString
5 + body: MyText
6 + published: false
7 +
8 + two:
9 + author: MyString
10 + body: MyText
11 + published: false
@@ -0,0 +1,45
1 + require File.dirname(__FILE__) + '/../test_helper'
2 +
3 + class AnnouncementsControllerTest < ActionController::TestCase
4 + def test_should_get_index
5 + get :index
6 + assert_response :success
7 + assert_not_nil assigns(:announcements)
8 + end
9 +
10 + def test_should_get_new
11 + get :new
12 + assert_response :success
13 + end
14 +
15 + def test_should_create_announcement
16 + assert_difference('Announcement.count') do
17 + post :create, :announcement => { }
18 + end
19 +
20 + assert_redirected_to announcement_path(assigns(:announcement))
21 + end
22 +
23 + def test_should_show_announcement
24 + get :show, :id => announcements(:one).id
25 + assert_response :success
26 + end
27 +
28 + def test_should_get_edit
29 + get :edit, :id => announcements(:one).id
30 + assert_response :success
31 + end
32 +
33 + def test_should_update_announcement
34 + put :update, :id => announcements(:one).id, :announcement => { }
35 + assert_redirected_to announcement_path(assigns(:announcement))
36 + end
37 +
38 + def test_should_destroy_announcement
39 + assert_difference('Announcement.count', -1) do
40 + delete :destroy, :id => announcements(:one).id
41 + end
42 +
43 + assert_redirected_to announcements_path
44 + end
45 + end
@@ -0,0 +1,8
1 + require File.dirname(__FILE__) + '/../test_helper'
2 +
3 + class AnnouncementTest < ActiveSupport::TestCase
4 + # Replace this with your real tests.
5 + def test_truth
6 + assert true
7 + end
8 + end
@@ -11,100 +11,104
11 11 :redirect_to => { :action => :index }
12 12
13 13
14 14 def index
15 15 redirect_to :action => 'login'
16 16 end
17 17
18 18 def login
19 19 saved_notice = flash[:notice]
20 20 reset_session
21 21 flash[:notice] = saved_notice
22 22
23 23 render :action => 'login', :layout => 'empty'
24 24 end
25 25
26 26 def list
27 27 prepare_list_information
28 28 end
29 29
30 30 def submit
31 31 user = User.find(session[:user_id])
32 32
33 33 @submission = Submission.new(params[:submission])
34 34 @submission.user = user
35 35 @submission.language_id = 0
36 36 @submission.source = params['file'].read if params['file']!=''
37 37 @submission.submitted_at = Time.new
38 38
39 39 if user.site!=nil and user.site.finished?
40 40 @submission.errors.add_to_base "The contest is over."
41 41 prepare_list_information
42 42 render :action => 'list' and return
43 43 end
44 44
45 45 if @submission.valid?
46 46 if @submission.save == false
47 47 flash[:notice] = 'Error saving your submission'
48 48 elsif Task.create(:submission_id => @submission.id,
49 49 :status => Task::STATUS_INQUEUE) == false
50 50 flash[:notice] = 'Error adding your submission to task queue'
51 51 end
52 52 else
53 53 prepare_list_information
54 54 render :action => 'list' and return
55 55 end
56 56 redirect_to :action => 'list'
57 57 end
58 58
59 59 def source
60 60 submission = Submission.find(params[:id])
61 61 if submission.user_id == session[:user_id]
62 62 fname = submission.problem.name + '.' + submission.language.ext
63 63 send_data(submission.source,
64 64 {:filename => fname,
65 65 :type => 'text/plain'})
66 66 else
67 67 flash[:notice] = 'Error viewing source'
68 68 redirect_to :action => 'list'
69 69 end
70 70 end
71 71
72 72 def compiler_msg
73 73 @submission = Submission.find(params[:id])
74 74 if @submission.user_id == session[:user_id]
75 75 render :action => 'compiler_msg', :layout => 'empty'
76 76 else
77 77 flash[:notice] = 'Error viewing source'
78 78 redirect_to :action => 'list'
79 79 end
80 80 end
81 81
82 82 def submission
83 83 @user = User.find(session[:user_id])
84 84 @problems = Problem.find_available_problems
85 85 if params[:id]==nil
86 86 @problem = nil
87 87 @submissions = nil
88 88 else
89 89 @problem = Problem.find_by_name(params[:id])
90 90 @submissions = Submission.find_all_by_user_problem(@user.id, @problem.id)
91 91 end
92 92 end
93 93
94 94 protected
95 95 def prepare_list_information
96 96 @problems = Problem.find_available_problems
97 97 @prob_submissions = Array.new
98 98 @user = User.find(session[:user_id])
99 99 @problems.each do |p|
100 100 sub = Submission.find_last_by_user_and_problem(@user.id,p.id)
101 101 if sub!=nil
102 102 @prob_submissions << { :count => sub.number, :submission => sub }
103 103 else
104 104 @prob_submissions << { :count => 0, :submission => nil }
105 105 end
106 106 end
107 +
108 + @announcements = Announcement.find(:all,
109 + :conditions => "published = 1",
110 + :order => "created_at DESC")
107 111 end
108 112
109 113 end
110 114
@@ -1,72 +1,73
1 1 # Methods added to this helper will be available to all templates in the application.
2 2 module ApplicationHelper
3 3
4 4 def user_header
5 5 menu_items = ''
6 6 user = User.find(session[:user_id])
7 7
8 8 if (user!=nil) and (user.admin?)
9 9 # admin menu
10 10 menu_items << "<b>Administrative task:</b> "
11 + append_to menu_items, '[Announcements]', 'announcements', 'index'
11 12 append_to menu_items, '[Problem admin]', 'problems', 'index'
12 13 append_to menu_items, '[User admin]', 'user_admin', 'index'
13 14 append_to menu_items, '[User stat]', 'user_admin', 'user_stat'
14 15 #append_to menu_items, '[Graders]', 'graders', 'list'
15 16 append_to menu_items, '[Site config]', 'configurations', 'index'
16 17 menu_items << "<br/>"
17 18 end
18 19
19 20 # main page
20 21 append_to menu_items, '[Main]', 'main', 'list'
21 22 append_to menu_items, '[Tasks]', 'tasks', 'list'
22 23 append_to menu_items, '[Submissions]', 'main', 'submission'
23 24 append_to menu_items, '[Test]', 'test', 'index'
24 25 append_to menu_items, '[Settings]', 'users', 'index'
25 26 append_to menu_items, '[Log out]', 'main', 'login'
26 27
27 28 menu_items
28 29 end
29 30
30 31 def append_to(option,label, controller, action)
31 32 option << ' ' if option!=''
32 33 option << link_to_unless_current(label,
33 34 :controller => controller,
34 35 :action => action)
35 36 end
36 37
37 38 def format_short_time(time)
38 39 now = Time.now
39 40 st = ''
40 41 if (time.yday != now.yday) or
41 42 (time.year != now.year)
42 43 st = time.strftime("%x ")
43 44 end
44 45 st + time.strftime("%X")
45 46 end
46 47
47 48
48 49 def user_title_bar(user)
49 50 if user.site!=nil and user.site.finished?
50 51 contest_over_string = <<CONTEST_OVER
51 52 <tr><td colspan="2" align="center">
52 53 <span class="contest-over-msg">THE CONTEST IS OVER</span>
53 54 </td></tr>
54 55 CONTEST_OVER
55 56 end
56 57 <<TITLEBAR
57 58 <div class="title">
58 59 <table>
59 60 #{contest_over_string}
60 61 <tr>
61 62 <td class="left-col">
62 63 #{user.full_name}<br/>
63 64 Current time is #{format_short_time(Time.new)}<br/>
64 65 </td>
65 66 <td class="right-col">APIO'08</td>
66 67 </tr>
67 68 </table>
68 69 </div>
69 70 TITLEBAR
70 71 end
71 72
72 73 end
@@ -1,22 +1,28
1 1 = user_title_bar(@user)
2 2
3 + - if @announcements.length!=0
4 + .announcementbox
5 + %span{:class => 'title'}
6 + Announcements
7 + = render :partial => 'announcement', :collection => @announcements
8 +
3 9 .submitbox
4 10 = error_messages_for 'submission'
5 11 = render :partial => 'submission_box'
6 12
7 13
8 14 %hr/
9 15
10 16 %table.info
11 17 %tr.info-head
12 18 %th
13 19 %th Tasks
14 20 %th # of sub(s)
15 21 %th Results
16 22 = render :partial => 'problem', :collection => @problems
17 23
18 24 %hr
19 25
20 26 .submitbox
21 27 = render :partial => 'submission_box'
22 28
@@ -1,25 +1,27
1 1 ActionController::Routing::Routes.draw do |map|
2 + map.resources :announcements
3 +
2 4 map.resources :sites
3 5
4 6 # The priority is based upon order of creation: first created -> highest priority.
5 7
6 8 # Sample of regular route:
7 9 # map.connect 'products/:id', :controller => 'catalog', :action => 'view'
8 10 # Keep in mind you can assign values other than :controller and :action
9 11
10 12 # Sample of named route:
11 13 # map.purchase 'products/:id/purchase', :controller => 'catalog', :action => 'purchase'
12 14 # This route can be invoked with purchase_url(:id => product.id)
13 15
14 16 # You can have the root of your site routed by hooking up ''
15 17 # -- just remember to delete public/index.html.
16 18 map.connect '', :controller => 'main', :action => 'login'
17 19
18 20 # Allow downloading Web Service WSDL as a file with an extension
19 21 # instead of a file named 'wsdl'
20 22 map.connect ':controller/service.wsdl', :action => 'wsdl'
21 23
22 24 # Install the default route as the lowest priority.
23 25 map.connect ':controller/:action/:id.:format'
24 26 map.connect ':controller/:action/:id'
25 27 end
@@ -1,108 +1,116
1 1 # This file is auto-generated from the current state of the database. Instead of editing this file,
2 2 # please use the migrations feature of ActiveRecord to incrementally modify your database, and
3 3 # then regenerate this schema definition.
4 4 #
5 5 # Note that this schema.rb definition is the authoritative source for your database schema. If you need
6 6 # to create the application database on another system, you should be using db:schema:load, not running
7 7 # all the migrations from scratch. The latter is a flawed and unsustainable approach (the more migrations
8 8 # you'll amass, the slower it'll run and the greater likelihood for issues).
9 9 #
10 10 # It's strongly recommended to check this file into your version control system.
11 11
12 - ActiveRecord::Schema.define(:version => 29) do
12 + ActiveRecord::Schema.define(:version => 30) do
13 +
14 + create_table "announcements", :force => true do |t|
15 + t.string "author"
16 + t.text "body"
17 + t.boolean "published"
18 + t.datetime "created_at"
19 + t.datetime "updated_at"
20 + end
13 21
14 22 create_table "configurations", :force => true do |t|
15 23 t.string "key"
16 24 t.string "value_type"
17 25 t.string "value"
18 26 t.datetime "created_at"
19 27 t.datetime "updated_at"
20 28 end
21 29
22 30 create_table "descriptions", :force => true do |t|
23 31 t.text "body"
24 32 t.boolean "markdowned"
25 33 t.datetime "created_at"
26 34 t.datetime "updated_at"
27 35 end
28 36
29 37 create_table "grader_processes", :force => true do |t|
30 38 t.string "host", :limit => 20
31 39 t.integer "pid"
32 40 t.string "mode"
33 41 t.boolean "active"
34 42 t.datetime "created_at"
35 43 t.datetime "updated_at"
36 44 t.integer "task_id"
37 45 end
38 46
39 47 add_index "grader_processes", ["host", "pid"], :name => "index_grader_processes_on_ip_and_pid"
40 48
41 49 create_table "languages", :force => true do |t|
42 50 t.string "name", :limit => 10
43 51 t.string "pretty_name"
44 52 t.string "ext", :limit => 10
45 53 end
46 54
47 55 create_table "problems", :force => true do |t|
48 56 t.string "name", :limit => 30
49 57 t.string "full_name"
50 58 t.integer "full_score"
51 59 t.date "date_added"
52 60 t.boolean "available"
53 61 t.string "url"
54 62 t.integer "description_id"
55 63 t.boolean "test_allowed"
56 64 end
57 65
58 66 create_table "rights", :force => true do |t|
59 67 t.string "name"
60 68 t.string "controller"
61 69 t.string "action"
62 70 end
63 71
64 72 create_table "rights_roles", :id => false, :force => true do |t|
65 73 t.integer "right_id"
66 74 t.integer "role_id"
67 75 end
68 76
69 77 add_index "rights_roles", ["role_id"], :name => "index_rights_roles_on_role_id"
70 78
71 79 create_table "roles", :force => true do |t|
72 80 t.string "name"
73 81 end
74 82
75 83 create_table "roles_users", :id => false, :force => true do |t|
76 84 t.integer "role_id"
77 85 t.integer "user_id"
78 86 end
79 87
80 88 add_index "roles_users", ["user_id"], :name => "index_roles_users_on_user_id"
81 89
82 90 create_table "sessions", :force => true do |t|
83 91 t.string "session_id"
84 92 t.text "data"
85 93 t.datetime "updated_at"
86 94 end
87 95
88 96 add_index "sessions", ["session_id"], :name => "index_sessions_on_session_id"
89 97 add_index "sessions", ["updated_at"], :name => "index_sessions_on_updated_at"
90 98
91 99 create_table "sites", :force => true do |t|
92 100 t.string "name"
93 101 t.boolean "started"
94 102 t.datetime "start_time"
95 103 t.datetime "created_at"
96 104 t.datetime "updated_at"
97 105 end
98 106
99 107 create_table "submissions", :force => true do |t|
100 108 t.integer "user_id"
101 109 t.integer "problem_id"
102 110 t.integer "language_id"
103 111 t.text "source"
104 112 t.binary "binary"
105 113 t.datetime "submitted_at"
106 114 t.datetime "compiled_at"
107 115 t.text "compiler_message"
108 116 t.datetime "graded_at"
@@ -63,96 +63,131
63 63 }
64 64
65 65 tr.info-odd {
66 66 background: #dddddd;
67 67 }
68 68
69 69 tr.info-even {
70 70 background: #f0f0f0;
71 71 }
72 72
73 73 /*******************************
74 74 [Main]
75 75 ********************************/
76 76 div.submitbox {
77 77 border: thin solid black;
78 78 padding: 5px;
79 79 color: white;
80 80 background-color: #777777;
81 81 font-weight: bold;
82 82 font-size: 13px;
83 83 }
84 84
85 85 /*******************************
86 86 [Settings]
87 87 ********************************/
88 88 table.uinfo {
89 89 border-collapse: collapse;
90 90 border: 1px solid black;
91 91 font-size: 13px;
92 92 }
93 93
94 94 td.uinfo {
95 95 vertical-align: top;
96 96 border: 1px solid black;
97 97 padding: 5px;
98 98 }
99 99
100 100 th.uinfo {
101 101 background: lightgreen;
102 102 vertical-align: top;
103 103 text-align: right;
104 104 border: 1px solid black;
105 105 padding: 5px;
106 106 }
107 107
108 108 /*******************************
109 109 [Submission]
110 110 ********************************/
111 111 div.compilermsgbody {
112 112 font-family: monospace;
113 113 }
114 114
115 115 div.task-menu {
116 116 text-align: center;
117 117 font-size: 13px;
118 118 font-weight: bold;
119 119 border-top: 1px solid black;
120 120 border-bottom: 1px solid black;
121 121 margin-top: 2px;
122 122 margin-bottom: 4px;
123 123 }
124 124
125 125 /*******************************
126 126 [Submission]
127 127 ********************************/
128 128 table.taskdesc {
129 129 border: 1px solid black;
130 130 border-collapse: collapse;
131 131 width: 95%;
132 132 font-size: 13px;
133 133 }
134 134
135 135 table.taskdesc p {
136 136 font-size: 13px;
137 137 }
138 138
139 139 table.taskdesc tr.name {
140 140 border: 1px solid black;
141 141 background: #aaaaaa;
142 142 color: white;
143 143 font-weight: bold;
144 144 font-size: 14px;
145 145 text-align: center;
146 146 }
147 147
148 148 table.taskdesc td.desc-odd {
149 149 padding: 5px;
150 150 padding-left: 20px;
151 151 background: #fefeee;
152 152 }
153 153
154 154 table.taskdesc td.desc-even {
155 155 padding: 5px;
156 156 padding-left: 20px;
157 157 background: #feeefe;
158 158 }
159 +
160 + /**********************
161 + [Announcement]
162 + ***********************/
163 +
164 + div.announcementbox {
165 + margin-top: 10px;
166 + margin-bottom: 10px;
167 + background: green;
168 + padding: 2px;
169 + }
170 +
171 + div.announcementbox span.title {
172 + font-weight: bold;
173 + color: white;
174 + padding-left: 10px;
175 + }
176 +
177 + div.announcement {
178 + margin: 2px;
179 + background: white;
180 + padding: 2px;
181 + padding-left: 10px;
182 + padding-right: 10px;
183 + }
184 +
185 + div.announcement p {
186 + font-size: 13px;
187 + }
188 +
189 + div.pub-info, div.pub-info p {
190 + text-align: right;
191 + font-style: italic;
192 + font-size: 10px;
193 + } No newline at end of file
You need to be logged in to leave comments. Login now