Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix/anonymoususerstats #147

Merged
merged 9 commits into from
Jul 3, 2023
Merged
10 changes: 8 additions & 2 deletions classes/privacy/provider.php
Original file line number Diff line number Diff line change
Expand Up @@ -143,9 +143,15 @@ public static function get_contexts_for_userid(int $userid) : contextlist {
INNER JOIN {modules} m ON m.id = cm.module AND m.name = :modname
INNER JOIN {moodleoverflow} mof ON mof.id = cm.instance
WHERE EXISTS (
SELECT 1 FROM {moodleoverflow_discussions} d WHERE d.moodleoverflow = mof.id AND (d.userid = :duserid OR d.usermodified = :dmuserid)
SELECT 1
FROM {moodleoverflow_discussions} d
WHERE d.moodleoverflow = mof.id AND (d.userid = :duserid OR d.usermodified = :dmuserid)
) OR EXISTS (
SELECT 1 FROM {moodleoverflow_posts} p WHERE p.discussion IN (SELECT id FROM {moodleoverflow_discussions} WHERE moodleoverflow = mof.id) AND p.userid = :puserid
SELECT 1
FROM {moodleoverflow_posts} p
WHERE p.discussion IN (SELECT id
FROM {moodleoverflow_discussions}
WHERE moodleoverflow = mof.id) AND p.userid = :puserid
) OR EXISTS (
SELECT 1 FROM {moodleoverflow_read} r WHERE r.moodleoverflowid = mof.id AND r.userid = :ruserid
) OR EXISTS (
Expand Down
4 changes: 2 additions & 2 deletions classes/ratings.php
Original file line number Diff line number Diff line change
Expand Up @@ -477,7 +477,7 @@ public static function moodleoverflow_discussion_is_solved($discussionid, $teach
*
* @return int
*/
private static function moodleoverflow_get_reputation_instance($moodleoverflowid, $userid = null) {
public static function moodleoverflow_get_reputation_instance($moodleoverflowid, $userid = null) {
global $DB, $USER;

// Get the user id.
Expand Down Expand Up @@ -574,7 +574,7 @@ private static function moodleoverflow_get_reputation_instance($moodleoverflowid
*
* @return int
*/
private static function moodleoverflow_get_reputation_course($courseid, $userid = null) {
public static function moodleoverflow_get_reputation_course($courseid, $userid = null) {
global $USER, $DB;

// Get the userid.
Expand Down
224 changes: 143 additions & 81 deletions classes/tables/userstats_table.php

Large diffs are not rendered by default.

6 changes: 4 additions & 2 deletions lang/en/moodleoverflow.php
Original file line number Diff line number Diff line change
Expand Up @@ -205,8 +205,10 @@
// Strings for the userstats feature.
$string['userstatsupvotes'] = 'Received upvotes';
$string['userstatsdownvotes'] = 'Received downvotes';
$string['userstatsactivity'] = 'Amount of activity';
$string['userstatsreputation'] = 'User reputation';
$string['userstatsforumactivity'] = 'Activity (this forum)';
$string['userstatsforumreputation'] = 'Reputation (this forum)';
$string['userstatscourseactivity'] = 'Activity (coursewide)';
$string['userstatscoursereputation'] = 'Reputation (coursewide)';
$string['helpamountofactivity'] = 'Each activity like writing a post, starting a discussion or giving a rating gives 1 point';
$string['showuserstats'] = 'Show cumulative user statistics';
$string['configshowuserstats'] = 'Allow teachers in courses to see statistics summarizing the activity of users in Moodleoverflows.';
Expand Down
2 changes: 1 addition & 1 deletion styles.css
Original file line number Diff line number Diff line change
Expand Up @@ -529,7 +529,7 @@
}


.moodleoverflow-statistics-table .header.c3 .helpactivityclass {
.moodleoverflow-statistics-table .header .helpactivityclass {
padding: 0;
margin-left: 8px;
}
Expand Down
1 change: 1 addition & 0 deletions tests/privacy_provider_test.php
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
* @group mod_moodleoverflow
* @group mod_moodleoverflow_privacy
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
* @covers \provider
*/
class privacy_provider_test extends \core_privacy\tests\provider_testcase {
/**
Expand Down
1 change: 1 addition & 0 deletions tests/readtracking_test.php
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
* @package mod_moodleoverflow
* @copyright 2017 Kennet Winter <[email protected]>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
* @covers \readtracking
*/
class readtracking_test extends advanced_testcase {

Expand Down
1 change: 1 addition & 0 deletions tests/subscriptions_test.php
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
* @package mod_moodleoverflow
* @copyright 2017 Kennet Winter <[email protected]>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
* @covers \subscriptions
*/
class subscriptions_test extends advanced_testcase {

Expand Down
184 changes: 160 additions & 24 deletions tests/userstats_test.php
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@
* @package mod_moodleoverflow
* @copyright 2023 Tamaro Walter
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*
* @covers \userstats_table
*/
class userstats_test extends \advanced_testcase {

Expand Down Expand Up @@ -107,11 +109,7 @@ public function test_upvote() {

// Create the user statistics table for this course and save it in $data.
$data = $this->create_statstable();
foreach ($data as $student) {
if ($student->id == $this->user2->id) {
$upvotes = $student->receivedupvotes;
}
}
$upvotes = $this->get_specific_userstats($data, $this->user2, 'receivedupvotes');
$this->assertEquals(1, $upvotes);
}

Expand All @@ -125,11 +123,7 @@ public function test_downvote() {

// Create the user statistics table for this course and save it in $data.
$data = $this->create_statstable();
foreach ($data as $student) {
if ($student->id == $this->user1->id) {
$downvotes = $student->receiveddownvotes;
}
}
$downvotes = $this->get_specific_userstats($data, $this->user1, 'receiveddownvotes');
$this->assertEquals(1, $downvotes);
}

Expand All @@ -146,11 +140,7 @@ public function test_activity() {
// Activity = 5.
// Create the user statistics table for this course and save it in $data.
$data = $this->create_statstable();
foreach ($data as $student) {
if ($student->id == $this->user1->id) {
$activity = $student->activity;
}
}
$activity = $this->get_specific_userstats($data, $this->user1, 'forumactivity');
$this->assertEquals(5, $activity);

}
Expand All @@ -165,18 +155,115 @@ public function test_reputation() {
$this->create_downvote($this->user1, $this->discussion2[1], $this->post2);
$this->create_solution($this->teacher, $this->discussion1[1], $this->answer1);

// Calculate the reputation of user2.
$reputation = \mod_moodleoverflow\ratings::moodleoverflow_get_reputation($this->moodleoverflow->id, $this->user2->id);
// Calculate the forum reputation of user2.
$reputation = \mod_moodleoverflow\ratings::moodleoverflow_get_reputation_instance($this->moodleoverflow->id,
$this->user2->id);
// Create the user statistics table for this course and save it in $data.
$data = $this->create_statstable();
foreach ($data as $student) {
if ($student->id == $this->user2->id) {
$reputation2 = $student->reputation;
}
}
$reputation2 = $this->get_specific_userstats($data, $this->user2, 'forumreputation');
$this->assertEquals($reputation, $reputation2);
}

/**
* Test, if userstats are calculated correctly if the moodleoverflow is partially anonymous.
* @covers \userstats_table
*/
public function test_partial_anonymous() {
global $DB;
// Test case: Only topic startes are anonymous.
$this->make_anonymous(1);

// Get the current userstats to compare later.
$olduserstats = $this->create_statstable();
$oldupvotesuser1 = $this->get_specific_userstats($olduserstats, $this->user1, 'receivedupvotes');
$oldactivityuser1 = $this->get_specific_userstats($olduserstats, $this->user1, 'forumactivity');

$oldupvotesuser2 = $this->get_specific_userstats($olduserstats, $this->user2, 'receivedupvotes');
$oldactivityuser2 = $this->get_specific_userstats($olduserstats, $this->user2, 'forumactivity');

// User1 starts a new discussion, the forum activity shouldn't change.
$discussion = $this->generator->post_to_forum($this->moodleoverflow, $this->user1);
$starterpost = $DB->get_record('moodleoverflow_posts', array('id' => $discussion[0]->firstpost), '*');
$newuserstats = $this->create_statstable();
$newactivityuser1 = $this->get_specific_userstats($newuserstats, $this->user1, 'forumactivity');
$this->assertEquals($oldactivityuser1, $newactivityuser1);

// User2 now gives an answer to user1, his activity should change.
$answeruser2 = $this->generator->reply_to_post($discussion[1], $this->user2, true);
$newuserstats = $this->create_statstable();
$newactivityuser2 = $this->get_specific_userstats($newuserstats, $this->user2, 'forumactivity');
$this->assertEquals($oldactivityuser2 + 1, $newactivityuser2);
$oldactivityuser2 = $newactivityuser2; // Update it for further comparisons.

// User1 rates the answer from user2 as helpful an gives it an upvote.
// The activity of user1 should only change when he gives an upvote.
// The received upvotes from user2 should change.
$this->create_helpful($this->user1, $discussion[1], $answeruser2);
$newuserstats = $this->create_statstable();
$newactivityuser1 = $this->get_specific_userstats($newuserstats, $this->user1, 'forumactivity');
$this->assertEquals($oldactivityuser1, $newactivityuser1);

$this->create_upvote($this->user1, $discussion[1], $answeruser2);
$newuserstats = $this->create_statstable();
$newactivityuser1 = $this->get_specific_userstats($newuserstats, $this->user1, 'forumactivity');
$newupvotesuser2 = $this->get_specific_userstats($newuserstats, $this->user2, 'receivedupvotes');
$this->assertEquals($oldactivityuser1 + 1, $newactivityuser1);
$this->assertEquals($oldupvotesuser2 + 1, $newupvotesuser2);

// User2 gives the discussion starter post an upvote.
// Activity of User2 should change, the receivedupvotes from user1 shouln't change.
$this->create_upvote($this->user2, $discussion[1], $starterpost);
$newuserstats = $this->create_statstable();
$newactivityuser2 = $this->get_specific_userstats($newuserstats, $this->user2, 'forumactivity');
$newupvotesuser1 = $this->get_specific_userstats($newuserstats, $this->user1, 'receivedupvotes');
$this->assertEquals($oldactivityuser2 + 1, $newactivityuser2);
$this->assertEquals($oldupvotesuser1, $newupvotesuser1);
}

/**
* Test, if userstats are calculated correctly if the moodleoverflow is partially anonymous.
* @covers \userstats_table
*/
public function test_total_anonymous() {
// Test case: Only topic startes are anonymous.
$this->make_anonymous(2);

// Get the current userstats to compare later.
$olduserstats = $this->create_statstable();
$oldupvotesuser1 = $this->get_specific_userstats($olduserstats, $this->user1, 'receivedupvotes');
$oldactivityuser1 = $this->get_specific_userstats($olduserstats, $this->user1, 'forumactivity');

$oldupvotesuser2 = $this->get_specific_userstats($olduserstats, $this->user2, 'receivedupvotes');
$oldactivityuser2 = $this->get_specific_userstats($olduserstats, $this->user2, 'forumactivity');

// User1 starts a new discussion, the forum activity shouldn't change.
$discussion = $this->generator->post_to_forum($this->moodleoverflow, $this->user1);
$newuserstats = $this->create_statstable();
$newactivityuser1 = $this->get_specific_userstats($newuserstats, $this->user1, 'forumactivity');
$this->assertEquals($oldactivityuser1, $newactivityuser1);

// User2 now gives an answer to user1, his activity shouldn't change.
$answeruser2 = $this->generator->reply_to_post($discussion[1], $this->user2, true);
$newuserstats = $this->create_statstable();
$newactivityuser2 = $this->get_specific_userstats($newuserstats, $this->user2, 'forumactivity');
$this->assertEquals($oldactivityuser2, $newactivityuser2);

// User1 rates the answer from user2 as helpful an gives it an upvote.
// The activity of user1 should only change when he gives an upvote.
// User2 received upvotes should not change.
$this->create_helpful($this->user1, $discussion[1], $answeruser2);
$newuserstats = $this->create_statstable();
$newactivityuser1 = $this->get_specific_userstats($newuserstats, $this->user1, 'forumactivity');
$this->assertEquals($oldactivityuser1, $newactivityuser1);

$this->create_upvote($this->user1, $discussion[1], $answeruser2);
$newuserstats = $this->create_statstable();
$newactivityuser1 = $this->get_specific_userstats($newuserstats, $this->user1, 'forumactivity');
$newupvotesuser2 = $this->get_specific_userstats($newuserstats, $this->user2, 'receivedupvotes');
$this->assertEquals($oldactivityuser1 + 1, $newactivityuser1);
$this->assertEquals($oldupvotesuser2, $newupvotesuser2);
}

// Helper functions.

/**
Expand Down Expand Up @@ -212,6 +299,23 @@ private function helper_course_set_up() {
$this->answer2 = $this->generator->reply_to_post($this->discussion2[1], $this->user1, true);
}

/**
* Makes the existing moodleoverflow anonymous.
* There are 2 types of anonymous moodleoverflows:
* anonymous = 1, the topic starter is anonymous
* anonymous = 2, all users are anonym
*
* @param int $anonymoussetting
*/
private function make_anonymous($anonymoussetting) {
global $DB;
if ($anonymoussetting == 1 || $anonymoussetting == 2) {
$this->moodleoverflow->anonymous = $anonymoussetting;
$DB->update_record('moodleoverflow', $this->moodleoverflow);
} else {
throw new \Exception('invalid parameter, anonymoussetting should be 1 or 2');
}
}

/**
* Create a usertable and return it.
Expand Down Expand Up @@ -284,7 +388,7 @@ private function create_helpful($author, $discussion, $post) {
'discussionid' => $discussion->id,
'userid' => $author->id,
'postid' => $post->id,
'rating' => 3,
'rating' => 4,
'firstrated' => time(),
'lastchanged' => time()
];
Expand All @@ -306,10 +410,42 @@ private function create_solution($author, $discussion, $post) {
'discussionid' => $discussion->id,
'userid' => $author->id,
'postid' => $post->id,
'rating' => 4,
'rating' => 3,
'firstrated' => time(),
'lastchanged' => time()
];
return $this->generator->create_rating($record);
}

/**
* Return a specific value from the userstatstable.
*
* @param array $statstable
* @param object $user
* @param string $stats // A key that specifies which value should be returned.
*/
private function get_specific_userstats($statstable, $user, $stats) {
foreach ($statstable as $student) {
if ($student->id == $user->id) {
switch ($stats) {
case 'receivedupvotes':
$result = $student->receivedupvotes;
break;
case 'receiveddownvotes':
$result = $student->receiveddownvotes;
break;
case 'forumactivity':
$result = $student->forumactivity;
break;
case 'forumreputation':
$result = $student->forumreputation;
break;
default:
throw new \Exception('parameter unknown');
break;
}
}
}
return $result;
}
}