├── assets
├── index.html
├── screen1.png
├── screen2.png
├── screen3.png
├── screen4.png
├── module_image.png
├── reputation_space_config.png
├── reputation_user_settings.png
├── reputation_spaceadmin_view.png
└── reputation_space_view_new_sorting.png
├── messages
└── de
│ ├── forms_exportForm.php
│ ├── widgets_views_stream.php
│ ├── views_adminReputation_setting.php
│ ├── views_adminReputation_exportCsv.php
│ ├── base.php
│ ├── widgets_views_spaceUserReputationWidget.php
│ ├── views_profileReputation_show.php
│ ├── views_adminReputation_show.php
│ └── forms_adminController_settings.php
├── Assets.php
├── migrations
├── uninstall.php
├── m160403_114443_reputation_content.php
└── m160403_114257_initial.php
├── module.json
├── views
├── space
│ ├── index.php
│ ├── stats.php
│ └── settings.php
├── admin
│ └── index.php
└── profile
│ └── config.php
├── widgets
├── ReputationStream.php
├── SpaceUserReputationWidget.php
└── views
│ ├── stream.php
│ └── spaceUserReputationWidget.php
├── models
├── DailyReputation.php
├── SpaceSettings.php
├── ReputationContent.php
├── ReputationBase.php
└── ReputationUser.php
├── config.php
├── Module.php
├── components
└── StreamAction.php
├── controllers
├── AdminController.php
├── ProfileController.php
└── SpaceController.php
├── README.md
└── Events.php
/assets/index.html:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/assets/screen1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/globeFrEak/humhub-modules-reputation/HEAD/assets/screen1.png
--------------------------------------------------------------------------------
/assets/screen2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/globeFrEak/humhub-modules-reputation/HEAD/assets/screen2.png
--------------------------------------------------------------------------------
/assets/screen3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/globeFrEak/humhub-modules-reputation/HEAD/assets/screen3.png
--------------------------------------------------------------------------------
/assets/screen4.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/globeFrEak/humhub-modules-reputation/HEAD/assets/screen4.png
--------------------------------------------------------------------------------
/assets/module_image.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/globeFrEak/humhub-modules-reputation/HEAD/assets/module_image.png
--------------------------------------------------------------------------------
/assets/reputation_space_config.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/globeFrEak/humhub-modules-reputation/HEAD/assets/reputation_space_config.png
--------------------------------------------------------------------------------
/assets/reputation_user_settings.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/globeFrEak/humhub-modules-reputation/HEAD/assets/reputation_user_settings.png
--------------------------------------------------------------------------------
/assets/reputation_spaceadmin_view.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/globeFrEak/humhub-modules-reputation/HEAD/assets/reputation_spaceadmin_view.png
--------------------------------------------------------------------------------
/messages/de/forms_exportForm.php:
--------------------------------------------------------------------------------
1 | "Gewichtung",
7 | );
--------------------------------------------------------------------------------
/assets/reputation_space_view_new_sorting.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/globeFrEak/humhub-modules-reputation/HEAD/assets/reputation_space_view_new_sorting.png
--------------------------------------------------------------------------------
/messages/de/widgets_views_stream.php:
--------------------------------------------------------------------------------
1 | 'Beliebt',
7 | 'Top' => 'Top',
8 | 'New' => 'Neu',
9 | 'Rising' => 'Aufsteigend'
10 | );
--------------------------------------------------------------------------------
/Assets.php:
--------------------------------------------------------------------------------
1 | sourcePath = dirname(__FILE__) . '/assets';
15 | parent::init();
16 | }
17 |
18 | }
19 |
--------------------------------------------------------------------------------
/migrations/uninstall.php:
--------------------------------------------------------------------------------
1 | dropTable('reputation_user');
11 | $this->dropTable('reputation_content');
12 | }
13 |
14 | public function down()
15 | {
16 | echo "uninstall does not support migration down.\n";
17 | return false;
18 | }
19 |
20 | }
--------------------------------------------------------------------------------
/module.json:
--------------------------------------------------------------------------------
1 | {
2 | "id": "reputation",
3 | "name": "Reputation",
4 | "description": "This Module Integrates A Reputation System Into HumHub. It Works With HumHub 1.1.x +.",
5 | "keywords": ["content", "reputation", "space", "user"],
6 | "version": "0.6.0",
7 | "time": "2017-02-05",
8 | "authors": [
9 | {
10 | "name": "Anton Kurnitzky",
11 | "name": "Philipp Horna"
12 | }
13 | ],
14 | "humhub": {
15 | "minVersion": "1.1.0"
16 | }
17 | }
--------------------------------------------------------------------------------
/messages/de/views_adminReputation_setting.php:
--------------------------------------------------------------------------------
1 | 'Konfiguration des Reputations-Moduls für diesen Space',
7 | 'Advanced Settings' => 'Erweiterte Einstellungen',
8 | 'Weightings' => 'Gewichtungen',
9 | 'Please read the documentation before changing the settings: TODO URL.' => 'Bitte Lesen sie erst die Dokumentation bevor sie Einstellungen vornehmen: TODO URL.',
10 | ' minutes ago' => ' Minuten'
11 | );
--------------------------------------------------------------------------------
/messages/de/views_adminReputation_exportCsv.php:
--------------------------------------------------------------------------------
1 | 'Dieser Space nutzt die Logarithmus Funktion. Zum Export wird ein Wert benötigt, der mit dem Prozentwert multipliziert wird. ',
7 | 'Weighting' => 'Gewichtung',
8 | 'Export as CSV' => 'CSV -Export',
9 | 'Generate CSV' => 'CSV erzeugen',
10 | 'Close' => 'Schließen',
11 | );
--------------------------------------------------------------------------------
/messages/de/base.php:
--------------------------------------------------------------------------------
1 | 'Reputation',
8 | 'This Module Integrates A Reputation System Into HumHub. It Works With HumHub 1.1.x +.' => 'Dieses Modul integriert ein Reputations-System. Es funktioniert ab Humhub 1.1.x und größer!',
9 | 'User Reputation' => 'Reputation',
10 | 'Save' => 'Speichern',
11 | 'Logarithmic' => 'Logarithmisch',
12 | 'Linear' => 'Linear',
13 | 'Hot' => 'Beliebt',
14 | 'Yes' => 'Ja',
15 | 'No' => 'Nein',
16 | 'E-mail address' => 'E-Mail-Adresse',
17 | );
18 |
--------------------------------------------------------------------------------
/messages/de/widgets_views_spaceUserReputationWidget.php:
--------------------------------------------------------------------------------
1 | Space User Reputation' => 'Space Mitglieder Reputation',
7 | 'Show all' => 'Alle anzeigen',
8 | 'Settings' => 'Einstellungen',
9 | 'No Reputation found!' => 'Keine Reputation gefunden!',
10 | 'You can only see reputation the user shares.' => 'Es wird nur Reputation angezeigt, die der Benutzer teilt.',
11 | 'Change your settings to share your Reputation on this Space' => 'Ändern Sie Ihre Einstellungen um Ihre Reputation in diesem Space zu teilen.',
12 |
13 | );
--------------------------------------------------------------------------------
/messages/de/views_profileReputation_show.php:
--------------------------------------------------------------------------------
1 | Space reputation' => 'Space-Reputation ',
7 | 'In the area below, you see how much reputation this user gained inside each space.' => 'Im unteren Bereich ist sichtbar, wie viel Reputation dieser Benutzer innerhalb verschiedener Spaces erreicht hat.',
8 | 'You can only see reputation the user shares.' => 'Es wird nur Reputation angezeigt, die der Benutzer teilt.',
9 | 'Updated' => 'Aktualisiert',
10 | 'Visible for other users.' => 'Sichtbar für andere Benutzer.',
11 | 'Share' => 'Teilen',
12 | 'Save' => 'Speichern'
13 | );
--------------------------------------------------------------------------------
/messages/de/views_adminReputation_show.php:
--------------------------------------------------------------------------------
1 | Space member reputation' => "Space-Mitglieder Reputation",
7 | 'In the area below, you see how much reputation each member inside this space has gained.' => "Im unteren Bereich ist sichtbar, wie viel Reputation die Benutzer innerhalb dieses Spaces erreicht haben.",
8 | 'User' => "Benutzer",
9 | 'Reputation' => "Reputation",
10 | 'Reputation score of this user' => 'Reputation dieses Nutzers',
11 | 'Export as CSV' => "Export als CSV",
12 | 'Update' => 'Aktualisieren',
13 | 'Configuration' => 'Konfiguration',
14 | 'Last Update: ' => 'Letzte Aktualisierung vor: ',
15 | ' minutes ago' => ' Minuten'
16 | );
--------------------------------------------------------------------------------
/views/space/index.php:
--------------------------------------------------------------------------------
1 | $space]); ?>
2 |
3 | This space is still empty! Start by posting something here...');
7 | } elseif ($isMember) {
8 | $emptyMessage = Yii::t('SpaceModule.views_space_index', 'This space is still empty! ');
9 | } else {
10 | $emptyMessage = Yii::t('SpaceModule.views_space_index', 'You are not member of this space and there is no public content, yet! ');
11 | }
12 |
13 | echo \humhub\modules\reputation\widgets\ReputationStream::widget(array(
14 | 'contentContainer' => $space,
15 | 'streamAction' => '/reputation/space/stream',
16 | 'messageStreamEmpty' => $emptyMessage,
17 | 'messageStreamEmptyWithFiltersCss' => $emptyMessage,
18 | ));
19 | ?>
--------------------------------------------------------------------------------
/messages/de/forms_adminController_settings.php:
--------------------------------------------------------------------------------
1 | "Funktion",
7 | 'Logarithm base' => "Basis des Logarithmus",
8 | 'Creating posts or comments' => "Erzeugen von Beiträgen oder Kommentaren",
9 | 'Somebody liked the post' => "Jemand gefällt der Beitrag",
10 | 'Somebody marked the post as favorite' => "Jemand markiert den Beitrag als Favorit",
11 | 'Somebody comments the post' => "Jemand kommentiert den Beitrag",
12 | 'Daily limit for Users' => "Tageslimit für Benutzer",
13 | 'Update reputation data on hourly cron job' => 'Aktualisiere Reputation im stündlichem Cron-Job',
14 | 'Decrease weighting per post' => 'Abnehmende Gewichtung pro Beitrag',
15 | 'Exponential decrease for Ranking Rising' => 'Expotentielle Degression für die Sortierung "Aufsteigend"',
16 | 'Exponential decrease for Ranking Hot' => 'Expotentielle Degression für die Sortierung "Beliebt"',
17 | 'Time in hours for the "NEW" filter to show Content' => 'Zeit in Stunden für den Filter "NEU", um Inhalte anzuzeigen',
18 | );
--------------------------------------------------------------------------------
/migrations/m160403_114443_reputation_content.php:
--------------------------------------------------------------------------------
1 | createTable('reputation_content', array(
9 | 'id' => 'pk',
10 | 'score' => 'int(11) NOT NULL',
11 | 'score_short' => 'float(11) NOT NULL',
12 | 'score_long' => 'float(11) NOT NULL',
13 | 'content_id' => 'int(11) DEFAULT NULL',
14 | 'created_at' => 'datetime DEFAULT NULL',
15 | 'created_by' => 'int(11) DEFAULT NULL',
16 | 'updated_at' => 'datetime DEFAULT NULL',
17 | 'updated_by' => 'int(11) DEFAULT NULL',
18 | ), '');
19 | }
20 |
21 | public function down() {
22 | echo "m160403_114443_reputation_content cannot be reverted.\n";
23 |
24 | return false;
25 | }
26 |
27 | /*
28 | // Use safeUp/safeDown to run migration code within a transaction
29 | public function safeUp()
30 | {
31 | }
32 |
33 | public function safeDown()
34 | {
35 | }
36 | */
37 | }
38 |
--------------------------------------------------------------------------------
/migrations/m160403_114257_initial.php:
--------------------------------------------------------------------------------
1 | createTable('reputation_user', array(
9 | 'id' => 'pk',
10 | 'value' => 'int(11) NOT NULL',
11 | 'visibility' => 'tinyint(4) NOT NULL',
12 | 'user_id' => 'int(11) NOT NULL',
13 | 'space_id' => 'int(11) NOT NULL',
14 | 'wall_id' => 'int(11) NOT NULL',
15 | 'created_at' => 'datetime DEFAULT NULL',
16 | 'created_by' => 'int(11) DEFAULT NULL',
17 | 'updated_at' => 'datetime DEFAULT NULL',
18 | 'updated_by' => 'int(11) DEFAULT NULL',
19 | ), '');
20 | }
21 |
22 | public function down() {
23 | echo "m160403_114257_initial cannot be reverted.\n";
24 |
25 | return false;
26 | }
27 |
28 | /*
29 | // Use safeUp/safeDown to run migration code within a transaction
30 | public function safeUp()
31 | {
32 | }
33 |
34 | public function safeDown()
35 | {
36 | }
37 | */
38 | }
39 |
--------------------------------------------------------------------------------
/widgets/ReputationStream.php:
--------------------------------------------------------------------------------
1 | '-limit-',
19 | 'filters' => '-filter-',
20 | 'sort' => '-sort-',
21 | 'from' => '-from-',
22 | 'mode' => \humhub\modules\reputation\components\StreamAction::MODE_HOT
23 | ], $this->streamActionParams);
24 |
25 | if ($this->contentContainer) {
26 | return $this->contentContainer->createUrl($this->streamAction, $params);
27 | } else {
28 | array_unshift($params, $this->streamAction);
29 | return Url::to($params);
30 | }
31 | }
32 |
33 | public function run() {
34 | return $this->render('stream', ['streamUrl' => $this->getStreamUrl(), 'showFilters' => $this->showFilters, 'filters' => $this->filters]);
35 | }
36 |
37 | }
38 |
--------------------------------------------------------------------------------
/widgets/SpaceUserReputationWidget.php:
--------------------------------------------------------------------------------
1 | getModule('reputation');
27 | $function = $module->settings->space()->get('functions', ReputationBase::DEFAULT_FUNCTION);
28 | $query = ReputationUser::find()->where('space_id = :spaceId AND visibility = 1', [':spaceId' => $this->contentContainer->id])->orderBy("value DESC");
29 | $query->limit($this->maxUsers);
30 | return $this->render('spaceUserReputationWidget', ['contentContainer' => $this->contentContainer, 'maxUsers' => $this->maxUsers, 'users' => $query->all(), 'function' => $function]);
31 | }
32 |
33 | }
34 |
35 | ?>
--------------------------------------------------------------------------------
/models/DailyReputation.php:
--------------------------------------------------------------------------------
1 | daily_limit = PHP_INT_MAX;
20 | } else {
21 | $this->daily_limit = $daily_limit;
22 | }
23 |
24 |
25 | if ($score <= $daily_limit) {
26 | $this->score = $score;
27 | } else {
28 | $this->score = $daily_limit;
29 | }
30 | }
31 |
32 | /**
33 | * @return int: current score
34 | */
35 | public function getScore()
36 | {
37 | return $this->score;
38 | }
39 |
40 | /**
41 | * @param $score : score to add
42 | */
43 | public function addScore($score)
44 | {
45 | if ($this->score < $this->daily_limit) {
46 | $this->score += $score;
47 | }
48 |
49 | if ($this->score > $this->daily_limit) {
50 | $this->score = $this->daily_limit;
51 | }
52 | }
53 | }
--------------------------------------------------------------------------------
/config.php:
--------------------------------------------------------------------------------
1 | 'reputation',
19 | 'class' => 'humhub\modules\reputation\Module',
20 | 'namespace' => 'humhub\modules\reputation',
21 | 'events' => [
22 | ['class' => CronController::className(), 'event' => CronController::EVENT_ON_HOURLY_RUN, 'callback' => ['humhub\modules\reputation\Events', 'onCronHourlyRun']],
23 | ['class' => Content::className(), 'event' => Content::EVENT_BEFORE_DELETE, 'callback' => ['humhub\modules\reputation\Events', 'onContentDelete']],
24 | ['class' => IntegrityController::className(), 'event' => IntegrityController::EVENT_ON_RUN, 'callback' => ['humhub\modules\reputation\Events', 'onIntegrityCheck']],
25 | ['class' => User::className(), 'event' => User::EVENT_BEFORE_DELETE, 'callback' => ['humhub\modules\reputation\Events', 'onUserDelete']],
26 | ['class' => Membership::className(), 'event' => Membership::EVENT_BEFORE_DELETE, 'callback' => ['humhub\modules\reputation\Events', 'onSpaceMembershipDelete']],
27 | ['class' => Space::className(), 'event' => Space::EVENT_BEFORE_DELETE, 'callback' => ['humhub\modules\reputation\Events', 'onSpaceDelete']],
28 | ['class' => Sidebar::className(), 'event' => Sidebar::EVENT_RUN, 'callback' => ['humhub\modules\reputation\Events', 'onSpaceSidebar']],
29 | ['class' => ProfileMenu::className(), 'event' => ProfileMenu::EVENT_INIT, 'callback' => ['humhub\modules\reputation\Events', 'onProfileMenuInit']],
30 | ['class' => DefaultMenu::className(), 'event' => DefaultMenu::EVENT_INIT, 'callback' => ['humhub\modules\reputation\Events', 'onSpaceAdminMenuWidgetInit']],
31 | ['class' => Menu::className(), 'event' => Menu::EVENT_INIT, 'callback' => ['humhub\modules\reputation\Events', 'onSpaceMenuInit']],
32 | ],
33 | ];
34 | ?>
--------------------------------------------------------------------------------
/Module.php:
--------------------------------------------------------------------------------
1 | createUrl('/reputation/space/settings');
54 | }
55 | }
56 |
57 | /**
58 | * @inheritdoc
59 | */
60 | public function disableContentContainer(ContentContainerActiveRecord $container) {
61 | $this->settings->contentContainer($container)->deleteAll();
62 | foreach (ReputationUser::findAll(['wall_id' => $container->wall_id]) as $reputationSpace) {
63 | $reputationSpace->delete();
64 | }
65 | }
66 |
67 | /**
68 | * @inheritdoc
69 | */
70 | public function getContentContainerName(ContentContainerActiveRecord $container) {
71 | return Yii::t('ReputationModule.base', 'Reputation');
72 | }
73 |
74 | /**
75 | * @inheritdoc
76 | */
77 | public function getContentContainerDescription(ContentContainerActiveRecord $container) {
78 | return Yii::t('ReputationModule.base', 'This Module Integrates A Reputation System Into HumHub. It Works With HumHub 1.1.x +.');
79 | }
80 |
81 | }
82 |
--------------------------------------------------------------------------------
/views/space/stats.php:
--------------------------------------------------------------------------------
1 |
10 |
11 |
12 | Space member reputation'); ?>
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
25 |
26 |
27 |
28 |
29 |
30 |
31 | $reputation->user_id]);
33 | if ($user == null)continue;
34 | ?>
35 |
36 |
37 |
38 |
42 |
43 |
44 |
45 | getDisplayName(), $user->getUrl()); ?>
46 |
47 |
48 |
49 |
50 |
51 | value);
54 | } else {
55 | echo Html::encode($reputation->value) . '%';
56 | }
57 | ?>
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
68 |
69 |
--------------------------------------------------------------------------------
/models/SpaceSettings.php:
--------------------------------------------------------------------------------
1 | 1),
37 | array('create_content', 'required'),
38 | array('create_content', 'number', 'min' => 0),
39 | array('smb_likes_content', 'required'),
40 | array('smb_likes_content', 'number', 'min' => 0),
41 | array('smb_favorites_content', 'required'),
42 | array('smb_favorites_content', 'number', 'min' => 0),
43 | array('smb_comments_content', 'required'),
44 | array('smb_comments_content', 'number', 'min' => 0),
45 | array('daily_limit', 'required'),
46 | array('smb_comments_content', 'number', 'min' => 0),
47 | array('decrease_weighting', 'required'),
48 | array('cron_job', 'required'),
49 | array('lambda_long', 'required'),
50 | array('lambda_long', 'double'),
51 | array('lambda_short', 'required'),
52 | array('lambda_short', 'double'),
53 | array('ranking_new_period', 'required'),
54 | array('ranking_new_period', 'number', 'min' => 1)
55 | );
56 | }
57 |
58 | /**
59 | * Declares customized attribute labels.
60 | * If not declared here, an attribute would have a label that is
61 | * the same as its name with the first letter in upper case.
62 | */
63 | public function attributeLabels() {
64 | return array(
65 | 'functions' => Yii::t('ReputationModule.forms_adminController_settings', 'Function'),
66 | 'logarithm_base' => Yii::t('ReputationModule.forms_adminController_settings', 'Logarithm base'),
67 | 'create_content' => Yii::t('ReputationModule.forms_adminController_settings', 'Creating posts or comments'),
68 | 'smb_likes_content' => Yii::t('ReputationModule.forms_adminController_settings', 'Somebody liked the post'),
69 | 'smb_favorites_content' => Yii::t('ReputationModule.forms_adminController_settings', 'Somebody marked the post as favorite'),
70 | 'smb_comments_content' => Yii::t('ReputationModule.forms_adminController_settings', 'Somebody comments the post'),
71 | 'daily_limit' => Yii::t('ReputationModule.forms_adminController_settings', 'Daily limit for Users'),
72 | 'decrease_weighting' => Yii::t('ReputationModule.forms_adminController_settings', 'Decrease weighting per post'),
73 | 'cron_job' => Yii::t('ReputationModule.forms_adminController_settings', 'Update reputation data on hourly cron job'),
74 | 'lambda_long' => Yii::t('ReputationModule.forms_adminController_settings', 'Exponential decrease for Ranking Hot'),
75 | 'lambda_short' => Yii::t('ReputationModule.forms_adminController_settings', 'Exponential decrease for Ranking Rising'),
76 | 'ranking_new_period' => Yii::t('ReputationModule.forms_adminController_settings', 'Time in hours for the "NEW" filter to show Content'),
77 | );
78 | }
79 |
80 | }
81 |
--------------------------------------------------------------------------------
/components/StreamAction.php:
--------------------------------------------------------------------------------
1 | getRequest()->get('sort', self::MODE_HOT);
47 | if ($sort === self::MODE_HOT) {
48 | $this->sort = $sort;
49 | } elseif ($sort === self::MODE_NEW) {
50 | $this->sort = $sort;
51 | } elseif ($sort === self::MODE_TOP) {
52 | $this->sort = $sort;
53 | } elseif ($sort === self::MODE_RISING) {
54 | $this->sort = $sort;
55 | }
56 | $this->setupCriteria();
57 | }
58 |
59 | public function setupCriteria() {
60 | parent::setupCriteria();
61 | /**
62 | * Setup Sorting
63 | */
64 | if ($this->sort === self::MODE_HOT) {
65 | $this->activeQuery->leftJoin('reputation_content AS rc', 'rc.content_id = wall_entry.content_id');
66 | if ($this->from != "") {
67 | $params = array(':from' => $this->from);
68 | $this->activeQuery->andWhere('wall_entry.content_id = :from', $params);
69 | }
70 | $this->activeQuery->orderBy('rc.score_long DESC');
71 | } elseif ($this->sort === self::MODE_NEW) {
72 | $this->activeQuery->leftJoin('reputation_content AS rc', 'rc.content_id = wall_entry.content_id');
73 | if ($this->from != "") {
74 | $params = array(':from' => $this->from);
75 | $this->activeQuery->andWhere('wall_entry.content_id = :from', $params);
76 | }
77 | $this->activeQuery->andWhere("content.created_at >= DATE_SUB(NOW(), INTERVAL :newRanking HOUR)", [':newRanking' => $this->spaceSettings['ranking_new_period']]);
78 | $this->activeQuery->orderBy('rc.score DESC');
79 | } elseif ($this->sort === self::MODE_TOP) {
80 | $this->activeQuery->leftJoin('reputation_content AS rc', 'rc.content_id = wall_entry.content_id');
81 | if ($this->from != "") {
82 | $params = array(':from' => $this->from);
83 | $this->activeQuery->andWhere('wall_entry.content_id = :from', $params);
84 | }
85 | $this->activeQuery->orderBy('rc.score DESC');
86 | } elseif ($this->sort === self::MODE_RISING) {
87 | $this->activeQuery->leftJoin('reputation_content AS rc', 'rc.content_id = wall_entry.content_id');
88 | if ($this->from != "") {
89 | $params = array(':from' => $this->from);
90 | $this->activeQuery->andWhere('wall_entry.content_id = :from', $params);
91 | }
92 | $this->activeQuery->orderBy('rc.score_short DESC');
93 | }
94 | }
95 |
96 | }
97 |
98 | ?>
--------------------------------------------------------------------------------
/controllers/AdminController.php:
--------------------------------------------------------------------------------
1 | no write access / 1 -> create links and edit own links / 2 -> full write access. * */
24 | // public $accessLevel = 0;
25 | //
26 | // /**
27 | // * Automatically loads the underlying contentContainer (User/Space) by using
28 | // * the uguid/sguid request parameter
29 | // *
30 | // * @return boolean
31 | // */
32 | // public function init() {
33 | // $retVal = parent::init();
34 | // $this->accessLevel = $this->getAccessLevel();
35 | // return $retVal;
36 | // }
37 | //
38 | // /**
39 | // * @return array action filters
40 | // */
41 | // public function filters() {
42 | // return array(
43 | // 'accessControl', // perform access control for CRUD operations
44 | // );
45 | // }
46 | //
47 | // /**
48 | // * Get the acces level to the linklist of the currently logged in user.
49 | // * @return number 0 -> no write access / 1 -> create links and edit own links / 2 -> full write access
50 | // */
51 | // private function getAccessLevel() {
52 | // if ($this->contentContainer instanceof User) {
53 | // return $this->contentContainer->id == Yii::$app->user->id ? 2 : 0;
54 | // } else if ($this->contentContainer instanceof Space) {
55 | // return $this->contentContainer->isAdmin(Yii::$app->user->id) ? 2 : 1;
56 | // }
57 | // }
58 |
59 | /*
60 | * Allow only space admins to see configuration
61 | */
62 | public function beforeAction($action) {
63 | if (!$this->contentContainer->permissionManager->can(new \humhub\modules\content\permissions\ManageContent())) {
64 | throw new HttpException(400, 'Access denied!');
65 | }
66 | return parent::beforeAction($action);
67 | }
68 |
69 | /*
70 | * Initialize user reputation overview
71 | *
72 | * force update can be triggered by appending &forceUpdate at the end of the url
73 | * otherwise cache is used
74 | */
75 |
76 | public function actionIndex() {
77 | $forceUpdate = false;
78 | if (Yii::$app->request->get('forceUpdate') === 1) {
79 | $forceUpdate = true;
80 | }
81 | $space = $this->contentContainer;
82 | ReputationUser::updateUserReputation($space, $forceUpdate);
83 | $params = [':spaceId' => $space->id];
84 | $query = ReputationUser::find();
85 | $query->where('space_id=:spaceId', $params);
86 | $query->orderBy('reputation_user.value DESC');
87 |
88 | $countQuery = clone $query;
89 | $itemCount = $countQuery->count();
90 | $pagination = new \yii\data\Pagination(['totalCount' => $itemCount, 'pageSize' => 10]);
91 | $query->offset($pagination->offset)->limit($pagination->limit);
92 |
93 | $reputations = $query->all();
94 |
95 | $module = Yii::$app->getModule('reputation');
96 | $function = $module->settings->space()->get('functions', ReputationBase::DEFAULT_FUNCTION);
97 |
98 | $lastUpdatedBefore = $this->GetLastUpdateTimeInMinutes($reputations);
99 |
100 | return $this->render('index', array(
101 | 'function' => $function,
102 | 'space' => $space,
103 | 'reputations' => $reputations,
104 | 'pagination' => $pagination,
105 | 'lastUpdatedBefore' => $lastUpdatedBefore,
106 | ));
107 | }
108 |
109 | /**
110 | * Get time in minutes since last update occurred
111 | *
112 | * @param $criteria
113 | * @return string: The time elapsed since the last update
114 | */
115 | private function GetLastUpdateTimeInMinutes($criteria) {
116 | $now = new \DateTime();
117 | $lastUpdateTime = new \DateTime($criteria[0]->updated_at);
118 | $lastUpdatedBefore = $lastUpdateTime->diff($now)->format('%i');
119 |
120 | return $lastUpdatedBefore;
121 | }
122 |
123 | }
124 |
--------------------------------------------------------------------------------
/controllers/ProfileController.php:
--------------------------------------------------------------------------------
1 | no write access / 1 -> create links and edit own links / 2 -> full write access. * */
18 | // public $accessLevel = 0;
19 | //
20 | // /**
21 | // * Automatically loads the underlying contentContainer (User/Space) by using
22 | // * the uguid/sguid request parameter
23 | // *
24 | // * @return boolean
25 | // */
26 | // public function init() {
27 | // $retVal = parent::init();
28 | // $this->accessLevel = $this->getAccessLevel();
29 | // return $retVal;
30 | // }
31 | //
32 | // /**
33 | // * @return array action filters
34 | // */
35 | // public function filters() {
36 | // return array(
37 | // 'accessControl', // perform access control for CRUD operations
38 | // );
39 | // }
40 | //
41 | // /**
42 | // * Get the acces level to the linklist of the currently logged in user.
43 | // * @return number 0 -> no write access / 1 -> create links and edit own links / 2 -> full write access
44 | // */
45 | // private function getAccessLevel() {
46 | // if ($this->contentContainer instanceof User) {
47 | // return $this->contentContainer->id == Yii::$app->user->id ? 2 : 0;
48 | // } else if ($this->contentContainer instanceof Space) {
49 | // return $this->contentContainer->isAdmin(Yii::$app->user->id) ? 2 : 1;
50 | // }
51 | // }
52 | //
53 | // /**
54 | // * Specifies the access control rules.
55 | // * This method is used by the 'accessControl' filter.
56 | // * @return array access control rules
57 | // */
58 | // public function accessRules() {
59 | // return array(
60 | // array('allow', // allow authenticated user to perform 'create' and 'update' actions
61 | // 'users' => array('@'),
62 | // ),
63 | // array('deny', // deny all users
64 | // 'users' => array('*'),
65 | // ),
66 | // );
67 | // }
68 |
69 | /**
70 | * Action that renders the list view.
71 | * @see views/profile/config.php
72 | */
73 | public function actionConfig() {
74 |
75 | if (isset($_POST['reputationUsers'])) {
76 | $user = User::findIdentityByAccessToken(Yii::$app->getRequest()->get('uguid'));
77 | $userSpaces = Membership::GetUserSpaces($user->id);
78 | foreach ($userSpaces as $space) {
79 | $getPost = Yii::$app->getRequest()->post('reputationUser_' . $space->id);
80 | if (isset($getPost)) {
81 | $userSettings = $getPost;
82 | $params = [':spaceId' => $space->id, ':userId' => $user->id];
83 | $query = ReputationUser::find();
84 | $query->where('space_id=:spaceId AND user_id=:userId', $params);
85 | $result = $query->one();
86 | if ($result != null) {
87 | $result->visibility = (isset($userSettings['visibility']) && $userSettings['visibility'] == 1) ? 1 : 0;
88 | $result->save();
89 | }
90 | }
91 | }
92 | }
93 | // TODO was ist das?!
94 | //Yii::$app->user->setFlash('data-saved', Yii::t('SpaceModule.controllers_AdminController', 'Saved'));
95 |
96 | $user = User::findIdentityByAccessToken(Yii::$app->getRequest()->get('uguid'));
97 | $params = [':userId' => $user->id];
98 | $query = ReputationUser::find();
99 | $query->where('user_id=:userId', $params);
100 | $query->leftJoin('space', 'space.id = reputation_user.space_id');
101 | $query->orderBy('reputation_user.space_id ASC');
102 | $result = $query->all();
103 |
104 | $itemCount = count($result);
105 |
106 | $pagination = new \yii\data\Pagination(['totalCount' => $itemCount]);
107 | return $this->render('config', array(
108 | 'contentContainer' => $this->contentContainer,
109 | 'user' => $user,
110 | 'reputations' => $result,
111 | 'pagination' => $pagination,
112 | ));
113 | }
114 |
115 | }
116 |
--------------------------------------------------------------------------------
/widgets/views/stream.php:
--------------------------------------------------------------------------------
1 | registerJs('var streamUrl="' . $streamUrl . '"', View::POS_BEGIN);
7 |
8 | $jsLoadWall = "s = new Stream('#wallStream');\n";
9 | $wallEntryId = (int) Yii::$app->request->getQueryParam('wallEntryId');
10 | if ($wallEntryId != "") {
11 | $jsLoadWall .= "s.showItem(" . $wallEntryId . ");\n";
12 | } else {
13 | $jsLoadWall .= "s.showStream();\n";
14 | }
15 | $jsLoadWall .= "currentStream = s;\n";
16 | $jsLoadWall .= "mainStream = s;\n";
17 | $jsLoadWall .= "$('#btn-load-more').click(function() { currentStream.loadMore(); })\n";
18 | $this->registerJs($jsLoadWall, View::POS_READY);
19 |
20 | if (Yii::$app->settings->get('horImageScrollOnMobile'))
21 | $this->registerJs(new \yii\web\JsExpression("
22 | if (/Android|webOS|iPhone|iPad|iPod|BlackBerry|BB|PlayBook|IEMobile|Windows Phone|Kindle|Silk|Opera Mini/i.test(navigator.userAgent)) {
23 | $('#wallStream').addClass('mobile');
24 | }"), View::POS_READY);
25 |
26 | $this->registerJsVar('defaultStreamSort', 'h');
27 | ?>
28 |
29 | context->showFilters) { ?>
30 |
31 |
32 |
34 |
41 |
42 |
43 |
44 |
45 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 | 'streamLoader']); ?>
70 |
71 |
72 |
73 |
74 |
75 |
76 | context->messageStreamEmpty; ?>
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 | context->messageStreamEmptyWithFilters; ?>
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
--------------------------------------------------------------------------------
/widgets/views/spaceUserReputationWidget.php:
--------------------------------------------------------------------------------
1 |
11 |
12 |
13 | 'space-members-panel']); ?>
14 |
Space User Reputation'); ?>
15 |
16 | 0) : ?>
17 |
66 |
67 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 | Yii::$app->user->guid), array('class' => 'btn btn-default btn-sm')); ?>
84 |
85 |
86 |
87 |
88 |
--------------------------------------------------------------------------------
/controllers/SpaceController.php:
--------------------------------------------------------------------------------
1 | contentContainer);
27 | return array(
28 | 'stream' => array(
29 | 'class' => \humhub\modules\reputation\components\StreamAction::className(),
30 | 'sort' => \humhub\modules\reputation\components\StreamAction::MODE_HOT,
31 | 'contentContainer' => $this->contentContainer,
32 | 'spaceSettings' => $spaceSettings
33 | ),
34 | );
35 | }
36 |
37 | /**
38 | * Shows the reputation_content space
39 | */
40 | public function actionIndex() {
41 | $forceUpdate = false;
42 | if (isset($_GET['forceUpdate'])) {
43 | $forceUpdate = true;
44 | }
45 |
46 | $space = $this->contentContainer;
47 | $canCreatePosts = $space->permissionManager->can(new \humhub\modules\post\permissions\CreatePost());
48 | $isMember = $space->isMember();
49 |
50 | ReputationContent::updateContentReputation($space, $forceUpdate);
51 | return $this->render('index', [
52 | 'space' => $space,
53 | 'canCreatePosts' => $canCreatePosts,
54 | 'isMember' => $isMember
55 | ]);
56 | }
57 |
58 | /**
59 | * Initialize settings view
60 | * Allows the user to set a bunch of parameters for reputation settings inside this space
61 | */
62 | public function actionSettings() {
63 | if (!$this->contentContainer->permissionManager->can(new \humhub\modules\content\permissions\ManageContent())) {
64 | throw new HttpException(400, 'Access denied!');
65 | }
66 | $space = $this->getSpace();
67 | $module = Yii::$app->getModule('reputation');
68 | $form = new SpaceSettings();
69 |
70 | if ($form->load(Yii::$app->request->post()) && $form->validate()) {
71 | $form->functions = $module->settings->space()->set('functions', $form->functions);
72 | $form->logarithm_base = $module->settings->space()->set('logarithm_base', $form->logarithm_base);
73 | $form->create_content = $module->settings->space()->set('create_content', $form->create_content);
74 | $form->smb_likes_content = $module->settings->space()->set('smb_likes_content', $form->smb_likes_content);
75 | $form->smb_favorites_content = $module->settings->space()->set('smb_favorites_content', $form->smb_favorites_content);
76 | $form->smb_comments_content = $module->settings->space()->set('smb_comments_content', $form->smb_comments_content);
77 | $form->daily_limit = $module->settings->space()->set('daily_limit', $form->daily_limit);
78 | $form->decrease_weighting = $module->settings->space()->set('decrease_weighting', $form->decrease_weighting);
79 | $form->cron_job = $module->settings->space()->set('cron_job', $form->cron_job);
80 | $form->ranking_new_period = $module->settings->space()->set('ranking_new_period', $form->ranking_new_period);
81 | $form->lambda_short = $module->settings->space()->set('lambda_short', $form->lambda_short);
82 | $form->lambda_long = $module->settings->space()->set('lambda_long', $form->lambda_long);
83 |
84 | ReputationContent::updateContentReputation($space, true);
85 | ReputationUser::updateUserReputation($space, true);
86 |
87 | $this->redirect(['/reputation/space/settings', 'sguid' => $space->guid]);
88 | } else {
89 | $spaceSettings = ReputationBase::getSpaceSettings($space);
90 | $form->functions = $spaceSettings['functions'];
91 | $form->logarithm_base = $spaceSettings['logarithm_base'];
92 | $form->create_content = $spaceSettings['create_content'];
93 | $form->smb_likes_content = $spaceSettings['smb_likes_content'];
94 | $form->smb_favorites_content = $spaceSettings['smb_favorites_content'];
95 | $form->smb_comments_content = $spaceSettings['smb_comments_content'];
96 | $form->daily_limit = $spaceSettings['daily_limit'];
97 | $form->decrease_weighting = $spaceSettings['decrease_weighting'];
98 | $form->cron_job = $spaceSettings['cron_job'];
99 | $form->ranking_new_period = $spaceSettings['ranking_new_period'];
100 | $form->lambda_short = $spaceSettings['lambda_short'];
101 | $form->lambda_long = $spaceSettings['lambda_long'];
102 | }
103 | return $this->render('settings', array('model' => $form, 'space' => $space));
104 | }
105 |
106 | public function actionStats() {
107 | $space = $this->getSpace();
108 | ReputationUser::updateUserReputation($space);
109 | $params = [':spaceId' => $space->id];
110 | $reputations = ReputationUser::find()->where('space_id=:spaceId AND visibility = 1', $params)->all();
111 | $itemCount = count($reputations);
112 | $pagination = new \yii\data\Pagination(['totalCount' => $itemCount]);
113 | $module = Yii::$app->getModule('reputation');
114 | $function = $module->settings->space()->get('functions', ReputationBase::DEFAULT_FUNCTION);
115 | return $this->render('stats', array(
116 | 'function' => $function,
117 | 'space' => $space,
118 | 'reputations' => $reputations,
119 | 'pagination' => $pagination,
120 | ));
121 | }
122 |
123 | }
124 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | ## Reputation module for HumHub [working on 1.1.x (Yii2)]
2 | ### Under Development - please report issues!
3 |
4 | This module integrates a reputation system into HumHub.
5 |
6 | ##About
7 | __Author:__ Anton Kurnitzky / Philipp Horna (Port to Humhub 1.1.x)
8 |
9 | This module was developed as part of my master thesis at the [Technische Hochschule Nürnberg](http://www.th-nuernberg.eu).
10 | It's default settings are designed to work for a social network in an educational context. By customizing the settings you can probably use this in any other context too.
11 | ##Installation
12 | * Copy the module to your HumHub module folder (.../humhub/protected/modules/reputation)
13 | * The folder name must be "reputation"
14 | * Activate the module on the HumHub admin page. Set it as default for space to activate it in all spaces. You should set is as default for user profiles so users can see their own reputation.
15 | * If not set to default for spaces, activate the module on each space you want to get an entry in the space navigation menu
16 | * If not set to default for user profiles, a user has to manually activate this module on their profile page.
17 |
18 | ##Usage
19 | ### Everybody
20 | Inside the space menu you will see a new menu called "Hot". This menu provides four new sorting options that are possible trough the reputation system. The ranking of the posts depends on the sorting option and your module configuration.
21 | 
22 |
23 | * Hot: The default sorting option. This option prioritizes posts that are younger than on week and have a high number of likes, favorites and comments.
24 | * Top: This option shows you the best rated posts at the top.
25 | * New: Show posts created in the last 36 hours. Sorted by best rating.
26 | * Rising: Similar to hot. But it prioritizes posts that are younger than 24 hours.
27 |
28 | ### Space-Admins
29 | As Space-Admin you will get a new menu item called "User Reputation". Inside this menu you will see a list of all space members and their respective reputation score.
30 | 
31 | At the bottom you have three actions:
32 |
33 | * Update: Refresh the data
34 | * Configuration: Opens the module configuration for this space. [More info](#Configuration).
35 |
36 | ### Users
37 | Inside your Profile menu you will see a new menu "Reputation".
38 | 
39 | Here you see all the spaces you're a member of and that have the reputation module enabled.
40 | You can see your reputation score and the time this score was last updated.
41 | To share your reputation with other users you can enable this per space. If you enable this every other user inside the HumHub installation can see your reputation. This is an explicit opt-in option. To set this to enabled for all users you have to set the visible column in the table reputation_user to 1.
42 |
43 | ##Configuration
44 | 
45 |
46 | * Function: Use a linear function that just show the score the user reached or use a logarithmic function. The logarithmic function is a good motivator because you reach a high score with little effort. For pure comparision the linear setting should be fine. **Default** is Logarithmic.
47 | * Base: This is only visible if you use the logarithmic function. Set the base for the logarithmic function. When you set it to 1000 a user needs 1000 points to get a value of 100%. But he only needs 32 points to get above 50%. **Default** is 100.
48 | * Creating posts or comments: How much points should a user get for creating a post or comment. **Default** is 1.
49 | * Somebody liked the post: How much points should the post creator get when somebody likes the post. The user who clicks like doesn't get any points. **Default** is 2.
50 | * Somebody marked the post as favorite: Same as "Somebody liked the post". **Default** is 2.
51 | * Somebody comments the post: How much points should the creator of the original post get if somebody (other) posts a comment. The posts of the comment also gets points according to the setting "Creating posts or comments". **Default** is 3.
52 | * Daily limit: Set a limit of points a user can reach on a single day. Set this to zero if you don't want to use a daily limit. **Default** is 15.
53 | * Decrease weighting: This setting decreases the weighting of additional likes, comments, favorites on a post. It divides any additional like by the count of likes. So for example 2 likes with the "Somebody liked the post" setting set to 2 generates only 3 points for the post creator. 2 + 2/2. 5 likes is 2 + 2/2 + 2/3 + 2/4 + 2/5 = 4.56. The exact formula is:  The purpose of this setting is to make it really hard to get a high reputation score from just one post. **Default** is Yes.
54 |
55 | ##Technical
56 | ### Update interval
57 | This module uses the [hourly cron job of HumHub](https://www.humhub.org/docs/guide-admin-installation.html#enable-cron-jobs). So make sure you properly configured the cron job on your system. If you want more up to date data you should change the cron schedule.
58 |
59 | It also uses [Yii Caching](http://www.yiiframework.com/doc/guide/1.1/en/caching.overview) to improve loading times. The cache is set to 15minutes. So if you open a view (e.g. "User Reptuation") it will use cached data if it's newer than 15 minutes. Otherwise it will refresh the data before displaying the view.
60 | If you want to see more up to date data you can always click on the "Update" button.
61 |
62 | That means you should never see data that's older than 15 minutes.
63 |
64 | ### Reputation sources
65 | Posts, Likes, Favorites and comments are used as reputation sources. Therefore this module uses the associated database tables (content, post, like, comment, favorite, etc.).
66 |
67 | ### Calculation
68 | The reputation calculation is performed dynamically. This means that on every calculation everything will be reconsidered.
69 | That gives you the advantage that you can change the module settings any time and the recalculated values will take the new settings into account. So you could just test a bunch of different settings and see their outcome.
70 |
--------------------------------------------------------------------------------
/views/admin/index.php:
--------------------------------------------------------------------------------
1 |
12 |
13 |
14 |
15 | Space member reputation'); ?>
16 |
17 | = DefaultMenu::widget(['space' => $space]); ?>
18 |
19 |
20 |
21 | ' . $lastUpdatedBefore . '' ?>
22 |
23 |
' ?>
24 |
25 |
26 | 0) : ?>
27 |
88 |
89 |
97 |
98 |
99 |
102 |
103 |
104 | $space->guid, 'forceUpdate' => 1), array('class' => 'btn btn-primary')); ?>
105 |
106 |
107 | $space->guid), array('class' => 'btn btn-warning')); ?>
108 |
109 |
110 |
111 |
--------------------------------------------------------------------------------
/views/profile/config.php:
--------------------------------------------------------------------------------
1 |
10 |
11 |
12 |
13 | Space reputation'); ?>
14 |
15 |
16 |
17 |
18 |
19 | user->id != $user->id) echo Yii::t('ReputationModule.views_profileReputation_show', 'You can only see reputation the user shares.'); ?>
20 |
21 |
22 |
23 | user->id === $user->id)): ?>
24 | ['config', 'uguid' => $user->guid],
27 | 'method' => 'post',
28 | 'id' => 'configure-form',
29 | 'enableAjaxValidation' => false,
30 | ]);
31 | ?>
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 | user->id == $user->id): ?>
40 |
41 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 | $reputation->space_id]);
53 |
54 | if ($space == null || ($reputation->visibility == 0 && Yii::$app->user->id != $reputation->user_id))
55 | continue;
56 |
57 | // Hidden input to get users on this page
58 | echo Html::hiddenInput("reputationUsers[" . $reputation->space_id . "]", $reputation->space_id);
59 |
60 | // Hidden field to get users on this page
61 | echo Html::hiddenInput('reputationUser_' . $reputation->space_id . "[placeholder]", 1);
62 |
63 | $module = Yii::$app->getModule('reputation');
64 | $setting_function = $module->settings->contentContainer($contentContainer)->get('functions', ReputationBase::DEFAULT_FUNCTION);
65 | ?>
66 |
67 |
68 |
69 | $space,
73 | 'width' => 32,
74 | 'htmlOptions' => [
75 | 'class' => 'current-space-image',
76 | ],
77 | 'link' => 'true',
78 | ]);
79 | ?>
80 |
81 |
82 | getDisplayName(), $space->getUrl()); ?>
83 |
84 |
85 |
86 |
87 |
88 | value) . ' ';
91 | } else {
92 | echo Html::encode($reputation->value) . '%';
93 | }
94 | ?>
95 |
96 |
97 | user->id == $reputation->user_id): ?>
98 |
99 |
100 |
101 |
102 | space_id . "[visibility]", $reputation->visibility, array('class' => 'visibility',
105 | 'id' => "chk_visibility_" . $reputation->space_id,
106 | 'data-view' => 'slider')
107 | );
108 | ?>
109 |
110 |
111 |
112 |
113 |
114 | updated_at; ?>
115 |
116 |
117 |
118 |
119 |
120 |
121 |
122 |
123 |
126 |
127 | user->id == $user->id)): ?>
128 |
129 | 'btn btn-primary')); ?>
130 |
131 |
132 |
133 |
134 |
135 |
136 |
137 |
--------------------------------------------------------------------------------
/models/ReputationContent.php:
--------------------------------------------------------------------------------
1 | true),
50 | array('created_at, updated_at', 'safe'),
51 | );
52 | }
53 |
54 | /**
55 | * @return array relational rules.
56 | */
57 | public function relations() {
58 | return array(
59 | 'content' => array(self::BELONGS_TO, 'Content', 'content_id'),
60 | );
61 | }
62 |
63 | /**
64 | * @return array customized attribute labels (name=>label)
65 | */
66 | public function attributeLabels() {
67 | return array(
68 | 'id' => 'ID',
69 | 'score' => 'Score',
70 | 'score_short' => 'Score short',
71 | 'score_long' => 'Score long',
72 | 'content_id' => 'Content',
73 | 'created_at' => 'Created At',
74 | 'created_by' => 'Created By',
75 | 'updated_at' => 'Updated At',
76 | 'updated_by' => 'Updated By',
77 | );
78 | }
79 |
80 | /**
81 | * Recalculate content reputation for a space
82 | *
83 | * @param $space : The space where the content should be updated
84 | * @param bool $forceUpdate : Ignore cache
85 | */
86 | public function updateContentReputation($container, $forceUpdate = false) {
87 | $spaceSettings = ReputationBase::getSpaceSettings($container);
88 | $spaceContent = ReputationBase::getContentFromSpace($container);
89 | $lambda_short = $spaceSettings['lambda_short'];
90 | $lambda_long = $spaceSettings['lambda_long'];
91 |
92 | foreach ($spaceContent as $content) {
93 |
94 | $cacheId = 'reputation_space_content' . '_' . $container->wall_id . '_' . $content->id;
95 | $contentReputation = Yii::$app->cache->get($cacheId);
96 |
97 | if ($contentReputation === false || $forceUpdate === true) {
98 | $contentReputation = [];
99 | // get all reputation_content objects from this space
100 | $params = array('content_id' => $content->id);
101 | $contentReputation = ReputationContent::findOne($params);
102 | if ($contentReputation == null) {
103 | // Create new reputation_content entry
104 | $contentReputation = new ReputationContent();
105 | $contentReputation->content_id = $content->id;
106 | $contentReputation->created_by = $content->created_by;
107 | }
108 | $score = ReputationContent::calculateContentReputationScore($content, $container, $forceUpdate);
109 | $contentReputation->score = $score;
110 | $timePassed = ReputationContent::getTimeInHoursSinceContentCreation($content->created_at);
111 | $contentReputation->score_long = ReputationContent::getDecayedScore($score, $timePassed, $lambda_long);
112 | $contentReputation->score_short = ReputationContent::getDecayedScore($score, $timePassed, $lambda_short);
113 | $contentReputation->updated_at = date('Y-m-d H:i:s');
114 | $contentReputation->updated_by = $content->updated_by;
115 | $contentReputation->save(false);
116 |
117 | Yii::$app->cache->set($cacheId, $contentReputation, ReputationBase::CACHE_TIME_SECONDS);
118 | }
119 | }
120 | }
121 |
122 | /**
123 | * Returns the static model of the specified AR class.
124 | * Please note that you should have this exact method in all your CActiveRecord descendants!
125 | * @param string $className active record class name.
126 | * @return ReputationContent the static model class
127 | *
128 | public static function model($className = __CLASS__)
129 | {
130 | return parent::model($className);
131 | }
132 | *
133 | */
134 | /*
135 | * Calculate the reputation score for all content objects inside this space
136 | * Use the count of likes, favorites and comments and the reputation settings to calculate this
137 | *
138 | * @param $content
139 | * @param $space
140 | */
141 | public function calculateContentReputationScore($content, $container, $forceUpdate) {
142 | $spaceSettings = ReputationBase::getSpaceSettings($container);
143 | $cacheId = 'likes_earned_cache_' . $content->id;
144 | $likes = ReputationBase::getLikesFromContent($content, $content->created_by, $cacheId, $forceUpdate);
145 | if ($container->isModuleEnabled('favorite')) {
146 | $scoreCount = 1;
147 | // now count the favorites this content earned from other users
148 | $cacheId = 'favorites_earned_cache_' . $content->id;
149 | $favorites = ReputationBase::getFavoritesFromContent($content, $content->created_by, $cacheId, $forceUpdate);
150 | } else {
151 | $favorites = array();
152 | }
153 | $cacheId = 'comments_earned_cache_' . $content->id;
154 | $comments = ReputationBase::getCommentsFromContent($content, $content->created_by, $cacheId, true, $forceUpdate);
155 | return (count($likes) * $spaceSettings['smb_likes_content'] + count($favorites) * $spaceSettings['smb_favorites_content'] + count($comments) * $spaceSettings['smb_comments_content']);
156 | }
157 |
158 | /**
159 | * Calculate time in hours since the content was created
160 | *
161 | * @param $createdAt : The creation time of the content object
162 | * @return int: Time in hours since content was created
163 | */
164 | private function getTimeInHoursSinceContentCreation($createdAt) {
165 | $now = new DateTime();
166 | $createdTime = new DateTime($createdAt);
167 | $timeSinceCreation = round(($now->getTimestamp() - $createdTime->getTimestamp()) / 3600, 2, PHP_ROUND_HALF_UP);
168 |
169 | // do not allow zero because this value is used as divisor later
170 | if ($timeSinceCreation == 0) {
171 | $timeSinceCreation = 1;
172 | }
173 |
174 | return $timeSinceCreation;
175 | }
176 |
177 | /**
178 | * Return the value of a decayed score, that is,
179 | * a value that decreases over time.
180 | * The formula used for the decay is exp(-lambda * t^2),
181 | * where lambda is damping factor and t is the age
182 | * of the object in seconds.
183 | * If lambda is 0, no decay takes place, whatsoever.
184 | *
185 | * @param int /float Initial score.
186 | * @param int Time in hours that has passed since the score was set.
187 | * @param float Damping factor.
188 | * @return float Decayed score.
189 | */
190 | public function getDecayedScore($score, $age, $lambda = 0) {
191 | // Actual calculation: exp(-lambda * t^2)
192 | return ($score + 1) * exp(-$lambda * $age * $age);
193 | }
194 |
195 | }
196 |
--------------------------------------------------------------------------------
/Events.php:
--------------------------------------------------------------------------------
1 | sender;
27 | $spaces = Space::find()->all();
28 | $count_spaces = count($spaces);
29 | $processed = 0;
30 | Console::startProgress($processed, $count_spaces, '[Module] calculate REPUTATION for Spaces...', false);
31 | foreach ($spaces as $space) {
32 | if ($space->isModuleEnabled('reputation')) {
33 | $cronJobEnabled = ReputationBase::getSpaceSettings($space);
34 | if ($cronJobEnabled['cron_job'] = 1) {
35 | self::onSpaceEnabledAsDefault($space);
36 | ReputationUser::updateUserReputation($space, true);
37 | ReputationContent::updateContentReputation($space, true);
38 | Console::updateProgress(++$processed, $count_spaces);
39 | }
40 | }
41 | }
42 | Console::endProgress(true);
43 | $controller->stdout('done - ' . $processed . ' spaces checked.' . PHP_EOL, Console::FG_GREEN);
44 |
45 | $users = User::find()->all();
46 | $count_users = count($spaces);
47 | Console::startProgress($processed, $count_users, '[Module] calculate REPUTATION for Users...', false);
48 | foreach ($users as $user) {
49 | if ($user->isModuleEnabled('reputation')) {
50 | self::onUserEnabledAsDefault($user);
51 | Console::updateProgress(++$processed, $count_users);
52 | }
53 | }
54 | Console::endProgress(true);
55 | $controller->stdout('done - ' . $processed . ' spaces checked.' . PHP_EOL, Console::FG_GREEN);
56 | }
57 |
58 | /**
59 | * Set Reputation Module when it is enabled as default on the Space
60 | *
61 | * @param $space Object
62 | */
63 | public static function onSpaceEnabledAsDefault($space) {
64 | $moduleEnabled = \humhub\modules\space\models\Module::findOne(['space_id' => $space->id, 'module_id' => 'reputation']);
65 | $moduleAsDefaultOn = \humhub\modules\space\models\Module::find()->where(['space_id' => 0, 'module_id' => 'reputation', 'state' => 1])->orWhere(['space_id' => 0, 'module_id' => 'reputation', 'state' => 2])->one();
66 | if ($moduleEnabled === NULL && $moduleAsDefaultOn != NULL) {
67 | $enableModule = new \humhub\modules\space\models\Module();
68 | $enableModule->module_id = 'reputation';
69 | $enableModule->space_id = $space->id;
70 | $enableModule->state = $moduleAsDefaultOn->state;
71 | $enableModule->save();
72 | }
73 | }
74 |
75 | /**
76 | * Set Reputation Module when it is enabled as default on the User
77 | *
78 | * @param $user Object
79 | */
80 | public static function onUserEnabledAsDefault($user) {
81 | $moduleEnabled = \humhub\modules\user\models\Module::findOne(['user_id' => $user->id, 'module_id' => 'reputation']);
82 | $moduleAsDefaultOn = \humhub\modules\user\models\Module::find()->where(['user_id' => 0, 'module_id' => 'reputation', 'state' => 1])->orWhere(['user_id' => 0, 'module_id' => 'reputation', 'state' => 2])->one();
83 | if ($moduleEnabled === NULL && $moduleAsDefaultOn != NULL) {
84 | $enableModule = new \humhub\modules\user\models\Module();
85 | $enableModule->module_id = 'reputation';
86 | $enableModule->user_id = $user->id;
87 | $enableModule->state = $moduleAsDefaultOn->state;
88 | $enableModule->save();
89 | }
90 | }
91 |
92 | /**
93 | * On user delete, also delete all reputation of this user
94 | *
95 | * @param type $event
96 | */
97 | public static function onUserDelete($event) {
98 | foreach (ReputationUser::findAll(['user_id' => $event->sender->id]) as $reputationUser) {
99 | $reputationUser->delete();
100 | }
101 | }
102 |
103 | /**
104 | * When a user leaves a space remove the user reputation for this space
105 | *
106 | * @param type $event
107 | */
108 | public static function onSpaceMembershipDelete($event) {
109 | foreach (ReputationUser::findAll(['user_id' => $event->sender->user_id, 'space_id' => $event->sender->space_id]) as $reputationUser) {
110 | $reputationUser->delete();
111 | }
112 | }
113 |
114 | /**
115 | * On space delete, also delete all reputation of this space
116 | *
117 | * @param type $event
118 | */
119 | public static function onSpaceDelete($event) {
120 | foreach (ReputationUser::findAll(['wall_id' => $event->sender->contentcontainer_id]) as $reputationSpace) {
121 | $reputationSpace->delete();
122 | }
123 | }
124 |
125 | /**
126 | * On content delete, also delete the content reputation
127 | *
128 | * @param type $event
129 | */
130 | public static function onContentDelete($event) {
131 | foreach (ReputationContent::findAll(['content_id' => $event->sender->id]) as $reputationContent) {
132 | $reputationContent->delete();
133 | }
134 | }
135 |
136 | /**
137 | * Show reputation menu in user profile
138 | *
139 | * @param type $event
140 | */
141 | public static function onProfileMenuInit($event) {
142 | if ($event->sender->user !== null && $event->sender->user->isModuleEnabled('reputation')) {
143 | $event->sender->addItem(array(
144 | 'label' => Yii::t('ReputationModule.base', 'User Reputation'),
145 | 'group' => 'profile',
146 | 'url' => $event->sender->user->createUrl('/reputation/profile/config'),
147 | 'isActive' => (Yii::$app->controller->module && Yii::$app->controller->module->id == 'reputation' && Yii::$app->controller->id == 'profile' && Yii::$app->controller->action->id == 'config'),
148 | 'sortOrder' => 1000,
149 | ));
150 | }
151 | }
152 |
153 | /*
154 | * Show reputation menu in space admin menu
155 | *
156 | * @param type $event
157 | */
158 |
159 | public static function onSpaceAdminMenuWidgetInit($event) {
160 | if ($event->sender->space !== null && $event->sender->space->isModuleEnabled('reputation') && $event->sender->space->isAdmin()) {
161 | $event->sender->addItem(['label' => Yii::t('ReputationModule.base', 'User Reputation'),
162 | 'url' => $event->sender->space->createUrl('/reputation/admin'),
163 | 'sortOrder' => 300,
164 | 'isActive' => (Yii::$app->controller->module && Yii::$app->controller->module->id === 'reputation'),
165 | ]);
166 | }
167 | }
168 |
169 | /*
170 | * Show reputation menu in space menu
171 | *
172 | * @param type $event
173 | */
174 |
175 | public static function onSpaceMenuInit($event) {
176 | if ($event->sender->space !== null && $event->sender->space->isModuleEnabled('reputation') && $event->sender->space->isMember()) {
177 | $event->sender->addItem(array(
178 | 'label' => Yii::t('ReputationModule.base', 'Hot'),
179 | 'url' => $event->sender->space->createUrl('/reputation/space'),
180 | 'icon' => ' ',
181 | 'isActive' => (Yii::$app->controller->module && Yii::$app->controller->module->id == 'reputation' && Yii::$app->controller->id == 'space' && Yii::$app->controller->action->id == 'index'),
182 | 'group' => 'modules',
183 | 'sortOrder' => 200,
184 | ));
185 | }
186 | }
187 |
188 | /**
189 | * On run of integrity check command, validate all module data
190 | *
191 | * @param $event
192 | */
193 | public static function onIntegrityCheck($event) {
194 | $integrityChecker = $event->sender;
195 | $integrityChecker->showTestHeadline("Reputation Module (Content) (" . ReputationContent::find()->count() . " entries)");
196 | $integrityChecker->showTestHeadline("Reputation Module (User) (" . ReputationUser::find()->count() . " entries)");
197 | }
198 |
199 | /**
200 | * Add Space Widget (TODO when Reputation on this space enabled)
201 | *
202 | * @param $event
203 | */
204 | public static function onSpaceSidebar($event) {
205 | if ($event->sender->space->isModuleEnabled('reputation')) {
206 | $event->sender->addWidget(widgets\SpaceUserReputationWidget::className(), array('contentContainer' => $event->sender->space), array('sortOrder' => 10));
207 | }
208 | }
209 |
210 | }
211 |
--------------------------------------------------------------------------------
/models/ReputationBase.php:
--------------------------------------------------------------------------------
1 | wall_id;
52 | $spaceContent = Yii::$app->cache->get($cacheId);
53 | if ($spaceContent === false || $forceUpdate === true) {
54 |
55 | $condition = 'contentcontainer_id=:spaceId AND object_model!=:activity';
56 | $params = [':spaceId' => $container->wall_id, ':activity' => 'humhub\modules\activity\models\Activity'];
57 | $query = Content::find()
58 | ->where($condition, $params)
59 | ->all();
60 |
61 | Yii::$app->cache->set($cacheId, $spaceContent = $query, ReputationContent::CACHE_TIME_SECONDS);
62 | }
63 | return $spaceContent;
64 | }
65 |
66 | /**
67 | * Count all comments a content object has received.
68 | *
69 | * @param Content $content : The content object
70 | * @param $userId : The user id
71 | * @param $cacheId : The cache id
72 | * @param bool $countOwnComments : Count comments created by same user as content
73 | * @param bool $forceUpdate : true if cache should be ignored
74 | * @return Comment[]
75 | */
76 | public function getCommentsFromContent(Content $content, $userId, $cacheId, $countOwnComments = false, $forceUpdate = false) {
77 | $comments = Yii::$app->cache->get($cacheId);
78 |
79 | if ($comments === false || $forceUpdate === true) {
80 | $object = $content->object_model;
81 | $objectModel = $object::tableName();
82 | $comments = array();
83 | try {
84 | $query = Comment::find();
85 | $query->leftJoin($objectModel . ' AS o', 'comment.object_id = o.id');
86 | $query->leftJoin('content AS ct', 'o.id = ct.object_id');
87 |
88 | if ($countOwnComments === true) {
89 | $condition = 'ct.id=:contentId AND ct.created_by=:userId AND comment.object_model=ct.object_model';
90 | } else {
91 | $condition = 'ct.id=:contentId AND ct.created_by=:userId AND comment.created_by!=:userId AND comment.object_model=ct.object_model';
92 | }
93 | $params = array(':contentId' => $content->id, ':userId' => $userId);
94 | $query->where($condition, $params);
95 | $comments = $query->all();
96 |
97 | Yii::$app->cache->set($cacheId, $query, ReputationBase::CACHE_TIME_SECONDS);
98 | } catch (Exception $e) {
99 | Yii::trace('Couldn\'t count comments from object model: ' . $objectModel);
100 | }
101 | }
102 |
103 | return $comments;
104 | }
105 |
106 | /**
107 | * Return an array with all space settings and call setSpaceSettings when not found
108 | * @param $container Object
109 | * @return $spaceSettings array
110 | */
111 | public function getSpaceSettings($container) {
112 | $getSettings = ContentContainerSetting::findAll(['module_id' => 'reputation', 'contentcontainer_id' => $container->wall_id]);
113 |
114 | if (count($getSettings) > 0) {
115 | foreach ($getSettings as $setting) {
116 | $spaceSettings[$setting['name']] = $setting['value'];
117 | }
118 | } else {
119 | $spaceSettings = self::setSpaceSettings($container);
120 | }
121 | return $spaceSettings;
122 | }
123 |
124 | /**
125 | * set standard Reputation settings onSpace
126 | * @param $container Object
127 | * @return $spaceSettings array
128 | */
129 | protected function setSpaceSettings($container) {
130 | $spaceSettings = [
131 | 'functions' => self::DEFAULT_FUNCTION,
132 | 'logarithm_base' => self::DEFAULT_LOGARITHM_BASE,
133 | 'create_content' => self::DEFAULT_CREATE_CONTENT,
134 | 'smb_likes_content' => self::DEFAULT_SMB_LIKES_CONTENT,
135 | 'smb_likes_content' => self::DEFAULT_SMB_FAVORITES_CONTENT,
136 | 'smb_favorites_content' => self::DEFAULT_SMB_COMMENTS_CONTENT,
137 | 'smb_comments_content' => self::DEFAULT_SMB_COMMENTS_CONTENT,
138 | 'daily_limit' => self::DEFAULT_DAILY_LIMIT,
139 | 'decrease_weighting' => self::DEFAULT_DECREASE_WEIGHTING,
140 | 'cron_job' => self::DEFAULT_CRON_JOB,
141 | 'lambda_long' => self::DEFAULT_LAMBDA_SHORT,
142 | 'lambda_short' => self::DEFAULT_LAMBDA_LONG,
143 | 'ranking_new_period' => self::DEFAULT_RANKING_NEW_PERIOD];
144 |
145 | foreach ($spaceSettings as $name => $value) {
146 | Setting::Set($container->id, $name, $value, 'reputation');
147 | }
148 | return $spaceSettings;
149 | }
150 |
151 | /**
152 | * Count all likes a content object has received. Do not count likes from user who created this post
153 | *
154 | * @param Content $content : The content object
155 | * @param $userId : The user id
156 | * @param $cacheId : The cache id
157 | * @param bool $forceUpdate : true if cache should be ignored
158 | * @return Like[]
159 | */
160 | protected function getLikesFromContent(Content $content, $userId, $cacheId, $forceUpdate = false) {
161 | $likes = Yii::$app->cache->get($cacheId);
162 |
163 | if ($likes === false || $forceUpdate === true) {
164 | $object = $content->object_model;
165 | $objectModel = $object::tableName();
166 | $likes = array();
167 | try {
168 | $query = Like::find();
169 | $query->leftJoin($objectModel . ' AS p', 'like.object_id = p.id');
170 | $query->leftJoin('content AS ct', 'p.id = ct.object_id');
171 | $condition = 'ct.id=:contentId AND like.created_by!=:userId AND ct.created_by=:userId AND like.object_model=:objectModel AND ct.object_model=:objectModel';
172 | $params = array(':contentId' => $content->id, ':objectModel' => $objectModel, ':userId' => $userId);
173 | $query->where($condition, $params);
174 | $query->all();
175 |
176 | Yii::$app->cache->set($cacheId, $query, ReputationBase::CACHE_TIME_SECONDS);
177 | } catch (Exception $e) {
178 | Yii::trace('Couldn\'t fetch likes from object model: ' . $objectModel);
179 | }
180 | }
181 |
182 | return $likes;
183 | }
184 |
185 | /**
186 | * Count all favorites a content object has received. Do not count favorites from user who created this post
187 | *
188 | * @param Content $content : The content object
189 | * @param $userId : The user id
190 | * @param $cacheId : The cache id
191 | * @param bool $forceUpdate : true if cache should be ignored
192 | * @return Favorite[]
193 | */
194 | protected function getFavoritesFromContent(Content $content, $userId, $cacheId, $forceUpdate = false) {
195 | $favorites = Yii::$app->cache->get($cacheId);
196 |
197 | if ($favorites === false || $forceUpdate === true) {
198 | $object = $content->object_model;
199 | $objectModel = $object::tableName();
200 | $favorites = array();
201 |
202 | // not possible to favorite comments atm
203 | if (strcmp($objectModel, 'comment') == 0) {
204 | return array();
205 | }
206 |
207 | try {
208 | $query = Favorite::find();
209 | $query->leftJoin($objectModel . ' AS p', 'favorite.object_id = p.id');
210 | $query->leftJoin('content AS ct', 'p.id = ct.object_id');
211 |
212 | $condition = 'ct.id=:contentId AND favorite.created_by!=:userId AND ct.created_by=:userId AND favorite.object_model=:objectModel AND ct.object_model=:objectModel';
213 | $params = array(':contentId' => $content->id, ':objectModel' => $objectModel, ':userId' => $userId);
214 | $query->where($condition, $params);
215 | $query->all();
216 |
217 | Yii::$app->cache->set($cacheId, $query, ReputationBase::CACHE_TIME_SECONDS);
218 | } catch (Exception $e) {
219 | Yii::trace('Couldn\'t fetch favorites from object model: ' . $objectModel);
220 | }
221 | }
222 |
223 | return $favorites;
224 | }
225 |
226 | }
227 |
--------------------------------------------------------------------------------
/views/space/settings.php:
--------------------------------------------------------------------------------
1 |
10 |
11 |
13 |
14 |
15 | ['settings', 'sguid' => $space->guid],
18 | 'method' => 'post',
19 | 'id' => 'configure-form',
20 | 'enableAjaxValidation' => false,
21 | ]);
22 | ?>
23 |
24 | errorSummary($model); ?>
25 |
26 |
27 |
28 |
29 |
30 | Yii::t('ReputationModule.base', 'Logarithmic'),
33 | ReputationBase::LINEAR => Yii::t('ReputationModule.base', 'Linear')
34 | );
35 | echo $form->
36 | field($model, 'functions')->
37 | label(Yii::t('ReputationModule.forms_adminController_settings', 'Function'))->
38 | dropDownList($functions, array('class' => 'form-control', 'id' => 'dropdown_function', 'hint' => Yii::t('ReputationModule.views_adminReputation_show', 'Choose the function that should be used to show user reputation.')));
39 | ?>
40 |
41 |
42 |
43 | functions == '1'): ?>
44 |
45 |
47 | field($model, 'logarithm_base')->
48 | label(Yii::t('ReputationModule.forms_adminController_settings', 'Logarithm base'))->
49 | textInput(array('class' => 'form-control'));
50 | ?>
51 |
52 |
53 |
54 |
56 | field($model, 'logarithm_base')->
57 | label(Yii::t('ReputationModule.forms_adminController_settings', 'Logarithm base'))->
58 | textInput(array('class' => 'form-control'));
59 | ?>
60 |
61 |
62 |
63 |
64 |
66 | field($model, 'daily_limit')->
67 | label(Yii::t('ReputationModule.forms_adminController_settings', 'Daily limit for Users'))->
68 | textInput(array('class' => 'form-control'));
69 | ?>
70 |
71 |
72 |
73 |
74 | Yii::t('ReputationModule.base', 'Yes'),
77 | 0 => Yii::t('ReputationModule.base', 'No')
78 | );
79 | echo $form->
80 | field($model, 'decrease_weighting')->
81 | label(Yii::t('ReputationModule.forms_adminController_settings', 'Decrease weighting per post'))->
82 | dropDownList($functions, array('class' => 'form-control', 'id' => 'join_visibility_dropdown', 'hint' => Yii::t('ReputationModule.views_adminReputation_show', 'Should the weighting of reputation decrease with the number with increasing activity?')));
83 | ?>
84 |
85 |
86 |
87 |
88 |
89 | Yii::t('ReputationModule.base', 'Yes'),
92 | 0 => Yii::t('ReputationModule.base', 'No')
93 | );
94 | echo $form->
95 | field($model, 'cron_job')->
96 | label(Yii::t('ReputationModule.forms_adminController_settings', 'Update reputation data on hourly cron job'))->
97 | dropDownList($functions, array('class' => 'form-control', 'id' => 'join_visibility_dropdown', 'hint' => Yii::t('ReputationModule.views_adminReputation_show', 'Should the hourly cron job update reputation data for this space?')));
98 | ?>
99 |
100 |
101 |
102 |
103 |
105 | field($model, 'ranking_new_period')->
106 | label(Yii::t('ReputationModule.forms_adminController_settings', 'Time in hours for the "NEW" filter to show Content'))->
107 | textInput(array('class' => 'form-control'));
108 | ?>
109 |
110 |
111 |
112 |
114 |
115 |
116 |
117 |
118 |
120 | field($model, 'create_content')->
121 | label(Yii::t('ReputationModule.forms_adminController_settings', 'Creating posts or comments'))->
122 | textInput(array('class' => 'form-control'));
123 | ?>
124 |
125 |
126 |
128 | field($model, 'smb_likes_content')->
129 | label(Yii::t('ReputationModule.forms_adminController_settings', 'Somebody liked the post'))->
130 | textInput(array('class' => 'form-control'));
131 | ?>
132 |
133 | isModuleEnabled('favorite')): ?>
134 |
135 |
137 | field($model, 'smb_favorites_content')->
138 | label(Yii::t('ReputationModule.forms_adminController_settings', 'Somebody marked the post as favorite'))->
139 | textInput(array('class' => 'form-control'));
140 | ?>
141 |
142 |
143 |
144 |
146 | field($model, 'smb_comments_content')->
147 | label(Yii::t('ReputationModule.forms_adminController_settings', 'Somebody comments the post'))->
148 | textInput(array('class' => 'form-control'));
149 | ?>
150 |
151 |
152 |
153 |
154 |
156 |
157 |
158 |
159 |
160 |
162 | field($model, 'lambda_long')->
163 | label(Yii::t('ReputationModule.forms_adminController_settings', 'Exponential decrease for Ranking Rising'))->
164 | textInput(array('class' => 'form-control'));
165 | ?>
166 |
167 |
168 |
170 | field($model, 'lambda_short')->
171 | label(Yii::t('ReputationModule.forms_adminController_settings', 'Exponential decrease for Ranking Hot'))->
172 | textInput(array('class' => 'form-control'));
173 | ?>
174 |
175 |
176 |
177 |
178 | = Html::submitButton(Yii::t('ReputationModule.base', 'Save'), array('class' => 'btn btn-primary')) ?>
179 |
180 |
181 |
182 |
183 |
219 |
--------------------------------------------------------------------------------
/models/ReputationUser.php:
--------------------------------------------------------------------------------
1 | array(self::BELONGS_TO, 'User', 'user_id'),
57 | 'space' => array(self::BELONGS_TO, 'Space', 'space_id'),
58 | );
59 | }
60 |
61 | /**
62 | * @return array customized attribute labels (name=>label)
63 | */
64 | public function attributeLabels() {
65 | return array(
66 | 'id' => 'ID',
67 | 'value' => 'Value',
68 | 'visibility' => 'Visibility',
69 | 'user_id' => 'User',
70 | 'space_id' => 'Space ID',
71 | 'wall_id' => 'ContentContainer wall_id',
72 | 'created_at' => 'Created At',
73 | 'created_by' => 'Created By',
74 | 'updated_at' => 'Updated At',
75 | 'updated_by' => 'Updated By',
76 | );
77 | }
78 |
79 | /**
80 | * Updates all user reputation for this space
81 | * @param $space : The space to check
82 | * @param bool $forceUpdate : Ignore cache
83 | */
84 | public function updateUserReputation($container, $forceUpdate = false) {
85 |
86 | // get all users from this space
87 | $attributes = array('space_id' => $container->id);
88 | $spaceUsers = Membership::findAll($attributes);
89 |
90 | foreach ($spaceUsers as $user) {
91 |
92 | $cacheId = 'reputation_space_user' . '_' . $container->wall_id . '_' . $user->user_id;
93 | $userReputation = Yii::$app->cache->get($cacheId);
94 |
95 | if ($userReputation === false || $forceUpdate === true) {
96 |
97 | // get all reputation_user objects from this space
98 | $condition = array('user_id' => $user->user_id, 'space_id' => $container->id);
99 | $userReputation = ReputationUser::findOne($condition);
100 |
101 | if ($userReputation == null) {
102 | // Create new reputation_user entry
103 | $userReputation = new ReputationUser;
104 | $userReputation->user_id = $user->user_id;
105 | $userReputation->space_id = $container->id;
106 | $userReputation->wall_id = $container->wall_id;
107 | $userReputation->visibility = 0;
108 | $userReputation->created_by = $user->user_id;
109 | }
110 | $userReputation->value = ReputationUser::calculateUserReputationScore($user->user_id, $container, $forceUpdate);
111 | $userReputation->updated_at = date('Y-m-d H:i:s');
112 | $userReputation->updated_by = $container->updated_by;
113 | $userReputation->save();
114 |
115 | Yii::$app->cache->set($cacheId, $userReputation, ReputationBase::CACHE_TIME_SECONDS);
116 | }
117 | }
118 |
119 | ReputationUser::deleteMissingUsers($container->wall_id);
120 | }
121 |
122 | /**
123 | * Calculate the user reputation score inside a space
124 | * Use likes, favorites, comments from content that user created
125 | * Use posted comments and likes received for this comments for content the user didn't create
126 | * Include limitations in calculate like weight decrease and daily limit
127 | *
128 | * @param $userId : The userId to calculate reputation for
129 | * @param $container : The Space (contentContainer) the calculation is being based on
130 | * @return int: User reputation score inside this space
131 | */
132 | private function calculateUserReputationScore($userId, $container, $forceUpdate = false) {
133 | $spaceSettings = ReputationBase::getSpaceSettings($container);
134 | $dailyLimit = $spaceSettings['daily_limit'];
135 | $decreaseWeighting = $spaceSettings['decrease_weighting'];
136 |
137 | $spaceContent = ReputationBase::getContentFromSpace($container, $forceUpdate);
138 |
139 | foreach ($spaceContent as $content) {
140 | /*
141 | * keep track of how many times an content object was liked, favorited etc.
142 | * this allows to decrease the value of repeating actions
143 | * e.g. the second like only gives the user half the points from the first like
144 | */
145 | $scoreCount = 1;
146 | /*
147 | * handle content that is created by this user
148 | * use likes, favorites, comments from content that user created
149 | */
150 | if ($content->created_by == $userId) {
151 | ReputationUser::addToDailyReputation($content, $spaceSettings['create_content'], $dailyLimit);
152 | // now count the likes this content received from other users
153 | $cacheId = 'likes_earned_cache_' . $userId . '_' . $content->id;
154 | $likes = ReputationBase::getLikesFromContent($content, $userId, $cacheId, $forceUpdate);
155 | foreach ($likes as $like) {
156 | if ($decreaseWeighting == '1') {
157 | ReputationUser::addToDailyReputation($like, $spaceSettings['smb_likes_content'] / $scoreCount, $dailyLimit);
158 | } else {
159 | ReputationUser::addToDailyReputation($like, $spaceSettings['smb_likes_content'], $dailyLimit);
160 | }
161 | $scoreCount++;
162 | }
163 |
164 | if ($container->isModuleEnabled('favorite')) {
165 | $scoreCount = 1;
166 | // now count the favorites this content received from other users
167 | $cacheId = 'favorites_earned_cache_' . $userId . '_' . $content->id;
168 | $favorites = ReputationBase::getFavoritesFromContent($content, $userId, $cacheId, $forceUpdate);
169 | foreach ($favorites as $favorite) {
170 | if ($decreaseWeighting == '1') {
171 | ReputationUser::addToDailyReputation($favorite, $spaceSettings['smb_favorites_content'] / $scoreCount, $dailyLimit);
172 | } else {
173 | ReputationUser::addToDailyReputation($favorite, $spaceSettings['smb_favorites_content'], $dailyLimit);
174 | }
175 | $scoreCount++;
176 | }
177 | }
178 | $scoreCount = 1;
179 | // now count how many comments this post has generated
180 | $cacheId = 'comments_earned_cache_' . $userId . '_' . $content->id;
181 | $comments = ReputationBase::getCommentsFromContent($content, $userId, $cacheId, false, $forceUpdate);
182 | foreach ($comments as $comment) {
183 | if ($decreaseWeighting == '1') {
184 | ReputationUser::addToDailyReputation($comment, $spaceSettings['smb_comments_content'] / $scoreCount, $dailyLimit);
185 | } else {
186 | ReputationUser::addToDailyReputation($comment, $spaceSettings['smb_comments_content'], $dailyLimit);
187 | }
188 | $scoreCount++;
189 | }
190 | $scoreCount = 1;
191 | }
192 |
193 | /**
194 | * now handle posts that were created by others users
195 | * The user gets points for comments he created and for likes the comments have received
196 | */
197 | $commentsPosted = ReputationUser::GetCommentsGeneratedByUser($userId, $content, $forceUpdate);
198 | foreach ($commentsPosted as $commentPosted) {
199 | ReputationUser::addToDailyReputation($commentPosted, $spaceSettings['create_content'], $dailyLimit);
200 | }
201 |
202 | $commentsLiked = ReputationUser::GetCommentsGeneratedByUserLikedByOthers($userId, $content, $forceUpdate);
203 | foreach ($commentsLiked as $commentLiked) {
204 | if ($decreaseWeighting == '1') {
205 | ReputationUser::addToDailyReputation($commentLiked, $spaceSettings['smb_likes_content'] / $scoreCount, $dailyLimit);
206 | } else {
207 | ReputationUser::addToDailyReputation($commentLiked, $spaceSettings['smb_likes_content'], $dailyLimit);
208 | }
209 | $scoreCount++;
210 | }
211 | }
212 |
213 | /*
214 | * Iterate over daily_reputation structure to get final score
215 | */
216 | $reputationScore = 0;
217 | foreach (ReputationUser::$daily_reputation as $reputation) {
218 | $reputationScore += $reputation->getScore();
219 | }
220 |
221 | // reset this array for next user
222 | ReputationUser::$daily_reputation = array();
223 |
224 |
225 |
226 | return ReputationUser::calculateUserScore($spaceSettings['functions'], $reputationScore, $spaceSettings['logarithm_base']);
227 | }
228 |
229 | /**
230 | * @param $content
231 | * @param $scoreToAdd
232 | * @param $daily_limit
233 | * @return array
234 | */
235 | private function addToDailyReputation($content, $scoreToAdd, $daily_limit) {
236 | global $daily_reputation;
237 | $date = date_create($content->created_at)->format('Y-m-d');
238 |
239 | if (array_key_exists($date, ReputationUser::$daily_reputation)) {
240 | $currentDate = ReputationUser::$daily_reputation[$date];
241 | $currentDate->addScore($scoreToAdd);
242 |
243 | return array($date, $currentDate, ReputationUser::$daily_reputation);
244 | } else {
245 | ReputationUser::$daily_reputation[$date] = new DailyReputation($scoreToAdd, $daily_limit);
246 | }
247 | }
248 |
249 | /**
250 | * Get all comments the user created.
251 | *
252 | * @param $userId
253 | * @param Content $content
254 | * @param $forceUpdate : Ignore cache
255 | * @return Comment[]
256 | */
257 | public function GetCommentsGeneratedByUser($userId, Content $content, $forceUpdate = false) {
258 | $cacheId = 'comments_generated_cache_' . $userId . '_' . $content->id;
259 |
260 | $commentsGenerated = Yii::$app->cache->get($cacheId);
261 |
262 | if ($commentsGenerated === false || $forceUpdate === true) {
263 | $object = $content->object_model;
264 | $objectModel = $object::tableName();
265 | $commentsGenerated = array();
266 | try {
267 | $query = Comment::find();
268 | $query->leftJoin($objectModel . ' AS o', 'comment.object_id = o.id');
269 | $query->leftJoin('content AS ct', 'o.id = ct.object_id');
270 | $params = array(':contentId' => $content->id, ':userId' => $userId);
271 | $query->where('ct.id=:contentId AND c.created_by=:userId AND c.object_model=ct.object_model', $params);
272 | $commentsGenerated = $query->all();
273 |
274 | Yii::$app->cache->set($cacheId, $commentsGenerated, ReputationBase::CACHE_TIME_SECONDS);
275 | } catch (Exception $e) {
276 | Yii::trace('Couldn\'t count generated comments from object model: ' . $objectModel);
277 | }
278 | }
279 |
280 | return $commentsGenerated;
281 | }
282 |
283 | /**
284 | * Get all likes that a user got for a comment he made
285 | * When a user likes his own comment it will not be counted
286 | *
287 | * @param $userId
288 | * @param Content $content
289 | * @param $forceUpdate : Ignore cache
290 | * @return int
291 | */
292 | public function GetCommentsGeneratedByUserLikedByOthers($userId, Content $content, $forceUpdate) {
293 | $cacheId = 'comments_liked_cache_' . $userId . '_' . $content->id;
294 | $commentsLiked = Yii::$app->cache->get($cacheId);
295 | if ($commentsLiked === false || $forceUpdate === true) {
296 | $object = $content->object_model;
297 | $objectModel = $object::tableName();
298 | $commentsLiked = array();
299 | try {
300 | $query = Like::find();
301 | $query->leftJoin('comment AS c', 'c.id = like.object_id');
302 | $query->leftJoin($objectModel . ' AS o', 'c.object_id = o.id');
303 | $query->leftJoin('content AS ct', 'o.id = ct.object_id');
304 | $params = array(':contentId' => $content->id, ':userId' => $userId);
305 | $query->where('like.object_model=\'humhub\modules\comment\models\Comment\' AND like.created_by!=:userId AND ct.id=:contentId AND c.created_by=:userId AND c.object_model=ct.object_model', $params);
306 | $commentsLiked = $query->all();
307 |
308 | Yii::$app->cache->set($cacheId, $commentsLiked, ReputationBase::CACHE_TIME_SECONDS);
309 | } catch (Exception $e) {
310 | Yii::trace('Couldn\'t count generated comments from object model: ' . $objectModel);
311 | }
312 | }
313 | return $commentsLiked;
314 | }
315 |
316 | /**
317 | * Calculate final user score.
318 | *
319 | * @param $function : Linear or Logarithmic
320 | * @param $reputationScore : The score the user reached
321 | * @param $logarithmBase : The logarithm base
322 | * @return int
323 | */
324 | private function calculateUserScore($function, $reputationScore, $logarithm_base) {
325 | if ($function == ReputationBase::LINEAR) {
326 | return intval($reputationScore);
327 | } else {
328 | if ($reputationScore == 0) {
329 | return 0;
330 | } else {
331 | // increase reputation score + 1 so log is not 0 when user has 1 point
332 | $logValue = log($reputationScore + 1, $logarithm_base);
333 | return intval(round($logValue * 100));
334 | }
335 | }
336 | }
337 |
338 | /**
339 | * Delete users that are not space members anymore
340 | *
341 | * @param $spaceId
342 | * @throws CDbException
343 | */
344 | private function deleteMissingUsers($spaceId) {
345 | $condition = array('space_id' => $spaceId);
346 | $reputationUsers = ReputationUser::findAll($condition);
347 | foreach ($reputationUsers as $user) {
348 | if (Membership::findOne('space_id=' . $spaceId . ' AND user_id=' . $user->user_id . '')) {
349 | Membership::delete();
350 | }
351 | }
352 | }
353 | }
354 |
--------------------------------------------------------------------------------