From 297f717a4f7921b2a41f4ad5c6c721dfd47fc0cb Mon Sep 17 00:00:00 2001 From: Joachim Filip Ignacy Bartosik Date: Fri, 13 Aug 2010 12:18:21 +0200 Subject: Document models Documented models: Answer Comment EmailAnswer Guest MultipleChoiceAnswer Option Question QuestionCategory QuestionContentEmail QuestionContentMultipleChoice QuestionContentText QuestionGroup User UserCategory UserQuestionGroup --- app/models/answer.rb | 14 ++++++++++++++ app/models/comment.rb | 2 ++ app/models/email_answer.rb | 2 ++ app/models/guest.rb | 2 ++ app/models/multiple_choice_answer.rb | 3 +++ app/models/option.rb | 2 ++ app/models/question.rb | 16 ++++++++++++++++ app/models/question_category.rb | 4 ++++ app/models/question_content_email.rb | 5 +++++ app/models/question_content_multiple_choice.rb | 2 ++ app/models/question_content_text.rb | 1 + app/models/question_group.rb | 4 ++++ app/models/user.rb | 12 ++++++++++++ app/models/user_category.rb | 6 ++++++ app/models/user_question_group.rb | 4 ++++ 15 files changed, 79 insertions(+) diff --git a/app/models/answer.rb b/app/models/answer.rb index 1d15b50..c086bf4 100644 --- a/app/models/answer.rb +++ b/app/models/answer.rb @@ -1,5 +1,14 @@ require 'permissions/owned_model.rb' require 'permissions/set.rb' +# Model storing answers for questions with text content. +# Hooks: +# * After creation notification is sent to mentor of owner of the answer +# * After update notification is sent to mentor of owner of the answer +# * If content of answer was changed it becomes un-approved +# +# Validations: +# * There can be only one reference answer for each question +# * User can give only one non-reference answer for each question class Answer < ActiveRecord::Base hobo_model # Don't put anything above this @@ -79,6 +88,7 @@ class Answer < ActiveRecord::Base owner._?.mentor_is?(acting_user) end + # Returns hash containing updated answer attributes. def self.update_from(params) ans = Answer.find(params['id']) result = ans.attributes @@ -88,6 +98,7 @@ class Answer < ActiveRecord::Base result end + # Returns new answer deducing type and attributes from params def self.new_from(params) for klass in [Answer, MultipleChoiceAnswer] name = klass.to_s.underscore @@ -95,6 +106,7 @@ class Answer < ActiveRecord::Base end end + # Returns wrong answers of given user def self.wrong_answers_of(uid) MultipleChoiceAnswer.find_by_sql ["SELECT ans.* FROM answers ans, answers ref WHERE ref.reference = ? AND ans.question_id = ref.question_id AND @@ -102,10 +114,12 @@ class Answer < ActiveRecord::Base end protected + # Sends email notification about new answer to mentor of owner def notify_new_answer UserMailer.deliver_new_answer(owner.mentor, self) unless owner._?.mentor.nil? end + # Sends email notification about changed answer to mentor of owner def notify_changed_answer UserMailer.deliver_changed_answer(owner.mentor, self) unless owner._?.mentor.nil? end diff --git a/app/models/comment.rb b/app/models/comment.rb index a67e7dc..2fcc5f0 100644 --- a/app/models/comment.rb +++ b/app/models/comment.rb @@ -1,3 +1,4 @@ +# Model storing comments mentors made for answers. class Comment < ActiveRecord::Base hobo_model # Don't put anything above this @@ -30,6 +31,7 @@ class Comment < ActiveRecord::Base end protected + # Sends notification about new comment to owner of mentor def notify_new_comment UserMailer.deliver_new_comment(answer.owner, self) end diff --git a/app/models/email_answer.rb b/app/models/email_answer.rb index db2af75..16c7b9c 100644 --- a/app/models/email_answer.rb +++ b/app/models/email_answer.rb @@ -1,3 +1,5 @@ +# Model storing answers for questions with email content. +# No user is allowed to do anything except viewing. class EmailAnswer < Answer fields do correct :boolean diff --git a/app/models/guest.rb b/app/models/guest.rb index c94891f..4348c85 100644 --- a/app/models/guest.rb +++ b/app/models/guest.rb @@ -1,3 +1,5 @@ +# Model representing guest users. +# It has methods that allow us to treat Guests as regular users. class Guest < Hobo::Guest def administrator?; false; end def answered_questions; []; end diff --git a/app/models/multiple_choice_answer.rb b/app/models/multiple_choice_answer.rb index 95e7186..6433f6d 100644 --- a/app/models/multiple_choice_answer.rb +++ b/app/models/multiple_choice_answer.rb @@ -1,4 +1,6 @@ +# Model storing answers for questions with multiple choice content. class MultipleChoiceAnswer < Answer + # Returns RichTypes::CheckList describing given answer def options if @options.nil? @options = RichTypes::CheckList.new(question.content.options) @@ -7,6 +9,7 @@ class MultipleChoiceAnswer < Answer @options end + # Sets new answer def options=(what) self.options @options.options = what diff --git a/app/models/option.rb b/app/models/option.rb index 63a1ac8..6a9801d 100644 --- a/app/models/option.rb +++ b/app/models/option.rb @@ -1,3 +1,5 @@ +# Hobo model storing options for multiple choice questions. +# Inherits permissions from option_owner. class Option < ActiveRecord::Base hobo_model # Don't put anything above this diff --git a/app/models/question.rb b/app/models/question.rb index 1122dd1..f1d380f 100644 --- a/app/models/question.rb +++ b/app/models/question.rb @@ -1,3 +1,12 @@ +# TODO: probably broken scope unanswered(user) +# Model storing answers for questions with text content. +# Hooks: +# * New question is approved if and only if user (relation) is nil or +# administrator +# * When new approved question is created all recruits that should answer it +# are notified +# * When question is marked as approved all recruits that should answer it +# are notified class Question < ActiveRecord::Base hobo_model # Don't put anything above this @@ -114,14 +123,19 @@ class Question < ActiveRecord::Base named_scope :multiple_choice, :joins => :question_content_multiple_choice + # Returns true if user gave a non-reference answer for the question, + # otherwise returns false or nil. def answered?(user) answers.owner_is(user).not_reference.count > 0 if user.signed_up? end + # If user is signed up and answered question returns (a non-reference answer) + # returns the answer. Returns nil otherwise. def answer_of(user) answers.owner_is(user).not_reference.first if user.signed_up? end + # Returns content of question if there is one or nil if there isn't. def content question_content_text || question_content_multiple_choice || @@ -137,6 +151,7 @@ class Question < ActiveRecord::Base after_update :notify_approved_question protected + # Sends notification about new question (TODO: check for group). def notify_new_question # If question category isn't assigned don't try to access it if question_category && approved @@ -146,6 +161,7 @@ class Question < ActiveRecord::Base end end + # Sends notification about new question (TODO: check for group). def notify_approved_question if question_category && !approved_was && approved notify_new_question diff --git a/app/models/question_category.rb b/app/models/question_category.rb index bcf2db7..7c4b78f 100644 --- a/app/models/question_category.rb +++ b/app/models/question_category.rb @@ -1,3 +1,5 @@ +# Questions are arranged in categories. Recruit should answer question in some +# categories. class QuestionCategory < ActiveRecord::Base hobo_model # Don't put anything above this @@ -15,6 +17,8 @@ class QuestionCategory < ActiveRecord::Base include Permissions::AnyoneCanViewAdminCanChange + # Array of arrays [Category name, Category id], includes also + # ['All Categories', nil] array. def self.as_select_opts [['All Categories', nil]] + QuestionCategory.all(:select => 'name, id').collect{ |q| [q.name, q.id]} end diff --git a/app/models/question_content_email.rb b/app/models/question_content_email.rb index 6e70388..f10fcc1 100644 --- a/app/models/question_content_email.rb +++ b/app/models/question_content_email.rb @@ -1,4 +1,9 @@ require 'permissions/inherit.rb' +# TODO: all QuestionContents in one table(?) +# TODO: use standard serialization, not custom one (?) +# To answer question with QuestionContentEmail user should send to application +# email meeting specified requirements (recruits can't see requirements), they +# should learn them from question description and documentation. class QuestionContentEmail < ActiveRecord::Base hobo_model # Don't put anything above this diff --git a/app/models/question_content_multiple_choice.rb b/app/models/question_content_multiple_choice.rb index f721d2f..cd1d277 100644 --- a/app/models/question_content_multiple_choice.rb +++ b/app/models/question_content_multiple_choice.rb @@ -1,4 +1,5 @@ require 'permissions/inherit.rb' +# Multiple choice content for question. class QuestionContentMultipleChoice < ActiveRecord::Base hobo_model # Don't put anything above this @@ -15,6 +16,7 @@ class QuestionContentMultipleChoice < ActiveRecord::Base inherit_permissions(:question) + # Returns new answer (of proper class) of user for question (relation). def new_answer_of(user) MultipleChoiceAnswer.new :question_id => question_id, :owner => user end diff --git a/app/models/question_content_text.rb b/app/models/question_content_text.rb index 988f890..37540e2 100644 --- a/app/models/question_content_text.rb +++ b/app/models/question_content_text.rb @@ -15,6 +15,7 @@ class QuestionContentText < ActiveRecord::Base inherit_permissions(:question) + # Returns new answer (of proper class) of user for question (relation). def new_answer_of(user) Answer.new :question_id => question_id, :owner => user end diff --git a/app/models/question_group.rb b/app/models/question_group.rb index 897c621..5c2ed3b 100644 --- a/app/models/question_group.rb +++ b/app/models/question_group.rb @@ -1,3 +1,7 @@ +# Users should answer only one question from each group. The question recruit +# should answer is randomly chosen from group by application. Unless user is +# recruit [s]he can't view grouped questions [s]he is not supposed to answer. +# Recruits can prepare to answer grouped questions by reading group description. class QuestionGroup < ActiveRecord::Base hobo_model # Don't put anything above this diff --git a/app/models/user.rb b/app/models/user.rb index 4982a13..078c37c 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -1,3 +1,9 @@ +#TODO: merge before_creation hooks +# Model representing signed up users. +# Hooks: +# * before creation application gives user token +# * before creation application gives user mentor role and Gentoo nick if user +# used https://dev.gentoo.org/~nick openid class User < ActiveRecord::Base hobo_user_model # Don't put anything above this @@ -120,10 +126,13 @@ class User < ActiveRecord::Base true end + # Returns all questions user should answer + # TODO: rewrite as SQL (?) def all_questions Question.ungrouped_questions_of_user(id) + Question.grouped_questions_of_user(id) end + # Returns questions user should answer but didn't answer yet. def unanswered_questions Question.unanswered_grouped(id) + Question.unanswered_ungrouped(id) end @@ -132,6 +141,7 @@ class User < ActiveRecord::Base Question.unanswered_grouped(id).count.zero? && Question.unanswered_ungrouped(id).count.zero? end + # Returns true if there is at least one unapproved project acceptance for this user def any_pending_project_acceptances? (ProjectAcceptance.count :conditions => { :accepting_nick => nick, :accepted => false}) > 0 end @@ -163,6 +173,8 @@ class User < ActiveRecord::Base self.required_questions_count - self.required_unanswered_count end + # Returns string describing recruit progress. Includes information only about + # question recruit is required to answer. def progress "Answered #{self.required_answered_count} of #{self.required_questions_count} questions." end diff --git a/app/models/user_category.rb b/app/models/user_category.rb index 968b996..d641268 100644 --- a/app/models/user_category.rb +++ b/app/models/user_category.rb @@ -1,4 +1,10 @@ require 'permissions/set.rb' +# Associates users with question categories +# Hooks: +# * Before creation looks through groups in category and associates user with +# one randomly chosen question from each group (unless user is already +# associated with some question from the group) +# TODO: wrap the whole thing in transaction (?) class UserCategory < ActiveRecord::Base hobo_model # Don't put anything above this diff --git a/app/models/user_question_group.rb b/app/models/user_question_group.rb index 5319984..5c5f537 100644 --- a/app/models/user_question_group.rb +++ b/app/models/user_question_group.rb @@ -1,3 +1,5 @@ +# Associates user with grouped question. No user can do anything to it - +# application manages those internally. class UserQuestionGroup < ActiveRecord::Base hobo_model # Don't put anything above this @@ -27,10 +29,12 @@ class UserQuestionGroup < ActiveRecord::Base protected # as users can never edit questions on their own if one of those isn't met # it'll be because of some problem in application + # TODO: change name def question_has_category errors.add(:question, 'must be grouped!') if question._?.question_group.nil? end + # TODO: change name def user_does_not_have_other_question_from_the_same_category # if there are Questions from the same group associated with the same user # through user_question_groups report an error -- cgit v1.2.3-65-gdbad