Skip to content

Instantly share code, notes, and snippets.

@paulchubatyy
Created June 2, 2010 09:55
Show Gist options
  • Save paulchubatyy/422162 to your computer and use it in GitHub Desktop.
Save paulchubatyy/422162 to your computer and use it in GitHub Desktop.
<?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();
}
}
<?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;
}
}
}
<?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;
}
}
<?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