Index: trunk/extensions/ArticleFeedbackv5/modules/jquery.articleFeedback/jquery.articleFeedback.js |
— | — | @@ -131,6 +131,15 @@ |
132 | 132 | */ |
133 | 133 | showOptions: 'show' === mw.user.bucket( 'ext.articleFeedback-options', mw.config.get( 'wgArticleFeedbackv5Options' ) ), |
134 | 134 | |
| 135 | + /** |
| 136 | + * Whether we need to load the aggregate ratings the next time the |
| 137 | + * button is clicked. This is initially set to true, turned to |
| 138 | + * false after the first time, then turned back to true on form |
| 139 | + * submission, in case the user wants to go back and see the ratings with |
| 140 | + * theirs included. |
| 141 | + */ |
| 142 | + loadAggregate: true, |
| 143 | + |
135 | 144 | // }}} |
136 | 145 | // {{{ buildForm |
137 | 146 | |
— | — | @@ -301,9 +310,6 @@ |
302 | 311 | $block.find( '.articleFeedbackv5-options' ).hide(); |
303 | 312 | } |
304 | 313 | |
305 | | - // Grab the results in the background |
306 | | - $.articleFeedbackv5.currentBucket().loadAggregateRatings(); |
307 | | - |
308 | 314 | return $block; |
309 | 315 | }, |
310 | 316 | |
— | — | @@ -368,6 +374,10 @@ |
369 | 375 | // Set up form/report switch behavior |
370 | 376 | $block.find( '.articleFeedbackv5-switch' ) |
371 | 377 | .click( function ( e ) { |
| 378 | + if ( $(this).attr( 'rel' ) == 'report' && $.articleFeedbackv5.currentBucket().loadAggregate ) { |
| 379 | + $.articleFeedbackv5.currentBucket().loadAggregateRatings(); |
| 380 | + $.articleFeedbackv5.currentBucket().loadAggregate = false; |
| 381 | + } |
372 | 382 | $.articleFeedbackv5.$holder.find( '.articleFeedbackv5-visibleWith-' + $(this).attr( 'rel' ) ) |
373 | 383 | .show(); |
374 | 384 | $.articleFeedbackv5.$holder.find( '.articleFeedbackv5-switch' ) |
— | — | @@ -535,56 +545,43 @@ |
536 | 546 | * the label's CSS class |
537 | 547 | */ |
538 | 548 | loadAggregateRatings: function () { |
539 | | - var usecache = !( !$.articleFeedbackv5.anonymous || $.articleFeedbackv5.alreadySubmitted ); |
540 | | - |
541 | 549 | $.ajax( { |
542 | 550 | 'url': $.articleFeedbackv5.apiUrl, |
543 | 551 | 'type': 'GET', |
544 | 552 | 'dataType': 'json', |
545 | | - 'cache': usecache, |
546 | 553 | 'data': { |
547 | 554 | 'action': 'query', |
548 | 555 | 'format': 'json', |
549 | | - 'list': 'articlefeedbackv5', |
550 | | - 'afsubaction': 'showratings', |
| 556 | + 'list': 'articlefeedbackv5-view-ratings', |
551 | 557 | 'afpageid': $.articleFeedbackv5.pageId, |
552 | | - 'afanontoken': usecache ? $.articleFeedbackv5.userId : '', |
553 | | - 'afuserrating': Number( !usecache ), |
| 558 | + 'afanontoken': $.articleFeedbackv5.userId, |
554 | 559 | 'maxage': 0, |
555 | | - 'smaxage': usecache ? 0 : mw.config.get( 'wgArticleFeedbackSMaxage' ) |
| 560 | + 'smaxage': mw.config.get( 'wgArticleFeedbackSMaxage' ) |
556 | 561 | }, |
557 | 562 | 'success': function ( data ) { |
558 | 563 | // Get data |
559 | 564 | if ( |
560 | 565 | !( 'query' in data ) |
561 | | - || !( 'articlefeedbackv5' in data.query ) |
562 | | - || !$.isArray( data.query.articlefeedbackv5 ) |
563 | | - || !data.query.articlefeedbackv5.length |
| 566 | + || !( 'articlefeedbackv5-view-ratings' in data.query ) |
| 567 | + || !( 'rollup' in data.query['articlefeedbackv5-view-ratings'] ) |
564 | 568 | ) { |
565 | 569 | mw.log( 'ArticleFeedback invalid response error.' ); |
566 | | - if ($.articleFeedbackv5.debug && 'error' in data && 'info' in data.error) { |
567 | | - console.log( data.error.info ); |
568 | | - $.articleFeedbackv5.$holder.find( '.articleFeedbackv5-error-message' ).html( data.error.info.replace( "\n", '<br />' ) ); |
| 570 | + var msg = 'ArticleFeedback invalid response error.'; |
| 571 | + if ( 'error' in data && 'info' in data.error ) { |
| 572 | + msg = data.error.info; |
| 573 | + } else { |
| 574 | + console.log(data); |
569 | 575 | } |
570 | | - $.articleFeedbackv5.$holder.find( '.articleFeedbackv5-error' ).show(); |
| 576 | + $.articleFeedbackv5.currentBucket().markShowstopperError( msg ); |
571 | 577 | return; |
572 | 578 | } |
573 | | - $.articleFeedbackv5.$holder.find( '.articleFeedbackv5-error' ).show(); |
574 | | - var feedback = data.query.articlefeedbackv5[0]; |
| 579 | + var rollup = data.query['articlefeedbackv5-view-ratings'].rollup; |
575 | 580 | |
576 | | - // Index rating data by rating ID |
577 | | - var ratings = {}; |
578 | | - if ( typeof feedback.ratings === 'object' && feedback.ratings !== null ) { |
579 | | - for ( var i = 0; i < feedback.ratings.length; i++ ) { |
580 | | - ratings[feedback.ratings[i].ratingid] = feedback.ratings[i]; |
581 | | - } |
582 | | - } |
583 | | - |
584 | 581 | // Ratings |
585 | 582 | $.articleFeedbackv5.$holder.find( '.articleFeedbackv5-rating' ).each( function () { |
586 | 583 | var name = $(this).attr( 'rel' ); |
587 | 584 | var info = $.articleFeedbackv5.currentBucket().ratingInfo; |
588 | | - var rating = name in info && info[name] in ratings ? ratings[info[name]] : null; |
| 585 | + var rating = name in info && info[name] in rollup ? rollup[info[name]] : null; |
589 | 586 | if ( |
590 | 587 | rating !== null |
591 | 588 | && 'total' in rating |
— | — | @@ -597,7 +594,7 @@ |
598 | 595 | $(this).find( '.articleFeedbackv5-rating-meter div' ) |
599 | 596 | .css( 'width', Math.round( average * 21 ) + 'px' ); |
600 | 597 | $(this).find( '.articleFeedbackv5-rating-count' ) |
601 | | - .text( mw.msg( 'articlefeedbackv5-report-ratings', rating.countall ) ); |
| 598 | + .text( mw.msg( 'articlefeedbackv5-report-ratings', rating.count ) ); |
602 | 599 | } else { |
603 | 600 | // Special case for no ratings |
604 | 601 | $(this).find( '.articleFeedbackv5-rating-average' ) |
— | — | @@ -626,6 +623,7 @@ |
627 | 624 | }, |
628 | 625 | 'error': function () { |
629 | 626 | mw.log( 'Report loading error' ); |
| 627 | + $.articleFeedbackv5.currentBucket().markShowstopperError( 'Report loading error' ); |
630 | 628 | $.articleFeedbackv5.$holder.find( '.articleFeedbackv5-error' ).show(); |
631 | 629 | } |
632 | 630 | } ); |
— | — | @@ -727,6 +725,31 @@ |
728 | 726 | }, |
729 | 727 | |
730 | 728 | // }}} |
| 729 | + // {{{ markShowstopperError |
| 730 | + |
| 731 | + /** |
| 732 | + * Marks a showstopper error |
| 733 | + * |
| 734 | + * @param string message the message to display, if in dev |
| 735 | + */ |
| 736 | + markShowstopperError: function ( message ) { |
| 737 | + console.log( message ); |
| 738 | + if ($.articleFeedbackv5.debug && message) { |
| 739 | + $.articleFeedbackv5.$holder.find( '.articleFeedbackv5-error-message' ).html( message.replace( "\n", '<br />' ) ); |
| 740 | + } |
| 741 | + var veil = $.articleFeedbackv5.$holder.find( '.articleFeedbackv5-error' ); |
| 742 | + var box = $.articleFeedbackv5.$holder.find( '.articleFeedbackv5-panel' ); |
| 743 | + // TODO: Make this smarter -- on ubuntu/ff at least, using the |
| 744 | + // offset puts it about 100px down from where it should be; |
| 745 | + // this math corrects for it, but will most likely be wrong on |
| 746 | + // other browsers |
| 747 | + veil.css('top', box.find('.articleFeedbackv5-ui').offset().top / 2 + 10); |
| 748 | + veil.css('width', box.width()); |
| 749 | + veil.css('height', box.height()); |
| 750 | + veil.show(); |
| 751 | + }, |
| 752 | + |
| 753 | + // }}} |
731 | 754 | // {{{ setSuccessState |
732 | 755 | |
733 | 756 | /** |
— | — | @@ -750,9 +773,10 @@ |
751 | 774 | */ |
752 | 775 | onSubmit: function () { |
753 | 776 | |
| 777 | + $.articleFeedbackv5.currentBucket().loadAggregate = true; |
754 | 778 | |
755 | 779 | ///////////////////////////////////////////////////////////////////////////////// |
756 | | -// BOOKMARK |
| 780 | +// TODO: Email capture |
757 | 781 | ///////////////////////////////////////////////////////////////////////////////// |
758 | 782 | |
759 | 783 | // 'submit': function () { |
Index: trunk/extensions/ArticleFeedbackv5/modules/ext.articleFeedback/ext.articleFeedback.dashboard.css |
— | — | @@ -1,33 +1,33 @@ |
2 | | -.articleFeedback-table { |
| 2 | +.articleFeedbackv5-table { |
3 | 3 | border: solid 1px #cccccc; |
4 | 4 | margin-bottom: 2em; |
5 | 5 | } |
6 | 6 | |
7 | | -.articleFeedback-table caption { |
| 7 | +.articleFeedbackv5-table caption { |
8 | 8 | text-align: left; |
9 | 9 | font-size: 1.6em; |
10 | 10 | margin-bottom: 0.5em; |
11 | 11 | } |
12 | 12 | |
13 | | -.articleFeedback-table th { |
| 13 | +.articleFeedbackv5-table th { |
14 | 14 | padding-left: 0.75em; |
15 | 15 | padding-top: 0.25em; |
16 | 16 | padding-bottom: 0.25em; |
17 | 17 | text-align: left; |
18 | 18 | } |
19 | 19 | |
20 | | -.articleFeedback-table td { |
| 20 | +.articleFeedbackv5-table td { |
21 | 21 | padding: 0.25em 0.75em; |
22 | 22 | border-top: solid 1px #eeeeee; |
23 | 23 | } |
24 | 24 | |
25 | | -.articleFeedback-table td.articleFeedback-table-column-page, |
26 | | -.articleFeedback-table td.articleFeedback-table-column-category { |
| 25 | +.articleFeedbackv5-table td.articleFeedbackv5-table-column-page, |
| 26 | +.articleFeedbackv5-table td.articleFeedbackv5-table-column-category { |
27 | 27 | text-align: left; |
28 | 28 | } |
29 | 29 | |
30 | | -.articleFeedback-table td.articleFeedback-table-column-rating, |
31 | | -.articleFeedback-table td.articleFeedback-table-column-average { |
| 30 | +.articleFeedbackv5-table td.articleFeedbackv5-table-column-rating, |
| 31 | +.articleFeedbackv5-table td.articleFeedbackv5-table-column-average { |
32 | 32 | text-align: right; |
33 | 33 | } |
34 | 34 | |
— | — | @@ -37,34 +37,34 @@ |
38 | 38 | * later if found useful. |
39 | 39 | */ |
40 | 40 | /* |
41 | | -.articleFeedback-table-column-score-0, |
42 | | -.articleFeedback-table-column-score-1 { |
| 41 | +.articleFeedbackv5-table-column-score-0, |
| 42 | +.articleFeedbackv5-table-column-score-1 { |
43 | 43 | background-color: #ffcccc; |
44 | 44 | } |
45 | 45 | |
46 | 46 | |
47 | | -.articleFeedback-table-column-score-2, |
48 | | -.articleFeedback-table-column-bad { |
| 47 | +.articleFeedbackv5-table-column-score-2, |
| 48 | +.articleFeedbackv5-table-column-bad { |
49 | 49 | background-color: #ffcc99; |
50 | 50 | } |
51 | 51 | |
52 | | -.articleFeedback-table-column-score-3 { |
| 52 | +.articleFeedbackv5-table-column-score-3 { |
53 | 53 | background-color: #ffff99; |
54 | 54 | } |
55 | 55 | |
56 | | -.articleFeedback-table-column-score-4, |
57 | | -.articleFeedback-table-column-good { |
| 56 | +.articleFeedbackv5-table-column-score-4, |
| 57 | +.articleFeedbackv5-table-column-good { |
58 | 58 | background-color: #99ff99; |
59 | 59 | } |
60 | | -.articleFeedback-table-column-score-5 { |
| 60 | +.articleFeedbackv5-table-column-score-5 { |
61 | 61 | background-color: #55ff55; |
62 | 62 | } |
63 | 63 | */ |
64 | 64 | |
65 | | -.articleFeedback-table-column-bad { |
| 65 | +.articleFeedbackv5-table-column-bad { |
66 | 66 | background-color: #ffcc99; |
67 | 67 | } |
68 | 68 | |
69 | | -.articleFeedback-table-column-good { |
| 69 | +.articleFeedbackv5-table-column-good { |
70 | 70 | background-color: #99ff99; |
71 | | -} |
\ No newline at end of file |
| 71 | +} |
Index: trunk/extensions/ArticleFeedbackv5/modules/ext.articleFeedback/ext.articleFeedback.css |
— | — | @@ -1,16 +1,16 @@ |
2 | 2 | /* |
3 | 3 | * Styles for Article Feedback Extension |
4 | 4 | */ |
5 | | -#articleFeedback-dialog { |
| 5 | +#articleFeedbackv5-dialog { |
6 | 6 | padding: 2em; |
7 | 7 | padding-top: 1em; |
8 | 8 | } |
9 | 9 | |
10 | | -.articleFeedback-survey-disclaimer { |
| 10 | +.articleFeedbackv5-survey-disclaimer { |
11 | 11 | font-weight: normal; /* Override bold */ |
12 | 12 | font-style: italic; |
13 | 13 | } |
14 | 14 | |
15 | | -.articleFeedback-survey-disclaimer a { |
| 15 | +.articleFeedbackv5-survey-disclaimer a { |
16 | 16 | color: #0645AD; /* Override blackish color set by JUI */ |
17 | 17 | } |
Index: trunk/extensions/ArticleFeedbackv5/ArticleFeedbackv5.php |
— | — | @@ -1,10 +1,10 @@ |
2 | 2 | <?php |
3 | 3 | /** |
4 | 4 | * Article Feedback extension |
5 | | - * |
| 5 | + * |
6 | 6 | * @file |
7 | 7 | * @ingroup Extensions |
8 | | - * |
| 8 | + * |
9 | 9 | * @author Trevor Parscal <trevor@wikimedia.org> |
10 | 10 | * @license GPL v2 or later |
11 | 11 | * @version 0.1.0 |
— | — | @@ -78,14 +78,14 @@ |
79 | 79 | * |
80 | 80 | * Since the dashboard is powered by a SpecialPage, we cannot rel on the built-in |
81 | 81 | * MW talk page for this, so we must expose our own page - internally or externally. |
82 | | - * |
83 | | - * This value will be passed into an i18n message which will parse the URL as an |
| 82 | + * |
| 83 | + * This value will be passed into an i18n message which will parse the URL as an |
84 | 84 | * external link using wikitext, so this must be a full URL. |
85 | 85 | * @var string |
86 | 86 | */ |
87 | 87 | $wgArticleFeedbackv5DashboardTalkPage = "http://www.mediawiki.org/wiki/Talk:Article_feedback"; |
88 | 88 | |
89 | | -# TODO: What's up with the surveys, then? |
| 89 | +# TODO: What's up with the surveys, then? |
90 | 90 | // Would ordinarily call this articlefeedback but survey names are 16 chars max |
91 | 91 | $wgPrefSwitchSurveys['articlerating'] = array( |
92 | 92 | 'updatable' => false, |
— | — | @@ -148,13 +148,14 @@ |
149 | 149 | |
150 | 150 | // Autoloading |
151 | 151 | $dir = dirname( __FILE__ ) . '/'; |
152 | | -$wgAutoloadClasses['ApiQueryArticleFeedbackv5'] = $dir . 'api/ApiQueryArticleFeedbackv5.php'; |
153 | | -$wgAutoloadClasses['ApiArticleFeedbackv5Utils'] = $dir . 'api/ApiArticleFeedbackv5Utils.php'; |
154 | | -$wgAutoloadClasses['ApiArticleFeedbackv5'] = $dir . 'api/ApiArticleFeedbackv5.php'; |
155 | | -$wgAutoloadClasses['ArticleFeedbackv5Hooks'] = $dir . 'ArticleFeedbackv5.hooks.php'; |
156 | | -$wgAutoloadClasses['SpecialArticleFeedbackv5'] = $dir . 'SpecialArticleFeedbackv5.php'; |
157 | | -$wgExtensionMessagesFiles['ArticleFeedbackv5'] = $dir . 'ArticleFeedbackv5.i18n.php'; |
158 | | -$wgExtensionAliasesFiles['ArticleFeedbackv5'] = $dir . 'ArticleFeedbackv5.alias.php'; |
| 152 | +$wgAutoloadClasses['ApiQueryArticleFeedbackv5'] = $dir . 'api/ApiQueryArticleFeedbackv5.php'; |
| 153 | +$wgAutoloadClasses['ApiArticleFeedbackv5Utils'] = $dir . 'api/ApiArticleFeedbackv5Utils.php'; |
| 154 | +$wgAutoloadClasses['ApiArticleFeedbackv5'] = $dir . 'api/ApiArticleFeedbackv5.php'; |
| 155 | +$wgAutoloadClasses['ApiViewRatingsArticleFeedbackv5'] = $dir . 'api/ApiViewRatingsArticleFeedbackv5.php'; |
| 156 | +$wgAutoloadClasses['ArticleFeedbackv5Hooks'] = $dir . 'ArticleFeedbackv5.hooks.php'; |
| 157 | +$wgAutoloadClasses['SpecialArticleFeedbackv5'] = $dir . 'SpecialArticleFeedbackv5.php'; |
| 158 | +$wgExtensionMessagesFiles['ArticleFeedbackv5'] = $dir . 'ArticleFeedbackv5.i18n.php'; |
| 159 | +$wgExtensionAliasesFiles['ArticleFeedbackv5'] = $dir . 'ArticleFeedbackv5.alias.php'; |
159 | 160 | |
160 | 161 | // Hooks |
161 | 162 | $wgHooks['LoadExtensionSchemaUpdates'][] = 'ArticleFeedbackv5Hooks::loadExtensionSchemaUpdates'; |
— | — | @@ -167,6 +168,7 @@ |
168 | 169 | |
169 | 170 | // API Registration |
170 | 171 | $wgAPIListModules['articlefeedbackv5'] = 'ApiQueryArticleFeedbackv5'; |
| 172 | +$wgAPIListModules['articlefeedbackv5-view-ratings'] = 'ApiViewRatingsArticleFeedbackv5'; |
171 | 173 | $wgAPIModules['articlefeedbackv5'] = 'ApiArticleFeedbackv5'; |
172 | 174 | |
173 | 175 | // Special Page |
Index: trunk/extensions/ArticleFeedbackv5/api/ApiViewRatingsArticleFeedbackv5.php |
— | — | @@ -0,0 +1,206 @@ |
| 2 | +<?php |
| 3 | +/** |
| 4 | + * ApiViewRatingsArticleFeedbackv5 class |
| 5 | + * |
| 6 | + * @package ArticleFeedback |
| 7 | + * @subpackage Api |
| 8 | + * @author Greg Chiasson <greg@omniti.com> |
| 9 | + * @author Reha Sterbin <reha@omniti.com> |
| 10 | + * @version $Id$ |
| 11 | + */ |
| 12 | + |
| 13 | +/** |
| 14 | + * This class pulls the aggregated ratings for display in Bucket #5 |
| 15 | + * |
| 16 | + * @package ArticleFeedback |
| 17 | + * @subpackage Api |
| 18 | + */ |
| 19 | +class ApiViewRatingsArticleFeedbackv5 extends ApiQueryBase { |
| 20 | + |
| 21 | + /** |
| 22 | + * Constructor |
| 23 | + */ |
| 24 | + public function __construct( $query, $moduleName ) { |
| 25 | + parent::__construct( $query, $moduleName, 'af' ); |
| 26 | + } |
| 27 | + |
| 28 | + /** |
| 29 | + * Execute the API call: Pull the aggregated ratings |
| 30 | + */ |
| 31 | + public function execute() { |
| 32 | + $params = $this->extractRequestParams(); |
| 33 | + global $wgArticleFeedbackv5RatingTypes; |
| 34 | + |
| 35 | + $params = $this->extractRequestParams(); |
| 36 | + $result = $this->getResult(); |
| 37 | + $result_path = array( 'query', $this->getModuleName() ); |
| 38 | + $revisionId = ApiArticleFeedbackv5Utils::getRevisionId( $params['pageid'] ); |
| 39 | + $pageId = $params['pageid']; |
| 40 | + $rollup = $this->fetchPageRollup( $pageId ); |
| 41 | + |
| 42 | + $result->addValue( $result_path, 'pageid', $params['pageid'] ); |
| 43 | + $result->addValue( $result_path, 'status', 'current' ); |
| 44 | + |
| 45 | + $info = array(); |
| 46 | + foreach ( $rollup as $row ) { |
| 47 | + $info[$row->field_id] = array( |
| 48 | + 'ratingdesc' => $row->field_name, |
| 49 | + 'ratingid' => (int) $row->field_id, |
| 50 | + 'total' => (int) $row->points, |
| 51 | + 'count' => (int) $row->reviews, |
| 52 | + ); |
| 53 | + } |
| 54 | + $result->addValue( $result_path, 'rollup', $info ); |
| 55 | + |
| 56 | + $result->setIndexedTagName_internal( array( 'query', $this->getModuleName() ), 'aa' ); |
| 57 | + } |
| 58 | + |
| 59 | + /** |
| 60 | + * Pulls the page rollup row |
| 61 | + * |
| 62 | + * @param $pageId int the page id |
| 63 | + * @return array the rollup row |
| 64 | + */ |
| 65 | + public function fetchPageRollup( $pageId ) { |
| 66 | + return $this->fetchRollup( $pageId, 0, 'page' ); |
| 67 | + } |
| 68 | + |
| 69 | + /** |
| 70 | + * Pulls the revision rollup row |
| 71 | + * |
| 72 | + * @param $pageId int the page id |
| 73 | + * @param $revisionLimit int [optional] go back only to this revision |
| 74 | + * @return array the rollup row |
| 75 | + */ |
| 76 | + public function fetchRevisionRollup( $pageId, $revisionLimit = 0 ) { |
| 77 | + return $this->fetchRollup( $pageId, $revisionLimit, 'revision' ); |
| 78 | + } |
| 79 | + |
| 80 | + /** |
| 81 | + * Pulls a rollup row |
| 82 | + * |
| 83 | + * @param $pageId int the page id |
| 84 | + * @param $revisionLimit int go back only to this revision |
| 85 | + * @param $type string the type of row to fetch ('page' or 'revision') |
| 86 | + * @return array the rollup row |
| 87 | + */ |
| 88 | + private function fetchRollup( $pageId, $revisionLimit, $type ) { |
| 89 | + $dbr = wfGetDB( DB_SLAVE ); |
| 90 | + $where = array(); |
| 91 | + |
| 92 | + if ( $type == 'page' ) { |
| 93 | + $table = 'article_feedback_ratings_rollup'; |
| 94 | + $prefix = 'aap'; |
| 95 | + } else { |
| 96 | + $table = 'article_revision_feedback_ratings_rollup'; |
| 97 | + $prefix = 'afr'; |
| 98 | + $where[] = 'afr_revision_id >= ' . $revisionLimit; |
| 99 | + } |
| 100 | + $where[$prefix . '_page_id'] = $pageId; |
| 101 | + $where[] = $prefix . '_rating_id = aaf_id'; |
| 102 | + |
| 103 | + $rows = $dbr->select( |
| 104 | + array( 'aft_' . $table, 'aft_article_field' ), |
| 105 | + array( |
| 106 | + 'aaf_name AS field_name', |
| 107 | + $prefix . '_rating_id AS field_id', |
| 108 | + 'SUM(' . $prefix . '_total) AS points', |
| 109 | + 'SUM(' . $prefix . '_count) AS reviews', |
| 110 | + ), |
| 111 | + $where, |
| 112 | + __METHOD__, |
| 113 | + array( |
| 114 | + 'GROUP BY' => $prefix . '_rating_id, aaf_name' |
| 115 | + ) |
| 116 | + ); |
| 117 | + |
| 118 | + return $rows; |
| 119 | + } |
| 120 | + |
| 121 | + /** |
| 122 | + * Gets the allowed parameters |
| 123 | + * |
| 124 | + * @return array the params info, indexed by allowed key |
| 125 | + */ |
| 126 | + public function getAllowedParams() { |
| 127 | + return array( |
| 128 | + 'userrating' => 0, |
| 129 | + 'anontoken' => null, |
| 130 | + 'userid' => null, |
| 131 | + 'subaction' => array( |
| 132 | + ApiBase::PARAM_REQUIRED => false, |
| 133 | + ApiBase::PARAM_ISMULTI => false, |
| 134 | + ApiBase::PARAM_TYPE => array( 'showratings', 'newform' ), |
| 135 | + ), |
| 136 | + 'revid' => array( |
| 137 | + ApiBase::PARAM_REQUIRED => false, |
| 138 | + ApiBase::PARAM_ISMULTI => false, |
| 139 | + ApiBase::PARAM_TYPE => 'integer', |
| 140 | + ), |
| 141 | + 'pageid' => array( |
| 142 | + ApiBase::PARAM_REQUIRED => true, |
| 143 | + ApiBase::PARAM_ISMULTI => false, |
| 144 | + ApiBase::PARAM_TYPE => 'integer', |
| 145 | + ) |
| 146 | + ); |
| 147 | + } |
| 148 | + |
| 149 | + /** |
| 150 | + * Gets the parameter descriptions |
| 151 | + * |
| 152 | + * @return array the descriptions, indexed by allowed key |
| 153 | + */ |
| 154 | + public function getParamDescription() { |
| 155 | + return array( |
| 156 | + 'pageid' => 'Page ID to get feedback ratings for', |
| 157 | + 'revid' => 'Rev ID to get feedback ratings for', |
| 158 | + 'anontoken' => 'Token for anonymous users', |
| 159 | + ); |
| 160 | + } |
| 161 | + |
| 162 | + /** |
| 163 | + * Gets the api descriptions |
| 164 | + * |
| 165 | + * @return array the description as the first element in an array |
| 166 | + */ |
| 167 | + public function getDescription() { |
| 168 | + return array( |
| 169 | + 'List article feedback ratings for a specified page' |
| 170 | + ); |
| 171 | + } |
| 172 | + |
| 173 | + /** |
| 174 | + * Gets any possible errors |
| 175 | + * |
| 176 | + * @return array the errors |
| 177 | + */ |
| 178 | + public function getPossibleErrors() { |
| 179 | + return array_merge( parent::getPossibleErrors(), array( |
| 180 | + array( 'missingparam', 'anontoken' ), |
| 181 | + array( 'code' => 'invalidtoken', 'info' => 'The anontoken is not 32 characters' ), |
| 182 | + ) |
| 183 | + ); |
| 184 | + } |
| 185 | + |
| 186 | + /** |
| 187 | + * Gets an example |
| 188 | + * |
| 189 | + * @return array the example as the first element in an array |
| 190 | + */ |
| 191 | + protected function getExamples() { |
| 192 | + return array( |
| 193 | + 'api.php?action=query&list=articlefeedbackv5-view-ratings&afpageid=1', |
| 194 | + ); |
| 195 | + } |
| 196 | + |
| 197 | + /** |
| 198 | + * Gets the version info |
| 199 | + * |
| 200 | + * @return string the SVN version info |
| 201 | + */ |
| 202 | + public function getVersion() { |
| 203 | + return __CLASS__ . ': $Id$'; |
| 204 | + } |
| 205 | + |
| 206 | +} |
| 207 | + |
Property changes on: trunk/extensions/ArticleFeedbackv5/api/ApiViewRatingsArticleFeedbackv5.php |
___________________________________________________________________ |
Added: svn:eol-style |
1 | 208 | + native |
Added: svn:keywords |
2 | 209 | + "Author Date Id HeadURL Revision" |
Index: trunk/extensions/ArticleFeedbackv5/api/ApiQueryArticleFeedbackv5.php |
— | — | @@ -1,198 +1,155 @@ |
2 | 2 | <?php |
3 | | -# This file loads the data and all. The other one saves it. |
| 3 | +/** |
| 4 | + * ApiQueryArticleFeedbackv5 class |
| 5 | + * |
| 6 | + * @package ArticleFeedback |
| 7 | + * @subpackage Api |
| 8 | + * @author Greg Chiasson <greg@omniti.com> |
| 9 | + * @author Reha Sterbin <reha@omniti.com> |
| 10 | + * @version $Id$ |
| 11 | + */ |
| 12 | + |
| 13 | +/** |
| 14 | + * This class loads data. The other one saves it. |
| 15 | + * |
| 16 | + * @package ArticleFeedback |
| 17 | + * @subpackage Api |
| 18 | + */ |
4 | 19 | class ApiQueryArticleFeedbackv5 extends ApiQueryBase { |
| 20 | + |
| 21 | + /** |
| 22 | + * Constructor |
| 23 | + */ |
5 | 24 | public function __construct( $query, $moduleName ) { |
6 | 25 | parent::__construct( $query, $moduleName, 'af' ); |
7 | 26 | } |
8 | 27 | |
9 | | - # split these two off into their own modules, instead of doing this. |
| 28 | + /** |
| 29 | + * Execute the API call: initialize a brand new request |
| 30 | + * |
| 31 | + * JS passes in a page id and, sometimes, a revision id. Return back the |
| 32 | + * correct bucket id. |
| 33 | + * |
| 34 | + * NB: This call used to return a feedback id and any associated answers as |
| 35 | + * well as the bucket id (each user was allowed one rating/comment saved |
| 36 | + * per page per revision); it no longer does, as per the 11/10 meeting -- |
| 37 | + * instead, we'll store everything the user submits. |
| 38 | + */ |
10 | 39 | public function execute() { |
| 40 | + $params = $this->extractRequestParams(); |
| 41 | + global $wgArticleFeedbackv5RatingTypes, $wgUser; |
11 | 42 | $params = $this->extractRequestParams(); |
12 | | - global $wgArticleFeedbackv5RatingTypes; |
13 | | - |
14 | | - if($params['subaction'] == 'showratings') { |
15 | | - $this->executeFetchRatings(); |
16 | | - } else { |
17 | | - $this->executeNewForm(); |
18 | | - } |
19 | | - } |
20 | | - |
21 | | - # Initialize a brand new request |
22 | | - protected function executeNewForm() { |
23 | | - global $wgUser; |
24 | | - $params = $this->extractRequestParams(); |
25 | 43 | $bucket = $this->getBucket(); |
26 | 44 | $result = $this->getResult(); |
27 | 45 | |
28 | | - if(!$params['revid']) { |
29 | | - $params['revid'] = ApiArticleFeedbackv5Utils::getRevisionId($params['pageid']); |
| 46 | + if ( !$params['revid'] ) { |
| 47 | + $params['revid'] = ApiArticleFeedbackv5Utils::getRevisionId( $params['pageid'] ); |
30 | 48 | } |
31 | | - |
32 | | - if(!$params['pageid'] || !$params['revid']) { |
| 49 | + if ( !$params['pageid'] || !$params['revid'] ) { |
33 | 50 | return null; |
34 | 51 | } |
35 | 52 | |
| 53 | + $this->logHit( $params['pageid'], $params['revid'], $bucket ); |
36 | 54 | |
37 | | - $this->logHit($params['pageid'], $params['revid'], $bucket); |
| 55 | + $result->addValue( 'form', 'pageId', $params['pageid'] ); |
| 56 | + $result->addValue( 'form', 'bucketId', $bucket ); |
38 | 57 | |
39 | | - $result->addValue('form', 'pageId', $params['pageid']); |
40 | | - $result->addValue('form', 'bucketId', $bucket); |
41 | | - # Not doing this, per 11/10 meeting, for scalability reasons. |
42 | | - #$feedbackId = $this->getFeedbackId($params, $bucket); |
43 | | - #$result->addValue('form', 'feedbackId', $feedbackId); |
| 58 | + // $feedbackId = $this->getFeedbackId($params, $bucket); |
| 59 | + // $result->addValue('form', 'feedbackId', $feedbackId); |
44 | 60 | } |
45 | 61 | |
46 | | - protected function executeFetchRatings() { |
47 | | - $params = $this->extractRequestParams(); |
48 | | - $result = $this->getResult(); |
49 | | - $revisionLimit = ApiArticleFeedbackv5Utils::getRevisionId( $params['pageid'] ); |
50 | | - $bucket = $this->getBucket(); |
51 | | - $pageId = $params['pageid']; |
52 | | - $rows = $this->fetchRevisionRollup($pageId, $revisionLimit); |
53 | | - $historical = $this->fetchPageRollup($pageId); |
54 | | - $ratings = array( |
55 | | - 'pageid' => $params['pageid'], |
56 | | - 'ratings' => array(), |
57 | | - 'status' => 'current' |
58 | | - ); |
59 | | - |
60 | | - foreach ( $rows as $row ) { |
61 | | - $overall = 0; |
62 | | - foreach($historical as $ancient) { |
63 | | - if($ancient->aaf_name == $row->aaf_name) { |
64 | | - $overall = $ancient->reviews; |
65 | | - } |
66 | | - } |
67 | | - $ratings['ratings'][] = array( |
68 | | - 'ratingdesc' => $row->field_name, |
69 | | - 'ratingid' => (int) $row->field_id, |
70 | | - 'total' => (int) $row->points, |
71 | | - 'count' => (int) $row->reviews, |
72 | | - 'countall' => (int) $overall |
73 | | - ); |
74 | | - } |
75 | | - |
76 | | - foreach ( $ratings as $r ) { |
77 | | - $result->addValue( |
78 | | - array('query', $this->getModuleName()), null, $r |
79 | | - ); |
80 | | - } |
81 | | - |
82 | | - $result->setIndexedTagName_internal( array( 'query', $this->getModuleName() ), 'aa' ); |
83 | | - } |
84 | | - |
| 62 | + /** |
| 63 | + * Determine into which bucket this request should fall |
| 64 | + * |
| 65 | + * @TODO Base this on last 2 digits of IP address per requirements; when we |
| 66 | + * have markup, we can add other buckets |
| 67 | + * |
| 68 | + * @return int the bucket id |
| 69 | + */ |
85 | 70 | protected function getBucket() { |
86 | | - #TODO base this on last 2 digits of IP address per requirements |
87 | 71 | return 5; |
88 | 72 | } |
89 | 73 | |
90 | | - private function logHit($page, $revision, $bucket) { |
| 74 | + /** |
| 75 | + * Log that this bucket was served for this page and revision |
| 76 | + * |
| 77 | + * @param $page int the page id |
| 78 | + * @param $revision int the revision id |
| 79 | + * @param $bucket int the bucket id |
| 80 | + */ |
| 81 | + private function logHit( $page, $revision, $bucket ) { |
91 | 82 | $dbr = wfGetDB( DB_SLAVE ); |
92 | 83 | $dbw = wfGetDB( DB_MASTER ); |
93 | | - $date = date('Y-m-d'); |
| 84 | + $date = date( 'Y-m-d' ); |
94 | 85 | |
95 | | - if(!$page && !$revision) { |
96 | | - return; |
| 86 | + if ( !$page && !$revision ) { |
| 87 | + return; |
97 | 88 | } |
98 | 89 | |
99 | | - # Select hit counter row |
| 90 | + // Select hit counter row |
100 | 91 | $hits = $dbr->selectField( |
101 | | - 'aft_article_hits', |
102 | | - 'aah_hits', |
103 | | - array( |
104 | | - 'aah_page_id' => $page, |
105 | | - 'aah_date' => $date, |
106 | | - 'aah_bucket_id' => $bucket, |
107 | | - ) |
108 | | - ); |
109 | | - |
110 | | - # If there's a row, update it. |
111 | | - if($hits) { |
112 | | - $dbw->update( |
113 | 92 | 'aft_article_hits', |
114 | | - array( 'aah_hits' => ($hits + 1) ), |
| 93 | + 'aah_hits', |
115 | 94 | array( |
116 | | - 'aah_page_id' => $page, |
117 | | - 'aah_date' => $date, |
118 | | - 'aah_bucket_id' => $bucket, |
| 95 | + 'aah_page_id' => $page, |
| 96 | + 'aah_date' => $date, |
| 97 | + 'aah_bucket_id' => $bucket, |
119 | 98 | ) |
120 | 99 | ); |
121 | | - } else { |
122 | | - # Otherwise, there's no row, insert one. |
123 | | - $dbw->insert('aft_article_hits', array( |
124 | | - 'aah_page_id' => $page, |
125 | | - 'aah_date' => $date, |
126 | | - 'aah_bucket_id' => $bucket, |
127 | | - 'aah_hits' => 1 |
128 | | - )); |
129 | | - } |
130 | | - } |
131 | 100 | |
132 | | - public function fetchPageRollup($pageId, $revisionLimit = 0) { |
133 | | - return $this->fetchRollup($pageId, $revisionLimit, 'page'); |
134 | | - } |
135 | | - |
136 | | - public function fetchRevisionRollup($pageId, $revisionLimit = 0) { |
137 | | - return $this->fetchRollup($pageId, $revisionLimit, 'revision'); |
138 | | - } |
139 | | - |
140 | | - private function fetchRollup($pageId, $revisionLimit, $type) { |
141 | | - $dbr = wfGetDB( DB_SLAVE ); |
142 | | - $where = array(); |
143 | | - |
144 | | - if($type == 'page') { |
145 | | - $table = 'article_feedback_ratings_rollup'; |
146 | | - $prefix = 'aap'; |
| 101 | + // If there's a row, update it. |
| 102 | + if ( $hits ) { |
| 103 | + $dbw->update( |
| 104 | + 'aft_article_hits', |
| 105 | + array( 'aah_hits' => ( $hits + 1 ) ), |
| 106 | + array( |
| 107 | + 'aah_page_id' => $page, |
| 108 | + 'aah_date' => $date, |
| 109 | + 'aah_bucket_id' => $bucket, |
| 110 | + ) |
| 111 | + ); |
147 | 112 | } else { |
148 | | - $table = 'article_revision_feedback_ratings_rollup'; |
149 | | - $prefix = 'afr'; |
150 | | - $where[] = 'afr_revision_id >= '.$revisionLimit; |
| 113 | + // Otherwise, there's no row, insert one. |
| 114 | + $dbw->insert('aft_article_hits', array( |
| 115 | + 'aah_page_id' => $page, |
| 116 | + 'aah_date' => $date, |
| 117 | + 'aah_bucket_id' => $bucket, |
| 118 | + 'aah_hits' => 1 |
| 119 | + )); |
151 | 120 | } |
152 | | - $where[$prefix.'_page_id'] = $pageId; |
153 | | - $where[] = $prefix.'_rating_id = aaf_id'; |
154 | | - |
155 | | - $rows = $dbr->select( |
156 | | - array( 'aft_'.$table, 'aft_article_field' ), |
157 | | - array( |
158 | | - 'aaf_name AS field_name', |
159 | | - $prefix.'_rating_id AS field_id', |
160 | | - 'SUM('.$prefix.'_total) AS points', |
161 | | - 'SUM('.$prefix.'_count) AS reviews', |
162 | | - ), |
163 | | - $where, |
164 | | - __METHOD__, |
165 | | - array( |
166 | | - 'GROUP BY' => $prefix.'_rating_id, aaf_name' |
167 | | - ) |
168 | | - ); |
169 | | - |
170 | | - return $rows; |
171 | 121 | } |
172 | 122 | |
173 | | - # Mostly deprecated |
174 | | - # Gets the user's feedback for this page. Only works on userids, |
175 | | - # NOT IP adderesses. Idea being that IPs can move, and we don't want |
176 | | - # your comments being shown to a different person who took your IP. |
177 | | - # ALSO take revision limit into account. |
178 | | - protected function getUserRatings($feedbackId) { |
| 123 | + /** |
| 124 | + * Gets the user's feedback for this page. |
| 125 | + * |
| 126 | + * Only works on userids, NOT IP adderesses. Idea being that IPs can move, |
| 127 | + * and we don't want your comments being shown to a different person who |
| 128 | + * took your IP. ALSO take revision limit into account. |
| 129 | + * |
| 130 | + * NB: Mostly deprecated; do not use in new code. |
| 131 | + * |
| 132 | + * @param $feedbackId the feedback id |
| 133 | + * @return array the previous answers |
| 134 | + */ |
| 135 | + protected function getUserRatings( $feedbackId ) { |
179 | 136 | global $wgUser; |
180 | 137 | $dbr = wfGetDB( DB_SLAVE ); |
181 | 138 | $feedback = array(); |
182 | 139 | $rows = $dbr->select( |
183 | 140 | array('aft_article_answer', 'aft_article_field', |
184 | | - 'aft_article_feedback'), |
| 141 | + 'aft_article_feedback'), |
185 | 142 | array('aaaa_response_rating', 'aaaa_response_text', |
186 | | - 'aaaa_response_bool', 'aaaa_response_option_id', |
187 | | - 'aaf_name', 'aaf_data_type'), |
| 143 | + 'aaaa_response_bool', 'aaaa_response_option_id', |
| 144 | + 'aaf_name', 'aaf_data_type'), |
188 | 145 | array( |
189 | | - 'aa_revision >= '.$this->getRevisionLimit(), |
| 146 | + 'aa_revision >= ' . $this->getRevisionLimit(), |
190 | 147 | 'aaaa_feedback_id' => $feedbackId, |
191 | 148 | 'aa_user_id' => $wgUser->getId(), |
192 | 149 | 'aa_is_submitted' => 1, |
193 | 150 | ) |
194 | 151 | ); |
195 | 152 | |
196 | | - foreach($rows as $row) { |
| 153 | + foreach ( $rows as $row ) { |
197 | 154 | $method = 'response_'.$row->aaf_data_type; |
198 | 155 | $feeedback[] = array( |
199 | 156 | 'name' => $row->aaf_name, |
— | — | @@ -203,10 +160,11 @@ |
204 | 161 | } |
205 | 162 | |
206 | 163 | /** |
207 | | - * Get the revision number of the oldest revision still being counted in totals. |
| 164 | + * Get the revision number of the oldest revision still being counted in |
| 165 | + * totals |
208 | 166 | * |
209 | | - * @param $pageId Integer: ID of page to check revisions for |
210 | | - * @return Integer: Oldest valid revision number or 0 of all revisions are valid |
| 167 | + * @param $pageId int ID of page to check revisions for |
| 168 | + * @return int oldest valid revision number or 0 of all revisions are valid |
211 | 169 | */ |
212 | 170 | protected function getRevisionLimit( $pageId ) { |
213 | 171 | global $wgArticleFeedbackv5RatingLifetime; |
— | — | @@ -228,6 +186,12 @@ |
229 | 187 | return 0; |
230 | 188 | } |
231 | 189 | |
| 190 | + /** |
| 191 | + * Gets the cache mode |
| 192 | + * |
| 193 | + * @param $params array the params passed in |
| 194 | + * @return string the cache mode ('anon-public-user-private' or 'public') |
| 195 | + */ |
232 | 196 | public function getCacheMode( $params ) { |
233 | 197 | if ( $params['userrating'] ) { |
234 | 198 | return 'anon-public-user-private'; |
— | — | @@ -236,6 +200,12 @@ |
237 | 201 | } |
238 | 202 | } |
239 | 203 | |
| 204 | + /** |
| 205 | + * TODO |
| 206 | + * Gets the allowed parameters |
| 207 | + * |
| 208 | + * @return array the params info, indexed by allowed key |
| 209 | + */ |
240 | 210 | public function getAllowedParams() { |
241 | 211 | return array( |
242 | 212 | 'userrating' => 0, |
— | — | @@ -243,7 +213,7 @@ |
244 | 214 | 'subaction' => array( |
245 | 215 | ApiBase::PARAM_REQUIRED => false, |
246 | 216 | ApiBase::PARAM_ISMULTI => false, |
247 | | - ApiBase::PARAM_TYPE => array('showratings','newform'), |
| 217 | + ApiBase::PARAM_TYPE => array( 'showratings', 'newform' ), |
248 | 218 | ), |
249 | 219 | 'revid' => array( |
250 | 220 | ApiBase::PARAM_REQUIRED => false, |
— | — | @@ -258,7 +228,12 @@ |
259 | 229 | ); |
260 | 230 | } |
261 | 231 | |
262 | | - # TODO |
| 232 | + /** |
| 233 | + * TODO |
| 234 | + * Gets the parameter descriptions |
| 235 | + * |
| 236 | + * @return array the descriptions, indexed by allowed key |
| 237 | + */ |
263 | 238 | public function getParamDescription() { |
264 | 239 | return array( |
265 | 240 | 'pageid' => 'Page ID to get feedback ratings for', |
— | — | @@ -267,14 +242,24 @@ |
268 | 243 | ); |
269 | 244 | } |
270 | 245 | |
271 | | - # TODO |
| 246 | + /** |
| 247 | + * TODO |
| 248 | + * Gets the api descriptions |
| 249 | + * |
| 250 | + * @return array the description as the first element in an array |
| 251 | + */ |
272 | 252 | public function getDescription() { |
273 | 253 | return array( |
274 | 254 | 'List article feedback ratings for a specified page' |
275 | 255 | ); |
276 | 256 | } |
277 | 257 | |
278 | | - # TODO |
| 258 | + /** |
| 259 | + * TODO |
| 260 | + * Gets any possible errors |
| 261 | + * |
| 262 | + * @return array the errors |
| 263 | + */ |
279 | 264 | public function getPossibleErrors() { |
280 | 265 | return array_merge( parent::getPossibleErrors(), array( |
281 | 266 | array( 'missingparam', 'anontoken' ), |
— | — | @@ -283,15 +268,27 @@ |
284 | 269 | ); |
285 | 270 | } |
286 | 271 | |
287 | | - # TODO |
| 272 | + /** |
| 273 | + * TODO |
| 274 | + * Gets an example |
| 275 | + * |
| 276 | + * @return array the example as the first element in an array |
| 277 | + */ |
288 | 278 | protected function getExamples() { |
289 | 279 | return array( |
290 | 280 | 'api.php?action=query&list=articlefeedbackv5&afpageid=1', |
291 | 281 | ); |
292 | 282 | } |
293 | 283 | |
294 | | - # TODO |
| 284 | + /** |
| 285 | + * TODO |
| 286 | + * Gets the version info |
| 287 | + * |
| 288 | + * @return string the SVN version info |
| 289 | + */ |
295 | 290 | public function getVersion() { |
296 | 291 | return __CLASS__ . ': $Id$'; |
297 | 292 | } |
| 293 | + |
298 | 294 | } |
| 295 | + |