Created
June 2, 2010 09:55
-
-
Save paulchubatyy/422162 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
/** | |
* Answer model is the class that represents single answer to the | |
* question. It handles all the operations with answer | |
* | |
* @package cevapbankasi | |
*/ | |
class Model_Answer extends Model_Abstract { | |
public static function initialize(Jelly_Meta $meta) | |
{ | |
$meta->table('answers') | |
->name_key('title') | |
->sorting(array('created_at' => 'asc')) | |
->fields(array( | |
'id' => new Field_Primary, | |
'author' => new Field_BelongsTo(array( | |
'foreign' => 'user', | |
'column' => 'user_id', | |
)), | |
'voters' => new Field_ManyToMany(array( | |
'foreign' => 'user', | |
'through' => array( | |
'model' => 'votes', | |
'columns' => array('answer_id', 'user_id'), | |
), | |
)), | |
'question' => new Field_BelongsTo(array( | |
'foreign' => 'question', | |
'column' => 'question_id' | |
)), | |
'content' => new Field_Text(array( | |
'rules' => array( | |
'not_empty' => array(TRUE), | |
), | |
'filters' => array( | |
'text::auto_p' => array(TRUE), | |
), | |
)), | |
'source' => new Field_Text(array( | |
'filters' => array( | |
'security::xss_clean' => array(TRUE), | |
'security::encode_php_tags' => array(TRUE), | |
'text::auto_p' => array(TRUE), | |
), | |
)), | |
'status' => new Field_Enum(array( | |
'choices' => array('visible', 'hidden'), | |
'default' => 'visible', | |
)), | |
'is_best' => new Field_Boolean(array( | |
'default' => FALSE, | |
)), | |
'points' => new Field_Integer(array( | |
'default' => 0, | |
)), | |
'created_at' => new Field_Timestamp(array( | |
'auto_now_create' => TRUE, | |
'format' => 'Y-m-d H:i:s', | |
)), | |
'updated_at' => new Field_Timestamp(array( | |
'auto_now_update' => TRUE, | |
'format' => 'Y-m-d H:i:s', | |
)), | |
)); | |
} | |
/** | |
* Creates the answer | |
* | |
* @param array $input | |
* @param object $author | |
* @param object $rule | |
* @return object $this | |
*/ | |
public function create(array $input, Model_User $author, Model_Rule $rule) | |
{ | |
// supercombo with grabbing init data, setting author and saving! | |
$this->set(arr::extract($input, array('question', 'content', 'source'))) | |
->set('author', $author) | |
->save(); | |
// updating related question | |
$this->question->set(array( | |
'answer_count' => $this->question->answer_count+1, | |
'last_answered_at' => time() | |
))->save(); | |
// updating user points | |
$author->update_points($rule); | |
// notifications here | |
$message = View::factory('emails/answer/new') | |
->set('answer', $this); | |
email::batch_send( | |
$this->question->watchlist(), | |
Conf::get('email.answer.new', 'New answer posted to the question you watch'), | |
$message | |
); | |
return $this; | |
} | |
/** | |
* Mark answer as best | |
* | |
* @return object answer instance | |
*/ | |
public function mark_best() | |
{ | |
// update-save combo! | |
$this->set('is_best', TRUE)->save(); | |
// if user wants to get notifications | |
if ($this->author->email_notifications) { | |
//creating the mesage | |
$message = View::factory('emails/answer/best') | |
->set('answer', $this); | |
// sending the email | |
email::send( | |
array($this->author->email, $this->author->username), | |
Conf::get('email.answer.best', 'Your answer is best'), | |
$message | |
); | |
} | |
return $this; | |
} | |
/** | |
* Adds the vote for the question | |
* | |
* @param Model_User object | |
* @param string | |
* @param object Rule that is applied | |
* @return object | |
*/ | |
public function vote(Model_User $user, $direction, Model_Rule $rule) | |
{ | |
if ($this->voted($user)) { | |
return $this; | |
} | |
$point = ($direction == 'up') ? 1 : -1; | |
$this->points += $point; | |
$this->add('voters', $user); | |
$this->save(); | |
$user->update_points($rule); | |
return $this; | |
} | |
/** | |
* Checks if the user has already voted for the question | |
* | |
* @param Model_User object | |
* @return bool | |
*/ | |
protected function voted(Model_User $user) | |
{ | |
foreach ($this->voters as $voter) { | |
if ($voter->id == $user->id) { | |
return TRUE; | |
} | |
} | |
return FALSE; | |
} | |
/** | |
* Answer delete procedure | |
* | |
* @param Model_User object | |
* @param Model_Rule object | |
* @return bool | |
*/ | |
public function truncate(Model_User $user, Model_Rule $rule) | |
{ | |
$user->update_points($rule); | |
return $this->delete(); | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
class Registry { | |
protected static $data = array(); | |
// this is a static class | |
final private function __construct() | |
{ | |
} | |
public static function set($key, $value) | |
{ | |
self::$data[$key] = $value; | |
} | |
public static function get($key, $default = NULL) | |
{ | |
if (isset(self::$data[$key])) { | |
return self::$data[$key]; | |
} else { | |
return $default; | |
} | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
/** | |
* Message model is used for internal messaging in the system. | |
* | |
* @package citylance | |
*/ | |
class Model_Message extends Model_Abstract { | |
public static function initialize(Jelly_Meta $meta) | |
{ | |
$meta->sorting(array('received_at' => 'DESC')) | |
->fields(array( | |
'id' => new Field_Primary, | |
'subject' => new Field_String(array( | |
'rules' => array( | |
'not_empty' => array(TRUE), | |
), | |
)), | |
'content' => new Field_Text(array( | |
'rules' => array( | |
'not_empty' => array(TRUE), | |
), | |
'filters' => array( | |
'text::auto_p' => array(TRUE), | |
), | |
)), | |
'sender' => new Field_BelongsTo(array( | |
'foreign' => 'user', | |
'column' => 'sender_id', | |
)), | |
'recipient' => new Field_BelongsTo(array( | |
'foreign' => 'user', | |
'column' => 'recipient_id', | |
'rules' => array( | |
'not_empty' => array(TRUE), | |
), | |
'callbacks' => array( | |
'contacts' => array('Model_User', '_check_contact') | |
), | |
)), | |
'unread' => new Field_Boolean(array( | |
'default' => TRUE, | |
)), | |
'inbox' => new Field_Boolean(array( | |
'default' => TRUE, | |
)), | |
'outbox' => new Field_Boolean(array( | |
'default' => TRUE, | |
)), | |
'draft' => new Field_Boolean(array( | |
'default' => TRUE, | |
)), | |
'created_at' => new Field_Timestamp(array( | |
'auto_now_create' => TRUE, | |
'format' => 'Y-m-d H:i:s', | |
)), | |
'updated_at' => new Field_Timestamp(array( | |
'auto_now_update' => TRUE, | |
'format' => 'Y-m-d H:i:s', | |
)), | |
'received_at' => new Field_Timestamp(array( | |
'format' => 'Y-m-d H:i:s', | |
)), | |
)); | |
} | |
/** | |
* Creates the message based on input array and the author | |
* | |
* @param array $input | |
* @param object $author | |
* @return object $this | |
*/ | |
public function create(array $input, Model_User $author) | |
{ | |
$this->set(arr::extract($input, array('subject', 'content', 'recipient'))) | |
->set(array( | |
'sender' => $author, | |
'inbox' => FALSE, | |
'outbox' => FALSE, | |
'draft' => TRUE, | |
)) | |
->save(); | |
return $this; | |
} | |
/** | |
* Truncates the message for the user | |
* | |
* @param object $user | |
* @return object $this | |
*/ | |
public function truncate(Model_User $user) | |
{ | |
$status = array('draft' => FALSE); | |
if ($user->id == $this->recipient->id) { | |
$status['inbox'] = FALSE; | |
} | |
if ($user->id == $this->sender->id) { | |
$status['outbox'] = FALSE; | |
} | |
$this->set($status)->save(); | |
} | |
/** | |
* Marks message as sent and places it to inbox and outbox | |
* | |
* @throws Kohana_Exception | |
*/ | |
public function send() | |
{ | |
$status = array( | |
'unread' => TRUE, | |
'inbox' => TRUE, | |
'outbox' => TRUE, | |
'draft' => FALSE, | |
); | |
if ($this->recipient->has('blacklist', $this->sender)) { | |
$status['inbox'] = FALSE; | |
} | |
$this->set($status)->save(); | |
} | |
/** | |
* Marks message as read | |
* | |
* @return object $this | |
*/ | |
public function mark_read() | |
{ | |
$this->set('unread', FALSE)->save(); | |
return $this; | |
} | |
/** | |
* Checks if user can view the message | |
* | |
* @param object $user | |
* @return boolean | |
*/ | |
public function can_view(Model_User $user) | |
{ | |
if ( | |
($this->recipient->id == $user->id AND $this->inbox) | |
OR ($this->sender->id == $user->id | |
AND ($this->outbox OR $this->draft)) | |
) { | |
return TRUE; | |
} | |
return FALSE; | |
} | |
/** | |
* Checks if the message can be edited by the user. | |
* | |
* @param object $user | |
* @return boolean | |
*/ | |
public function cat_edit(Model_User $user) | |
{ | |
if ($this->sender->id == $user->id AND $this->draft) { | |
return TRUE; | |
} | |
return FALSE; | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
class Controller_Question extends Controller_Website { | |
protected $types = array( | |
'Recent Questions' => 'recent', | |
'Recent Answers' => 'answered', | |
'Recent Resolved' => 'resolved', | |
'Popular Questions' => 'popular', | |
'In Voting' => 'opened', | |
); | |
protected $current_type; | |
protected $pagination = NULL; | |
protected $protected_methods = array('save', 'ask', 'subscribe', 'star', 'abuse'); | |
public function before() | |
{ | |
parent::before(); | |
// user must be authenticated to get access to protected methods | |
if (in_array($this->request->action, $this->protected_methods) | |
AND !$this->auth->logged_in()) | |
{ | |
$this->request->redirect(url::site(Route::get('forbidden')->uri())); | |
} | |
$this->resources[] = 'assets/js/star.js'; | |
} | |
/* | |
* Shows the list of the questions category-agnostic | |
* | |
* @param string filter by type @see $this->types; | |
* @param int page number | |
**/ | |
public function action_index($type, $page) | |
{ | |
$this->resources[] = 'assets/js/question.js'; | |
$this->content->bind('questions', $questions) | |
->set('types', $this->types); | |
$this->current_type = $type; | |
$method = 'get_'.$type; | |
$pager = Pagination::factory(array( | |
'total_items' => Jelly::select('question')->$method() | |
->count(), | |
)); | |
$questions = Jelly::select('question')->$method() | |
->paginate($pager->items_per_page, $pager->offset) | |
->execute(); | |
if (Request::$is_ajax) { | |
$this->message(array( | |
'questions' => $this->content->render(), | |
'pagination' => $pager->render(), | |
)); | |
} else { | |
$this->pagination = $pager; | |
} | |
} | |
/** | |
* Shows the list of questions in the category | |
* | |
* @param int category id | |
* @param string filter by type @see $this->types | |
* @param int page number | |
*/ | |
public function action_category($category, $type, $page) | |
{ | |
$this->resources[] = 'assets/js/question.js'; | |
$this->content = View::factory('question/index') | |
->bind('questions', $questions) | |
->set('types', $this->types); | |
$this->current_type = $type; | |
$this->category = $category; | |
$category = Jelly::select('category', $category); | |
$method = 'get_'.$type; | |
Registry::set('current_category', $category); | |
$pager = Pagination::factory(array( | |
'total_items' => Jelly::select('question')->category($category) | |
->$method() | |
->count(), | |
)); | |
$questions = Jelly::select('question')->category($category) | |
->$method() | |
->paginate($pager->items_per_page, $pager->offset) | |
->execute(); | |
if (Request::$is_ajax) { | |
$this->message(array( | |
'questions' => $this->content->render(), | |
'pagination' => $pager->render(), | |
)); | |
} else { | |
$this->pagination = $pager; | |
} | |
} | |
/** | |
* Show signle question with the answers | |
* | |
* @param int Question id | |
*/ | |
public function action_view($question_id) | |
{ | |
// adding page specific javascripts | |
$this->resources[] = 'assets/js/answer.js'; | |
// binding the variables that will be used in the template | |
$this->content->bind('question', $question) | |
->bind('answers', $answers) | |
->bind('categories', $categories) | |
->bind('similar', $similar) | |
->bind('substatus', $substatus) | |
->bind('author_view', $author_view); | |
// fetching the question from the database | |
$question = Jelly::select('question')->load($question_id); | |
// check if the questions to get the auto best answer | |
if ($question->must_be_resolved()) { | |
// resolving the question | |
$question->resolve(); | |
} | |
// creating the category path to the question | |
$categories = $question->category->get_path(); | |
// creating pagination | |
$pagination = Pagination::factory(array( | |
'total_items' => Jelly::select('answer') | |
->view_with_question($question->id) | |
->count(), | |
)); | |
// selecting the answers of the question | |
$answers = Jelly::select('answer')->view_with_question($question_id) | |
->paginate($pagination->items_per_page, $pagination->offset) | |
->execute(); | |
// getting similar questions | |
$similar = Jelly::select('question')->similar($question)->limit(5) | |
->execute(); | |
// assuming the user is not authorized yet | |
$substatus = 'not_authorized'; | |
// .. and he is not the author of the question | |
$author_view = FALSE; | |
// he is authorized, isn't he? | |
if ($this->auth->logged_in()) { | |
// damn yeah. Let's see if he has subscribed to get updated | |
$substatus = !$question->subscribed($this->auth->get_user()); | |
// and he may post answers! | |
$this->content->set('answer_form', View::factory('answer/form') | |
->bind('question', $question) | |
->set('answer', Jelly::factory('answer'))); | |
if ($this->auth->get_user()->id == $question->author->id) { | |
// fuck! we have the question author here! | |
$author_view = TRUE; | |
} | |
} | |
// adding the pagination, we will use it later in render method | |
$this->pagination = $pagination; | |
} | |
/* | |
* Save the question to the database | |
* | |
* @auth required | |
*/ | |
public function action_save() | |
{ | |
// fetching the event that is going to happen | |
$event = Jelly::select('rule')->event('question.create')->load(); | |
// check if we have enough points to create question | |
// | |
if ($this->auth->get_user()->is_allowed($event) == FALSE) { | |
// oh no, we need to earn more points! | |
return $this->message(url::site( | |
Route::get('forbidden')->uri(array( | |
'action' => 'points'))), | |
'redirect'); | |
} | |
$question = Jelly::factory('question'); | |
try { | |
// creating | |
$question->create($_POST, $this->auth->get_user(), $event); | |
// success!!!!1111 | |
$this->message(url::site(Route::get('question')->uri(array( | |
'id' => $question->id, | |
))), 'redirect'); | |
} catch (Validate_Exception $e) { | |
// stupid input errors, lets report them | |
$this->message($e->array->errors('question/errors'), 'error'); | |
} catch (Permission_Exception $e) { | |
$this->message($e->text(), 'error'); | |
} | |
} | |
/* | |
* Ask question form | |
* | |
* @auth required | |
* @param int category id of the question to create | |
*/ | |
public function action_ask() | |
{ | |
// adding page specific js | |
$this->resources[] = 'assets/js/ask.js'; | |
// binding | |
$this->content->set('question', Jelly::factory('question')) | |
->bind('points', $points) | |
->bind('questions_left', $ql); | |
// fetching event points | |
$points = abs(Jelly::select('rule')->event('question.create')->load()->points); | |
// fetching questions left for today | |
$ql = $this->auth->get_user()->get_level()->question_limit - $this->auth->get_user()->today_question; | |
} | |
/* | |
* Subscribe to get the question updated to the email | |
* | |
* @auth required | |
* @param int Question id | |
*/ | |
public function action_subscribe($question_id) | |
{ | |
$this->content->bind('subscribtion_status', $status); | |
$status = Jelly::select('question')->load($question_id) | |
->subscribe($this->auth->get_user())->subscribed($this->auth->get_user()); | |
$this->message($this->content->render()); | |
} | |
public function action_star($question_id) | |
{ | |
$event = Jelly::select('rule')->event('question.star')->load(); | |
if ($this->auth->get_user()->is_allowed($event) == FALSE) { | |
// oh no, we need to earn more points! | |
return $this->message(url::site( | |
__('You cannot star this question any more')), | |
'error'); | |
} | |
$this->auth->get_user()->star(Jelly::select('question')->load($question_id), $event); | |
$this->message($this->content->render()); | |
} | |
public function action_random($question_id) | |
{ | |
$question = Jelly::select('question')->load($question_id); | |
$this->request->redirect(Route::get('question')->uri(array( | |
'id' => $this->another($question)->id | |
))); | |
} | |
protected function another($question, $category = NULL) | |
{ | |
if (!$category) { | |
$category = $question->category; | |
} | |
$questions = Jelly::select('question')->category($category)->execute(); | |
$q = $questions->count(); | |
if ($q == 1) { | |
return $this->another($question, $category->parent); | |
} else { | |
$i = mt_rand(0, $q-1); | |
if ($questions[$i]->id == $question->id) { | |
return $this->another($question, $category); | |
} else { | |
return $questions[$i]; | |
} | |
} | |
} | |
public function action_abuse($question_id) | |
{ | |
$question = Jelly::select('question')->load($question_id); | |
$question->abuse(); | |
$this->message(__('Question has been reported')); | |
} | |
public function action_categorylist($category_id = NULL) | |
{ | |
if (empty($category_id)) { | |
$category_id = 0; | |
} | |
$block = View::factory('question/left') | |
->bind('categories', $categories) | |
->bind('current_category', $current); | |
$current = Jelly::select('category')->load($category_id); | |
$categories = Jelly::select('category')->children($category_id)->execute(); | |
if (Request::$is_ajax) { | |
$this->content = $block; | |
} else { | |
return $block; | |
} | |
} | |
protected function get_left() | |
{ | |
return $this->action_categorylist(); | |
} | |
protected function get_top() | |
{ | |
$list_actions = array('index', 'category'); | |
if (in_array($this->request->action, $list_actions)) { | |
if ($this->request->action == 'index') { | |
$route = 'questions'; | |
} else { | |
$route = 'category'; | |
} | |
return $this->top = View::factory('question/top') | |
->set('types', $this->types) | |
->set('current', $this->current_type) | |
->set('route', $route) | |
->set('category', (isset($this->category)) ? $this->category : NULL); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment