/** * Study Page Search * * Convert the search term to a framenum parameter and forward to index. * * @url /study/search/:search * */ public function executeEdit($request) { $search = trim($request->getParameter('id', '')); if (!empty($search)) { $search = CJK::normalizeFullWidthRomanCharacters($search); // update search box with cleaned up search term $request->setParameter('search', str_replace('_', '/', $search)); $framenum = KanjisPeer::getFramenumForSearch($search); } if ($request->getMethod() === coreRequest::POST) { // Handle POST request from EditStory component. $this->forward404Unless(BaseValidators::validateInteger($framenum) && intval($framenum)); // Learned kanji (doLearned.x, from input type="image") if ($request->hasParameter('doLearned_x')) { LearnedKanjiPeer::addKanji($this->getUser()->getUserId(), $framenum); // redirect to next restudy kanji $next = ReviewsPeer::getNextUnlearnedKanji($this->getUser()->getUserId()); if ($next !== false) { $this->redirect('study/edit?id=' . $next); } } } $request->setParameter('framenum', $framenum); if ($framenum) { $this->framenum = $framenum; $this->kanjiData = (object) KanjisPeer::getKanjiById($this->framenum); $this->getResponse()->setTitle('Study: ' . $this->kanjiData->kanji . ' "' . $this->kanjiData->keyword . '"'); } else { $this->framenum = false; } }
public function execute($request) { $user_id = coreContext::getInstance()->getUser()->getUserId(); $this->filter = $this->getUser()->getLocalPrefs()->get('review.graph.filter', ''); $carddata = ReviewsPeer::getLeitnerBoxCounts($this->filter); $this->restudy_cards = $carddata[0]['expired_cards']; // count untested cards and add to graph $this->untested_cards = ReviewsPeer::getCountUntested($user_id, $this->filter); $carddata[0]['fresh_cards'] = $this->untested_cards; $carddata[0]['total_cards'] += $this->untested_cards; // count totals (save a database query) //$this->total_cards = 0; $this->expired_total = 0; for ($i = 0; $i < count($carddata); $i++) { $box =& $carddata[$i]; //$this->total_cards += $box['total_cards']; // count expired cards, EXCEPT the red stack if ($i > 0) { $this->expired_total += $box['expired_cards']; } } $this->chart_data = $this->makeChartData($carddata); //DBG::printr($this->chart_data);exit; $this->me = $this; return coreView::SUCCESS; }
public function executeProgress() { // determine active lesson if the user has added cards in order, // otherwise set to FALSE $cur_frame = ReviewsPeer::getHeisigProgressCount($this->getUser()->getUserId()); $this->currentLesson = $cur_frame ? rtkBook::getLessonForFramenum($cur_frame + 1) : false; // find the success/fail flashcard count per lesson $progress = ReviewsPeer::getProgressStatus($this->getUser()->getUserId()); // rtk lesson data $rtkLessons = rtkBook::getLessons(); // how many lessons have been started $this->activeLessons = 0; $lessons = array(); for ($i = 1; $i <= 56; $i++) { $lessons[$i] = array('label' => 'Lesson ' . $i, 'passValue' => 0, 'failValue' => 0, 'testedCards' => 0, 'totalCards' => 0, 'maxValue' => $rtkLessons[$i]); } foreach ($progress as $p) { if ($p->lessonId <= 0) { throw new coreException('Bad lesson id'); } // fixme: only RtK1 for now if ($p->lessonId > 56) { break; } $lessons[$p->lessonId] = array('label' => 'Lesson ' . $p->lessonId, 'passValue' => $p->pass, 'failValue' => $p->fail, 'testedCards' => $p->pass + $p->fail, 'totalCards' => $p->total, 'maxValue' => $rtkLessons[$p->lessonId]); $this->activeLessons++; } $this->lessons = $lessons; }
/** * Return EditStory component based on GET or POST request. * * PARAMS * framenum Valid kanji id (frame number) * kanjiData Kanji data for kanji id * reviewMode True if called from the Review page * * POST requests to update the story for current user. * * character Current kanji (utf8) * chkPublic Public story * txtStory Story * * * @return * @param object $request */ public function execute($request) { if ($request->getMethod() !== coreRequest::POST) { // get user's story $story = StoriesPeer::getStory($this->getUser()->getUserId(), $this->framenum); if ($story) { $request->getParameterHolder()->add(array('txtStory' => $story->text, 'chkPublic' => $story->public)); } } else { $validator = new coreValidator($this->getActionName()); if ($validator->validate($request->getParameterHolder()->getAll())) { if ($request->hasParameter('doUpdate')) { $txtStory = trim($request->getParameter('txtStory', '')); $txtStory = strip_tags($txtStory); // delete empty story if (empty($txtStory)) { StoriesPeer::deleteStory($this->getUser()->getUserId(), $this->framenum); } else { StoriesPeer::updateStory($this->getUser()->getUserId(), $this->framenum, array('text' => $txtStory, 'public' => $request->hasParameter('chkPublic') ? 1 : 0)); } $request->setParameter('txtStory', $txtStory); } } } // set state $request->setParameter('framenum', $this->framenum); if (!$request->hasParameter('reviewMode')) { $this->isRestudyKanji = ReviewsPeer::isRestudyKanji($this->getUser()->getUserId(), $this->framenum); $this->isRelearnedKanji = LearnedKanjiPeer::hasKanji($this->getUser()->getUserId(), $this->framenum); } $this->formatted_story = StoriesPeer::getFormattedStory($request->getParameter('txtStory', ''), $this->kanjiData->keyword, true); return coreView::SUCCESS; }
/** * Delete all given flashards, returns an array of ids of flashcards * that were succesfully deleted. * * @param object $userId * @param object $selection * * @return array Array of successfully deleted flashcards (ids) or false */ public static function deleteSelection($userId, array $cardSelection) { $cards = ReviewsPeer::deleteFlashcards($userId, $cardSelection); if (is_array($cards) && count($cards)) { ActiveMembersPeer::updateFlashcardCount($userId); } return $cards; }
public function execute($request) { $queryParams = $this->getUser()->getLocalPrefs()->syncRequestParams('detailedflashcardlist', array(uiSelectPager::QUERY_ROWSPERPAGE => 20, uiSelectTable::QUERY_SORTCOLUMN => 'framenum', uiSelectTable::QUERY_SORTORDER => 0)); $this->pager = new uiSelectPager(array('select' => ReviewsPeer::getDetailedFlashcardList($this->getUser()->getUserId()), 'internal_uri' => 'review/flashcardlist', 'query_params' => $queryParams, 'max_per_page' => $queryParams[uiSelectPager::QUERY_ROWSPERPAGE], 'page' => $request->getParameter(uiSelectPager::QUERY_PAGENUM, 1))); $this->pager->init(); $this->table = new uiSelectTable(new FlashcardListBinding(), $this->pager->getSelect(), $request->getParameterHolder()); $this->table->configure(array('sortColumn' => $queryParams[uiSelectTable::QUERY_SORTCOLUMN], 'sortOrder' => $queryParams[uiSelectTable::QUERY_SORTORDER])); }
/** * Component variables: * * ts_start Timestamp from the review session start time * * @param object $request */ public function execute($request) { $queryParams = $this->getUser()->getLocalPrefs()->syncRequestParams('reviewsummary', array(uiSelectPager::QUERY_ROWSPERPAGE => 20, uiSelectTable::QUERY_SORTCOLUMN => 'framenum', uiSelectTable::QUERY_SORTORDER => 0)); // pager $this->pager = new uiSelectPager(array('select' => ReviewsPeer::getReviewSessionFlashcards($this->getUser()->getUserId(), $this->ts_start), 'internal_uri' => '@review_summary', 'query_params' => $queryParams, 'max_per_page' => $queryParams[uiSelectPager::QUERY_ROWSPERPAGE], 'page' => $request->getParameter(uiSelectPager::QUERY_PAGENUM, 1))); $this->pager->init(); // data table $this->table = new uiSelectTable(new FlashcardListBinding(), $this->pager->getSelect(), $request->getParameterHolder()); return coreView::SUCCESS; }
/** * Home page. * * @return */ public function executeIndex() { if ($this->getUser()->isAuthenticated()) { //echo $this->getUser()->sqlLocalTime(); exit; // get member stats for quick summary $this->curFrameNum = ReviewsPeer::getHeisigProgressCount($this->getUser()->getUserId()); $this->progress = rtkBook::getProgressSummary($this->curFrameNum); $this->countExpired = ReviewsPeer::getCountExpired($this->getUser()->getUserId()); $this->countFailed = ReviewsPeer::getCountFailed($this->getUser()->getUserId()); return 'Member'; } // prepare unique homepage design return 'Guest'; }
/** * Transform kanji in the input Japanese text into links to the Study area, * and add class for Javascript popup with the Heisig keywords. * * @param string $j_text Japanese text in utf-8 from validated post data. * @return string Japanese text as HTML code. */ protected function transformJapaneseText($j_text) { coreToolkit::loadHelpers('Tag'); $j_text = escape_once(trim($j_text)); // collect associative array of known kanji => kanji, framenum, keyword $kanjis = ReviewsPeer::getKnownKanji($this->getUser()->getUserId(), array('kanji', 'keyword')); $known = array(); foreach ($kanjis as $i => $kanjiData) { $known[$kanjiData['kanji']] = $kanjiData; } // wrap known kanji in text with links to Study area and hooks for javascript tooltip foreach ($known as $kanji => $info) { $url = '/study/?search=' . $info['framenum']; $rep = '<a href="' . $url . '" class="j" title="' . $info['keyword'] . '">' . $kanji . '</a>'; $j_text = str_replace($kanji, $rep, $j_text); } // assumes lines end with \r\n $j_text = preg_replace('/[\\r\\n]+/', '<br/>', $j_text); return $j_text; }
public function executeIndex($request) { $username = $request->getParameter('username'); if (!$username) { if ($this->getUser()->isAuthenticated()) { $username = $this->getUser()->getUserName(); } else { // if unauthenticated user checks his (bookmarked?) profile, go to login and back $url = $this->getController()->genUrl('profile/index', true); $this->getUser()->redirectToLogin(array('referer' => $url)); } } if ($user = UsersPeer::getUser($username)) { $this->user = $user; $this->self_account = $user['username'] == $this->getUser()->getUserName(); $this->kanji_count = ReviewsPeer::getReviewedFlashcardCount($user['userid']); $this->total_reviews = ReviewsPeer::getTotalReviews($user['userid']); $this->forum_uid = coreConfig::get('app_path_to_punbb') !== null ? PunBBUsersPeer::getInstance()->getForumUID($username) : false; return coreView::SUCCESS; } return coreView::ERROR; }
/** * Study Page Search * * Convert the search term to a framenum parameter and forward to index. * * @url /study/search/:search * */ public function executeEdit($request) { // searching or browsing (previous, next buttons) if ($request->getMethod() === coreRequest::GET) { // get search term from url $search = trim($request->getParameter('id', '')); if (!empty($search)) { $search = CJK::normalizeFullWidthRomanCharacters($search); // replace characters that caused problems (dashes) with wildcard for SQL $search = str_replace('-', '%', $search); $framenum = KanjisPeer::getFramenumForSearch($search); } } else { // POST handled by EditStoryComponent, LearnedKanji handled here $framenum = $request->getParameter('framenum', false); // Handle POST request from EditStory component. $this->forward404Unless(BaseValidators::validateInteger($framenum) && intval($framenum)); // Learned kanji (doLearned.x, from input type="image") if ($request->hasParameter('doLearned_x')) { LearnedKanjiPeer::addKanji($this->getUser()->getUserId(), $framenum); // redirect to next restudy kanji $next = ReviewsPeer::getNextUnlearnedKanji($this->getUser()->getUserId()); if ($next !== false) { $this->redirect('study/edit?id=' . $next); } } } if ($framenum) { $this->kanjiData = (object) KanjisPeer::getKanjiById($framenum); $this->getResponse()->setTitle('Study: ' . $this->kanjiData->kanji . ' "' . $this->kanjiData->keyword . '"'); // replace search term with frame number in search box $request->setParameter('search', $this->kanjiData->framenum); } else { // search gave no results $this->kanjiData = false; } }
<div class="clearboth"></div> </div> <div class="intro"> <p> This list shows all your flashcards. Click a column heading to sort the table on that column, click more than once to revert the sort order. Note that in addition to the column you selected, there is always a secondary sorting on the frame number. Click in any row to go to the study area. </p> </div> <div class="stats"> <div class="box"> <strong>Statistics</strong><br /> <?php echo ReviewsPeer::getFlashcardCount($_user->getUserId()); ?> flashcards.<br /> </div> </div> <div class="clear"></div> <?php #DBG::user() echo ui_select_table($table, $pager); ?> </div> </div> </div>
/** * Returns the number of related Reviews objects. * * @param Criteria $criteria * @param boolean $distinct * @param PropelPDO $con * @return int Count of related Reviews objects. * @throws PropelException */ public function countReviewss(Criteria $criteria = null, $distinct = false, PropelPDO $con = null) { if ($criteria === null) { $criteria = new Criteria(ImagesPeer::DATABASE_NAME); } else { $criteria = clone $criteria; } if ($distinct) { $criteria->setDistinct(); } $count = null; if ($this->collReviewss === null) { if ($this->isNew()) { $count = 0; } else { $criteria->add(ReviewsPeer::IMAGES_ID, $this->id); $count = ReviewsPeer::doCount($criteria, false, $con); } } else { // criteria has no effect for a new object if (!$this->isNew()) { // the following code is to determine if a new query is // called for. If the criteria is the same as the last // one, just return count of the collection. $criteria->add(ReviewsPeer::IMAGES_ID, $this->id); if (!isset($this->lastReviewsCriteria) || !$this->lastReviewsCriteria->equals($criteria)) { $count = ReviewsPeer::doCount($criteria, false, $con); } else { $count = count($this->collReviewss); } } else { $count = count($this->collReviewss); } } return $count; }
/** * Kanji Flashcard review page with uiFlashcardReview * * GET request = review page * * type = 'expired'|'untested'|'relearned'|'fresh' * box = 'all'|[1-5] * filt = ''|'rtk1'|'rtk3' * * POST request = ajax request during review * * @param object $request */ protected function reviewAction($request) { $reviewBox = $request->getParameter('box', 'all'); $reviewType = $request->getParameter('type', 'expired'); $reviewFilt = $request->getParameter('filt', ''); $reviewMerge = $request->getParameter('merge') ? true : false; // validate $this->forward404Unless(preg_match('/^(all|[1-9]+)$/', $reviewBox)); $this->forward404Unless(preg_match('/^(expired|untested|relearned|fresh)$/', $reviewType)); $this->forward404Unless($reviewFilt == '' || preg_match('/(rtk1|rtk3)/', $reviewFilt)); // pick title $this->setReviewTitle($reviewType, $reviewFilt); // $sAjaxUrl = $this->getController()->genUrl('@review'); $options = array('partial_name' => 'review/ReviewKanji', 'ajax_url' => $sAjaxUrl, 'ts_start' => ReviewsPeer::getLocalizedTimestamp(), 'fn_get_flashcard' => array('KanjisPeer', 'getFlashcardData'), 'fn_put_flashcard' => array('ReviewsPeer', 'putFlashcardData')); if ($request->getMethod() !== coreRequest::POST) { $options['items'] = ReviewsPeer::getFlashcards($reviewBox, $reviewType, $reviewFilt, $reviewMerge); $this->uiFR = new uiFlashcardReview($options); } else { /* if (rand(1,10) < 3) { sleep(6); }*/ // handle Ajax request (or throws exception) $oJson = coreJson::decode($request->getParameter('json', '{}')); if (!empty($oJson)) { $flashcardReview = new uiFlashcardReview($options); return $this->renderText($flashcardReview->handleJsonRequest($oJson)); } throw new rtkAjaxException('Empty JSON Request.'); } return coreView::SUCCESS; }
<div class="frame"> <ul> <?php foreach (ReviewsPeer::getRestudyKanjiList($_user->getUserId()) as $R) { ?> <li<?php echo $R['framenum'] == $framenum ? ' class="selected"' : ''; ?> > <span><?php echo $R['framenum']; ?> </span> <?php $kw = preg_replace('/\\//', '<br/>', $R['keyword']); echo link_to($kw, 'study/edit?id=' . $R['framenum']); ?> </li> <?php } ?> </ul> <div class="clear"></div> </div>
public function executeExportflashcards() { $throttler = new RequestThrottler($this->getUser(), 'export'); if (!$throttler->isValid()) { return $this->renderPartial('misc/requestThrottleError'); } $csv = new ExportCSV($this->getContext()->getDatabase()); $select = ReviewsPeer::getSelectForExport($this->getUser()->getUserId()); $csvText = $csv->export($select, array('FrameNumber', 'Kanji', 'Keyword', 'LastReview', 'ExpireDate', 'LeitnerBox', 'FailCount', 'PassCount'), array('col_escape' => array(0, 1, 1, 0, 0, 0, 0, 0))); $throttler->setTimeout(); $this->getResponse()->setFileAttachmentHeaders('rtk_flashcards.csv'); $this->setLayout(false); return $this->renderText($csvText); }
/** * Add cards in Heisig order. * * Selection should be a frame number to add up to, * or a number of cards to add "+10", filling in all missing cards in the RTK range. * * @param string $selection "56" (add up to 56), or "+20" (add 20 cards) * * @return int Number of cards in selection (also 0), or false if error */ public function addHeisigRange($userId, $selection) { $this->itemIds = array(); // get user's existing flashcard ids in RTK range $userCards = ReviewsPeer::getFlashcardIds($userId, 'rtk1+3'); // map in an array, 1 means card exists, 0 it doesn't $inDeck = array(); foreach ($userCards as $id) { $inDeck[(int) $id] = true; } // add a number of cards, or up to frame number, fill in the missing cards if (preg_match('/^\\+([0-9]+)$/', $selection, $matches)) { $range = $matches[1]; if ($range < 1) { $this->request->setError('x', 'Invalid range of cards'); return false; } for ($i = 1, $n = 0; $n < $range && $i <= rtkBook::MAXKANJI_VOL3; $i++) { if (!isset($inDeck[$i])) { $this->itemIds[] = $i; $n++; } } } else { $addTo = intval($selection); if (!rtkBook::isValidRtkFrameNum($addTo)) { $this->request->setError('x', sprintf('Invalid index number: "%s"', $selection)); return false; } for ($i = 1; $i <= $addTo; $i++) { if (!isset($inDeck[$i])) { $this->itemIds[] = $i; } } } return $this->getNumCards(); }
<div class="summary"> <span class="total"><strong><?php echo $total_flashcards; ?> </strong> kanji flashcards</span> ( <?php echo link_to('browse detailed list', 'review/flashcardlist'); ?> - <a href="@manage">manage flashcards</a> ) </div> <div class="filterstop"> <?php $links = array(array('ALL', '#', array('class' => 'uiFilterStd-all')), array('RTK1', '#', array('class' => 'uiFilterStd-rtk1'))); if (ReviewsPeer::getCountRtK3($_user->getUserId()) > 0) { $links[] = array('RTK3', '#', array('class' => 'uiFilterStd-rtk3')); } switch ($filter) { case 'rtk1': $active = 1; break; case 'rtk3': $active = 2; break; default: $active = 0; break; } echo ui_filter_std('Filter:', $links, array('id' => 'rtk-filter', 'active' => $active)); ?>
/** * Updates the flashcard count. * * @param int $userId User id. * * @return boolean TRUE on success, FALSE on error. */ public static function updateFlashcardCount($userId) { $data = array('fc_count' => ReviewsPeer::getFlashcardCount($userId)); return self::getInstance()->updateCols($userId, $data); }
/** * Retrieve multiple objects by pkey. * * @param array $pks List of primary keys * @param PropelPDO $con the connection to use * @throws PropelException Any exceptions caught during processing will be * rethrown wrapped into a PropelException. */ public static function retrieveByPKs($pks, PropelPDO $con = null) { if ($con === null) { $con = Propel::getConnection(ReviewsPeer::DATABASE_NAME, Propel::CONNECTION_READ); } $objs = null; if (empty($pks)) { $objs = array(); } else { $criteria = new Criteria(ReviewsPeer::DATABASE_NAME); $criteria->add(ReviewsPeer::ID, $pks, Criteria::IN); $objs = ReviewsPeer::doSelect($criteria, $con); } return $objs; }
<span class="btn"> <?php echo link_to('<img src="/images/2.0/study/review-small.gif" alt="Review" width="56" height="19" />', '@review', array('query_string' => 'type=relearned')); ?> <?php echo link_to('Clear', 'study/clear', array('class' => 'cancel')); ?> </span> </p> <?php } ?> <?php if ($restudyCount = ReviewsPeer::getRestudyKanjiCount($_user->getUserId())) { ?> <p class="set"> <em><?php echo $restudyCount; ?> </em> to restudy<br/> <span class="btn"> <?php echo link_to('<img src="/images/2.0/study/review-small.gif" alt="Review" width="56" height="19" />', '@review', array('query_string' => 'box=1')); ?> </span> </p> <div class="failed-kanji">