├── styles └── prosilver │ ├── template │ ├── index.html │ ├── event │ │ ├── overall_footer_after.html │ │ ├── overall_header_head_append.html │ │ ├── viewtopic_body_postrow_custom_fields_before.html │ │ ├── memberlist_view_user_statistics_after.html │ │ ├── index_body_stat_blocks_before.html │ │ ├── mcp_warn_post_add_warning_field_after.html │ │ ├── mcp_warn_user_add_warning_field_after.html │ │ └── viewtopic_body_post_buttons_before.html │ ├── rateuser.html │ ├── ratepost.html │ ├── postdetails.html │ ├── userdetails.html │ ├── details.html │ └── reputation.js │ └── theme │ ├── images │ ├── neg.png │ ├── pos.png │ ├── icons_rating.png │ └── reputation_delete.png │ ├── reputation_viewtopic.css │ └── reputation_common.css ├── config ├── tables.yml ├── listeners.yml ├── notifications.yml ├── routing.yml └── services.yml ├── adm └── style │ ├── event │ ├── acp_group_options_after.html │ └── acp_forums_normal_settings_append.html │ ├── reputation_settings.html │ ├── reputation_rate.html │ └── reputation_overview.html ├── composer.json ├── exception ├── out_of_bounds.php ├── invalid_argument.php └── base.php ├── notification └── type │ ├── rate_post_negative.php │ ├── rate_post_positive.php │ └── rate_user.php ├── migrations ├── converter │ ├── c3_remove_columns.php │ ├── c6_remove_data.php │ ├── c1_convert_table.php │ ├── c5_remove_permissions.php │ ├── c4_remove_modules.php │ └── c2_convert_data.php └── v10x │ ├── m4_initial_modules.php │ ├── m6_main_reputation_types.php │ ├── m5_initial_columns.php │ ├── m3_initial_permissions.php │ ├── m1_initial_schema.php │ └── m2_initial_data.php ├── controller ├── acp_interface.php └── action_controller.php ├── acp ├── reputation_info.php └── reputation_module.php ├── core ├── reputation_power_interface.php ├── reputation_helper.php ├── reputation_manager_interface.php ├── reputation_power.php └── reputation_manager.php ├── language └── en │ ├── reputation_toplist.php │ ├── reputation_warning.php │ ├── exceptions.php │ ├── reputation_common.php │ ├── permissions_reputation.php │ ├── info_acp_reputation.php │ ├── reputation_rating.php │ ├── reputation_system.php │ └── reputation_acp.php ├── event ├── main_listener.php ├── memberlist_listener.php ├── index_listener.php ├── mcp_listener.php ├── acp_listener.php └── viewtopic_listener.php ├── README.md └── ext.php /styles/prosilver/template/index.html: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /styles/prosilver/theme/images/neg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Pico/phpBB-Reputation-System/HEAD/styles/prosilver/theme/images/neg.png -------------------------------------------------------------------------------- /styles/prosilver/theme/images/pos.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Pico/phpBB-Reputation-System/HEAD/styles/prosilver/theme/images/pos.png -------------------------------------------------------------------------------- /styles/prosilver/theme/images/icons_rating.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Pico/phpBB-Reputation-System/HEAD/styles/prosilver/theme/images/icons_rating.png -------------------------------------------------------------------------------- /config/tables.yml: -------------------------------------------------------------------------------- 1 | parameters: 2 | tables.reputations: %core.table_prefix%reputations 3 | tables.reputation_types: %core.table_prefix%reputation_types 4 | -------------------------------------------------------------------------------- /styles/prosilver/theme/images/reputation_delete.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Pico/phpBB-Reputation-System/HEAD/styles/prosilver/theme/images/reputation_delete.png -------------------------------------------------------------------------------- /styles/prosilver/template/event/overall_footer_after.html: -------------------------------------------------------------------------------- 1 | 2 |
3 | 4 | -------------------------------------------------------------------------------- /styles/prosilver/template/event/overall_header_head_append.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /adm/style/event/acp_group_options_after.html: -------------------------------------------------------------------------------- 1 |
2 |

{L_RS_GROUP_POWER_EXPLAIN}
3 |
4 |
-------------------------------------------------------------------------------- /styles/prosilver/template/event/viewtopic_body_postrow_custom_fields_before.html: -------------------------------------------------------------------------------- 1 | 2 |
{L_REPUTATION}: {postrow.USER_REPUTATION}
3 | 4 | -------------------------------------------------------------------------------- /styles/prosilver/template/event/memberlist_view_user_statistics_after.html: -------------------------------------------------------------------------------- 1 | 2 |
{L_REPUTATION}:
{USER_REPUTATION} [ {L_RS_VIEW_DETAILS} | {L_RS_RATE_USER} ]
3 | -------------------------------------------------------------------------------- /adm/style/event/acp_forums_normal_settings_append.html: -------------------------------------------------------------------------------- 1 |
2 |

{L_RS_FORUM_REPUTATION_EXPLAIN}
3 |

4 |
5 |
-------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "pico/reputation", 3 | "type": "phpbb-extension", 4 | "description": "An extension which adds reputations (karma) to your board.", 5 | "homepage": "https://github.com/Pico88/phpBB-Reputation-System", 6 | "version": "1.0.0-dev", 7 | "license": "GPL-2.0", 8 | "authors": [ 9 | { 10 | "name": "Lukasz Kaczynski", 11 | "username": "Pico88", 12 | "role": "Developer" 13 | } 14 | ], 15 | "require": { 16 | "php": ">=5.3.3" 17 | }, 18 | "extra": { 19 | "display-name": "Reputation System", 20 | "soft-require": { 21 | "phpbb/phpbb": ">=3.1.0-RC2,<3.2.*@dev" 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /exception/out_of_bounds.php: -------------------------------------------------------------------------------- 1 | translate_portions($user, $this->message_full, 'EXCEPTION_OUT_OF_BOUNDS'); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /exception/invalid_argument.php: -------------------------------------------------------------------------------- 1 | translate_portions($user, $this->message_full, 'EXCEPTION_INVALID_ARGUMENT'); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /styles/prosilver/template/event/index_body_stat_blocks_before.html: -------------------------------------------------------------------------------- 1 | 2 |
3 |

{L_RS_TOPLIST}

4 |

{L_RS_TOPLIST_EXPLAIN}{L_COLON} 5 | 6 | 7 | 8 | {L_RS_NEW_LINE} 9 | {toplist.USERNAME_FULL} 10 | ({toplist.USER_REPUTATION}){L_RS_NEW_LINE}{L_COMMA_SEPARATOR} 11 | 12 | 13 | 14 | {L_RS_NO_USERS} 15 | 16 |

17 |
18 | -------------------------------------------------------------------------------- /notification/type/rate_post_negative.php: -------------------------------------------------------------------------------- 1 | config['rs_version']); 18 | } 19 | 20 | public function revert_schema() 21 | { 22 | return array( 23 | 'drop_columns' => array( 24 | $this->table_prefix . 'forums' => array( 25 | 'enable_reputation', 26 | ), 27 | $this->table_prefix . 'users' => array( 28 | 'user_reputation', 29 | 'user_rep_new', 30 | 'user_rep_last', 31 | 'user_rs_notification', 32 | 'user_rs_default_power', 33 | ), 34 | $this->table_prefix . 'posts' => array( 35 | 'post_reputation', 36 | ), 37 | ), 38 | ); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /migrations/v10x/m4_initial_modules.php: -------------------------------------------------------------------------------- 1 | '\pico\reputation\acp\reputation_module', 30 | 'modes' => array('overview', 'settings', 'rate', 'sync'), 31 | ), 32 | )), 33 | ); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /styles/prosilver/template/event/mcp_warn_post_add_warning_field_after.html: -------------------------------------------------------------------------------- 1 | 2 |
3 |
4 | 5 |

{L_MCP_RS_ADD_WARNING}

6 |

{L_MCP_RS_ADD_WARNING_EXPLAIN}

7 | 8 |
9 |
10 |
11 |
16 |
17 |
18 |
19 | 20 |
21 |
22 |
 
23 |
24 |
25 |
26 | 27 |
28 |
29 | -------------------------------------------------------------------------------- /styles/prosilver/template/event/mcp_warn_user_add_warning_field_after.html: -------------------------------------------------------------------------------- 1 | 2 |
3 |
4 | 5 |

{L_MCP_RS_ADD_WARNING}

6 |

{L_MCP_RS_ADD_WARNING_EXPLAIN}

7 | 8 |
9 |
10 |
11 |
16 |
17 |
18 |
19 | 20 |
21 |
22 |
 
23 |
24 |
25 |
26 | 27 |
28 |
29 | -------------------------------------------------------------------------------- /controller/acp_interface.php: -------------------------------------------------------------------------------- 1 | '\pico\reputation\acp\reputation_module', 19 | 'title' => 'ACP_REPUTATION_SYSTEM', 20 | 'modes' => array( 21 | 'overview' => array('title' => 'ACP_REPUTATION_OVERVIEW', 'auth' => 'ext_pico/reputation && acl_a_reputation', 'cat' => array('ACP_REPUTATION_SYSTEM')), 22 | 'settings' => array('title' => 'ACP_REPUTATION_SETTINGS', 'auth' => 'ext_pico/reputation && acl_a_reputation', 'cat' => array('ACP_REPUTATION_SYSTEM')), 23 | 'rate' => array('title' => 'ACP_REPUTATION_RATE', 'auth' => 'ext_pico/reputation && acl_a_reputation', 'cat' => array('ACP_REPUTATION_SYSTEM')), 24 | 'sync' => array('title' => 'ACP_REPUTATION_SYNC', 'auth' => 'ext_pico/reputation && acl_a_reputation', 'display' => false, 'cat' => array('ACP_REPUTATION_SYSTEM')), 25 | ), 26 | ); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /core/reputation_power_interface.php: -------------------------------------------------------------------------------- 1 | config['rs_version']); 18 | } 19 | 20 | static public function depends_on() 21 | { 22 | return array( 23 | '\pico\reputation\migrations\converter\c3_remove_columns', 24 | '\pico\reputation\migrations\converter\c4_remove_modules', 25 | ); 26 | } 27 | 28 | public function update_data() 29 | { 30 | return array( 31 | array('config.remove', array('rs_post_highlight')), 32 | array('config.remove', array('rs_ranks_path')), 33 | array('config.remove', array('rs_ranks')), 34 | array('config.remove', array('rs_pm_notify')), 35 | array('config.remove', array('rs_notification')), 36 | array('config.remove', array('rs_hide_post')), 37 | array('config.remove', array('rs_hide_post')), 38 | array('config.remove', array('rs_hide_post')), 39 | array('config.remove', array('rs_version')), 40 | ); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /migrations/converter/c1_convert_table.php: -------------------------------------------------------------------------------- 1 | db_tools->sql_table_exists($this->table_prefix . 'reputations') || $this->db_tools->sql_column_exists($this->table_prefix . 'reputations', 'reputation_id'); 18 | } 19 | 20 | public function update_data() 21 | { 22 | return array( 23 | array('custom', array(array($this, 'rename_reputations_table'))), 24 | ); 25 | } 26 | 27 | public function rename_reputations_table() 28 | { 29 | switch($this->db->get_sql_layer()) 30 | { 31 | case 'mssql': 32 | case 'mssql_odbc': 33 | case 'mssqlnative': 34 | $sql = "EXEC sp_rename '{$this->table_prefix}reputations', '{$this->table_prefix}reputations_mod_backup'"; 35 | break; 36 | 37 | default: 38 | $sql = "ALTER TABLE {$this->table_prefix}reputations RENAME TO {$this->table_prefix}reputations_mod_backup"; 39 | break; 40 | } 41 | 42 | $this->db->sql_query($sql); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /migrations/v10x/m6_main_reputation_types.php: -------------------------------------------------------------------------------- 1 | table_prefix . 'reputation_types'; 18 | $result = $this->db->sql_query_limit($sql, 1); 19 | $row = $this->db->sql_fetchrow($result); 20 | 21 | return $row != false; 22 | } 23 | 24 | static public function depends_on() 25 | { 26 | return array('\pico\reputation\migrations\v10x\m1_initial_schema'); 27 | } 28 | 29 | public function update_data() 30 | { 31 | return array( 32 | array('custom', array(array($this, 'insert_reputation_types'))), 33 | ); 34 | } 35 | 36 | public function insert_reputation_types() 37 | { 38 | $reputation_types = array( 39 | array('reputation_type_name' => 'post'), 40 | array('reputation_type_name' => 'user'), 41 | array('reputation_type_name' => 'warning'), 42 | ); 43 | 44 | $this->db->sql_multi_insert($this->table_prefix . 'reputation_types', $reputation_types); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /styles/prosilver/theme/reputation_viewtopic.css: -------------------------------------------------------------------------------- 1 | .rate-good-icon:before { background-position: 0 0; } 2 | 3 | .rate-bad-icon:before { background-position: -15px 0; } 4 | 5 | .rate-good-icon:hover:before { background-position: 0 -21px; } 6 | 7 | .rate-bad-icon:hover:before { background-position: -15px -21px; } 8 | 9 | .rate-good-icon:before, .rate-bad-icon:before { background-image: url("./images/icons_rating.png"); } 10 | 11 | .own, .rate-good-icon.rated_bad, .rate-bad-icon.rated_good { display: none; } 12 | 13 | .rate-good-icon.rated_good:before { background-position: 0 -21px; } 14 | 15 | .rate-bad-icon.rated_bad:before { background-position: -15px -21px; } 16 | 17 | .user-reputation span { 18 | color: #536482; 19 | font-weight: normal; 20 | } 21 | 22 | .post-reputation { 23 | padding-bottom: 0; 24 | height: 16px; 25 | font-weight: bold; 26 | cursor: auto !important; 27 | } 28 | 29 | .post-reputation:hover { text-shadow: 0 0 #fff; } 30 | 31 | .post-reputation.positive span, .post-reputation.negative span { color: #fff; } 32 | 33 | .post-reputation.positive { background: #6F8F52; } 34 | 35 | .post-reputation.negative { background: #B82929; } 36 | 37 | .post-reputation.neutral span { color: #666666; } 38 | 39 | .reputation-avatar img { 40 | width: 40px; 41 | height: initial; 42 | } -------------------------------------------------------------------------------- /adm/style/reputation_settings.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 |

{L_ACP_REPUTATION_SETTINGS}

6 | 7 |

{L_ACP_REPUTATION_SETTINGS_EXPLAIN}

8 | 9 | 10 |
11 |

{L_WARNING}

12 |

{ERROR_MSG}

13 |
14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | {options.LEGEND} 25 | 26 | 27 |
28 |

{options.TITLE_EXPLAIN}
29 |
{options.CONTENT}
30 |
31 | 32 | 33 | 34 |
35 | 36 |
37 | {L_ACP_SUBMIT_CHANGES} 38 |

39 |   40 | 41 |

42 | {S_FORM_TOKEN} 43 |
44 |
45 | 46 | -------------------------------------------------------------------------------- /migrations/converter/c5_remove_permissions.php: -------------------------------------------------------------------------------- 1 | config['rs_version']); 18 | } 19 | 20 | public function update_data() 21 | { 22 | return array( 23 | array('if', array( 24 | array('permission.exists', array('f_rs_rate', false)), 25 | array('permission.remove', array('f_rs_rate')), 26 | )), 27 | array('if', array( 28 | array('permission.exists', array('f_rs_give_negative', false)), 29 | array('permission.remove', array('f_rs_rate')), 30 | )), 31 | array('if', array( 32 | array('permission.exists', array('m_rs_give', true)), 33 | array('permission.remove', array('m_rs_give')), 34 | )), 35 | array('if', array( 36 | array('permission.exists', array('u_rs_give', true)), 37 | array('permission.remove', array('u_rs_give')), 38 | )), 39 | array('if', array( 40 | array('permission.exists', array('u_rs_give_negative', true)), 41 | array('permission.remove', array('u_rs_give_negative')), 42 | )), 43 | ); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /core/reputation_helper.php: -------------------------------------------------------------------------------- 1 | 0) 37 | { 38 | return 'positive'; 39 | } 40 | else if ($points < 0) 41 | { 42 | return 'negative'; 43 | } 44 | else 45 | { 46 | return 'neutral'; 47 | } 48 | } 49 | 50 | /** 51 | * Avatar dimensions 52 | * 53 | * @param string $size Avatar size 54 | * @static 55 | * @access public 56 | * @return int Avatar dimension 57 | */ 58 | static public function avatar_dimensions($size) 59 | { 60 | switch ($size) 61 | { 62 | case 'small': 63 | return self::SMALL; 64 | break; 65 | 66 | case 'medium': 67 | return self::MEDIUM; 68 | break; 69 | } 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /language/en/reputation_toplist.php: -------------------------------------------------------------------------------- 1 | 'Reputation Toplist', 42 | 'RS_TOPLIST_EXPLAIN' => 'Most popular members', 43 | 44 | 'RS_NO_USERS' => 'there are no users to display', 45 | 46 | 'RS_NEW_LINE' => '
', 47 | )); 48 | -------------------------------------------------------------------------------- /adm/style/reputation_rate.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 |

{L_ACP_REPUTATION_RATE}

6 | 7 |

{L_ACP_REPUTATION_RATE_EXPLAIN}

8 | 9 | 10 |
11 |

{L_WARNING}

12 |

{ERROR_MSG}

13 |
14 | 15 | 16 |
17 | 18 |
19 |
20 |
21 |
22 |
[ {L_FIND_USERNAME} ]
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 | 33 |

34 |   35 | 36 |

37 | {S_FORM_TOKEN} 38 |
39 | 40 |
41 | 42 | -------------------------------------------------------------------------------- /acp/reputation_module.php: -------------------------------------------------------------------------------- 1 | add_lang_ext('pico/reputation', 'reputation_acp'); 23 | 24 | // Define acp controller 25 | $acp_controller = $phpbb_container->get('pico.reputation.acp.controller'); 26 | 27 | // Send url to acp controller 28 | $acp_controller->set_page_url($this->u_action); 29 | 30 | switch ($mode) 31 | { 32 | case 'overview': 33 | $this->tpl_name = 'reputation_overview'; 34 | 35 | $this->page_title = $user->lang('ACP_REPUTATION_OVERVIEW'); 36 | 37 | $acp_controller->display_overview(); 38 | break; 39 | 40 | case 'settings': 41 | $this->tpl_name = 'reputation_settings'; 42 | 43 | $this->page_title = $user->lang('ACP_REPUTATION_SETTINGS'); 44 | 45 | $acp_controller->manage_options(); 46 | break; 47 | 48 | case 'rate': 49 | $this->tpl_name = 'reputation_rate'; 50 | 51 | $this->page_title = $user->lang('ACP_REPUTATION_RATE'); 52 | 53 | $acp_controller->rate_user(); 54 | break; 55 | 56 | case 'sync': 57 | // ToDo 58 | trigger_error('ToDo'); 59 | break; 60 | } 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /styles/prosilver/template/event/viewtopic_body_post_buttons_before.html: -------------------------------------------------------------------------------- 1 | 2 | 3 |
  • 4 | {postrow.RS_RATE_POST_POSITIVE} 5 |
  • 6 | 7 | 8 |
  • 9 | {postrow.RS_RATE_POST_NEGATIVE} 10 |
  • 11 | 12 |
  • 13 | 14 | {postrow.POST_REPUTATION} 15 | 16 |
    {postrow.POST_REPUTATION}
    17 | 18 |
  • 19 | -------------------------------------------------------------------------------- /migrations/v10x/m5_initial_columns.php: -------------------------------------------------------------------------------- 1 | array( 24 | $this->table_prefix . 'forums' => array( 25 | 'reputation_enabled' => array('BOOL', 0), 26 | ), 27 | $this->table_prefix . 'groups' => array( 28 | 'group_reputation_power' => array('USINT', 0), 29 | ), 30 | $this->table_prefix . 'users' => array( 31 | 'user_reputation' => array('INT:11', 0), 32 | ), 33 | $this->table_prefix . 'posts' => array( 34 | 'post_reputation' => array('INT:11', 0), 35 | ), 36 | ), 37 | ); 38 | } 39 | 40 | public function revert_schema() 41 | { 42 | return array( 43 | 'drop_columns' => array( 44 | $this->table_prefix . 'forums' => array( 45 | 'reputation_enabled', 46 | ), 47 | $this->table_prefix . 'groups' => array( 48 | 'group_reputation_power', 49 | ), 50 | $this->table_prefix . 'users' => array( 51 | 'user_reputation', 52 | ), 53 | $this->table_prefix . 'posts' => array( 54 | 'post_reputation', 55 | ), 56 | ), 57 | ); 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /language/en/reputation_warning.php: -------------------------------------------------------------------------------- 1 | 'Reputation points for warning', 42 | 'MCP_RS_ADD_WARNING_EXPLAIN' => 'You can give negative reputation points to this user for a bad behaviour etc. This will only work if you have checked the checkbox below.', 43 | 'MCP_RS_ADD_REPUTATION' => 'Add reputation', 44 | 45 | 'MCP_RS_POINTS' => array( 46 | 1 => '-%d point', 47 | 2 => '-%d points', 48 | ), 49 | )); 50 | -------------------------------------------------------------------------------- /migrations/v10x/m3_initial_permissions.php: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 |
    data-referer="_referer={U_RS_REFERER}"> 6 |
    7 |
    8 | 9 |
    10 | 11 |
    12 |
    13 |
    14 |
    15 | {RS_POWER_POINTS_LEFT}
    16 |
    17 | 18 |
    19 |
    20 |
    25 |
    26 | 27 |
    28 |
    29 | 30 |
    {ERROR_MSG}
    31 |
    32 | 33 |
    34 | 35 |
    36 | 37 |   38 | 39 |
    40 | 41 |
    42 |
    43 |
    44 | 45 | 46 | 47 | -------------------------------------------------------------------------------- /adm/style/reputation_overview.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 |

    {L_ACP_REPUTATION_SYSTEM}

    6 | 7 |
    8 |
    9 |
    10 |
    11 |
    12 |
    13 |
    14 |

    15 |   16 | 17 |

    18 | {S_FORM_TOKEN} 19 |
    20 |
    21 | 22 |
    23 |
    24 |
    25 |

    {L_RS_SYNC_EXPLAIN}
    26 |
    27 |
    28 |
    29 | 30 |
    31 |
    32 |

    {L_RS_TRUNCATE_EXPLAIN}
    33 |
    34 |
    35 |
    36 | 37 |
    38 | 39 | -------------------------------------------------------------------------------- /language/en/exceptions.php: -------------------------------------------------------------------------------- 1 | 'required field missing', 53 | 'EXCEPTION_INVALID_ARGUMENT' => 'Invalid argument specified for `%1$s`. Reason: %2$s.', 54 | 'EXCEPTION_INVALID_TYPE' => 'reputation type does not exist', 55 | 'EXCEPTION_OUT_OF_BOUNDS' => 'The field `%1$s` received data beyond its bounds', 56 | )); 57 | -------------------------------------------------------------------------------- /styles/prosilver/template/ratepost.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 |
    data-referer="_referer={U_RS_REFERER}"> 6 |
    7 |
    8 | 9 |
    10 | 11 | 12 |
    13 |
    14 |
    15 |
    16 | {RS_POWER_POINTS_LEFT}
    17 |
    18 | 19 | 20 |
    21 |
    22 |
    27 |
    28 | 29 | 30 | 31 |
    32 |
    33 | 34 |
    {ERROR_MSG}
    35 |
    36 | 37 |
    38 | 39 |
    40 | 41 |   42 | 43 |
    44 | 45 |
    46 |
    47 |
    48 | 49 | 50 | 51 | -------------------------------------------------------------------------------- /config/listeners.yml: -------------------------------------------------------------------------------- 1 | services: 2 | pico.reputation.acp_listener: 3 | class: pico\reputation\event\acp_listener 4 | arguments: 5 | - @request 6 | - @template 7 | tags: 8 | - { name: event.listener } 9 | 10 | pico.reputation.index_listener: 11 | class: pico\reputation\event\index_listener 12 | arguments: 13 | - @auth 14 | - @config 15 | - @dbal.conn 16 | - @controller.helper 17 | - @template 18 | - @user 19 | tags: 20 | - { name: event.listener } 21 | 22 | pico.reputation.main_listener: 23 | class: pico\reputation\event\main_listener 24 | arguments: 25 | - @config 26 | - @template 27 | tags: 28 | - { name: event.listener } 29 | 30 | pico.reputation.mcp_listener: 31 | class: pico\reputation\event\mcp_listener 32 | arguments: 33 | - @auth 34 | - @config 35 | - @request 36 | - @template 37 | - @user 38 | - @pico.reputation.manager 39 | tags: 40 | - { name: event.listener } 41 | 42 | pico.reputation.memberlist_listener: 43 | class: pico\reputation\event\memberlist_listener 44 | arguments: 45 | - @auth 46 | - @config 47 | - @controller.helper 48 | tags: 49 | - { name: event.listener } 50 | 51 | pico.reputation.viewtopic_listener: 52 | class: pico\reputation\event\viewtopic_listener 53 | arguments: 54 | - @auth 55 | - @config 56 | - @controller.helper 57 | - @template 58 | - @user 59 | - @pico.reputation.helper 60 | - %tables.reputations% 61 | tags: 62 | - { name: event.listener } -------------------------------------------------------------------------------- /migrations/converter/c4_remove_modules.php: -------------------------------------------------------------------------------- 1 | config['rs_version']); 18 | } 19 | 20 | public function update_data() 21 | { 22 | return array( 23 | array('if', array( 24 | array('module.exists', array('acp', false, 'ACP_REPUTATION_SYSTEM')), 25 | array('module.remove', array('acp', false, 'ACP_REPUTATION_OVERVIEW')), 26 | array('module.remove', array('acp', false, 'ACP_REPUTATION_SETTINGS')), 27 | array('module.remove', array('acp', false, 'ACP_REPUTATION_RANKS')), 28 | array('module.remove', array('acp', false, 'ACP_REPUTATION_GIVE')), 29 | array('module.remove', array('acp', false, 'ACP_REPUTATION_SYSTEM')), 30 | )), 31 | array('if', array( 32 | array('module.exists', array('mcp', false, 'MCP_REPUTATION')), 33 | array('module.remove', array('mcp', false, 'MCP_REPUTATION_FRONT')), 34 | array('module.remove', array('mcp', false, 'MCP_REPUTATION_LIST')), 35 | array('module.remove', array('mcp', false, 'MCP_REPUTATION_GIVE')), 36 | array('module.remove', array('mcp', false, 'MCP_REPUTATION')), 37 | )), 38 | array('if', array( 39 | array('module.exists', array('ucp', false, 'UCP_REPUTATION')), 40 | array('module.remove', array('ucp', false, 'UCP_REPUTATION_FRONT')), 41 | array('module.remove', array('ucp', false, 'UCP_REPUTATION_LIST')), 42 | array('module.remove', array('ucp', false, 'UCP_REPUTATION_GIVEN')), 43 | array('module.remove', array('ucp', false, 'UCP_REPUTATION_SETTING')), 44 | array('module.remove', array('ucp', false, 'UCP_REPUTATION')), 45 | )), 46 | ); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /language/en/reputation_common.php: -------------------------------------------------------------------------------- 1 | 'Reputation', 42 | 43 | 'RS_DISABLED' => 'Sorry, but the board administrator has disabled this feature.', 44 | 45 | 'RS_COMMENT' => 'Comment', 46 | 'RS_POINTS' => 'Points', 47 | 48 | 'RS_POST_REPUTATION' => 'Post reputation', 49 | 'RS_POST_RATED' => 'You have rated this post', 50 | 'RS_RATE_POST_POSITIVE' => 'Rate post positive', 51 | 'RS_RATE_POST_NEGATIVE' => 'Rate post negative', 52 | 'RS_RATE_USER' => 'Rate user', 53 | 'RS_VIEW_DETAILS' => 'View details', 54 | 55 | 'NOTIFICATION_TYPE_REPUTATION' => 'Someone gives you reputation point', 56 | 'NOTIFICATION_RATE_POST_POSITIVE' => 'Rated positively by %s for post', 57 | 'NOTIFICATION_RATE_POST_NEGATIVE' => 'Rated negatively by %s for post', 58 | 'NOTIFICATION_RATE_USER' => 'Rated by %s', 59 | )); 60 | -------------------------------------------------------------------------------- /migrations/v10x/m1_initial_schema.php: -------------------------------------------------------------------------------- 1 | array( 24 | $this->table_prefix . 'reputations' => array( 25 | 'COLUMNS' => array( 26 | 'reputation_id' => array('UINT', null, 'auto_increment'), 27 | 'user_id_from' => array('UINT', 0), 28 | 'user_id_to' => array('UINT', 0), 29 | 'reputation_time' => array('TIMESTAMP', 0), 30 | 'reputation_type_id' => array('USINT', 0), 31 | 'reputation_item_id' => array('UINT', 0), 32 | 'reputation_points' => array('INT:11', 0), 33 | 'reputation_comment' => array('TEXT_UNI', ''), 34 | ), 35 | 'PRIMARY_KEY' => 'reputation_id', 36 | 'KEYS' => array( 37 | 'user_id_from' => array('INDEX', 'user_id_from'), 38 | 'user_id_to' => array('INDEX', 'user_id_to'), 39 | 'item_id' => array('INDEX', 'reputation_item_id'), 40 | ), 41 | ), 42 | $this->table_prefix . 'reputation_types' => array( 43 | 'COLUMNS' => array( 44 | 'reputation_type_id' => array('UINT', null, 'auto_increment'), 45 | 'reputation_type_name' => array('VCHAR:20', ''), 46 | ), 47 | 'PRIMARY_KEY' => 'reputation_type_id', 48 | 'KEYS' => array( 49 | 'type' => array('INDEX', 'reputation_type_name'), 50 | ), 51 | ), 52 | ), 53 | ); 54 | } 55 | 56 | public function revert_schema() 57 | { 58 | return array( 59 | 'drop_tables' => array( 60 | $this->table_prefix . 'reputations', 61 | $this->table_prefix . 'reputation_types', 62 | ), 63 | ); 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /config/notifications.yml: -------------------------------------------------------------------------------- 1 | services: 2 | pico.reputation.notification.type.rate_post_positive: 3 | class: pico\reputation\notification\type\rate_post_positive 4 | scope: prototype # scope MUST be prototype for this to work! 5 | arguments: 6 | - @user_loader 7 | - @dbal.conn 8 | - @cache.driver 9 | - @user 10 | - @auth 11 | - @config 12 | - %core.root_path% 13 | - %core.php_ext% 14 | - %tables.notification_types% 15 | - %tables.notifications% 16 | - %tables.user_notifications% 17 | tags: 18 | - { name: notification.type } 19 | 20 | pico.reputation.notification.type.rate_post_negative: 21 | class: pico\reputation\notification\type\rate_post_negative 22 | scope: prototype # scope MUST be prototype for this to work! 23 | arguments: 24 | - @user_loader 25 | - @dbal.conn 26 | - @cache.driver 27 | - @user 28 | - @auth 29 | - @config 30 | - %core.root_path% 31 | - %core.php_ext% 32 | - %tables.notification_types% 33 | - %tables.notifications% 34 | - %tables.user_notifications% 35 | tags: 36 | - { name: notification.type } 37 | 38 | pico.reputation.notification.type.rate_user: 39 | class: pico\reputation\notification\type\rate_user 40 | scope: prototype # scope MUST be prototype for this to work! 41 | arguments: 42 | - @user_loader 43 | - @dbal.conn 44 | - @cache.driver 45 | - @user 46 | - @auth 47 | - @config 48 | - @controller.helper 49 | - %core.root_path% 50 | - %core.php_ext% 51 | - %tables.notification_types% 52 | - %tables.notifications% 53 | - %tables.user_notifications% 54 | tags: 55 | - { name: notification.type } -------------------------------------------------------------------------------- /language/en/permissions_reputation.php: -------------------------------------------------------------------------------- 1 | 'Reputation', 42 | 43 | 'ACL_A_REPUTATION' => 'Can manage reputation settings', 44 | 45 | 'ACL_M_RS_MODERATE' => 'Can moderate reputation points', 46 | 'ACL_M_RS_RATE' => 'Can award additional reputation points', 47 | 48 | 'ACL_U_RS_DELETE' => 'Can delete given points', 49 | 'ACL_U_RS_RATE' => 'Can rate other users', 50 | 'ACL_U_RS_RATE_NEGATIVE' => 'Can negatively rate other users
    User has to be able to rate other users before he/she can negatively rate other users.', 51 | 'ACL_U_RS_RATE_POST' => 'Can rate posts made by other users', 52 | 'ACL_U_RS_VIEW' => 'Can view reputation', 53 | 54 | 'ACL_F_RS_RATE' => 'Can rate posts made by other users', 55 | 'ACL_F_RS_RATE_NEGATIVE' => 'Can negatively rate posts made by other users
    User has to be able to rate posts before he/she can negatively rate posts made by other users.', 56 | )); 57 | -------------------------------------------------------------------------------- /event/main_listener.php: -------------------------------------------------------------------------------- 1 | config = $config; 37 | $this->template = $template; 38 | } 39 | 40 | /** 41 | * Assign functions defined in this class to event listeners in the core 42 | * 43 | * @return array 44 | * @static 45 | * @access public 46 | */ 47 | static public function getSubscribedEvents() 48 | { 49 | return array( 50 | 'core.common' => 'reputation_status', 51 | 'core.user_setup' => 'load_language_on_setup', 52 | ); 53 | } 54 | 55 | /** 56 | * Check if Reputation System is enabled or disabled 57 | * 58 | * @return null 59 | * @access public 60 | */ 61 | public function reputation_status() 62 | { 63 | $this->template->assign_vars(array( 64 | 'S_REPUTATION' => $this->config['rs_enable'] ? true : false, 65 | )); 66 | } 67 | 68 | /** 69 | * Load common reputation language files during user setup 70 | * 71 | * @param object $event The event object 72 | * @return null 73 | * @access public 74 | */ 75 | public function load_language_on_setup($event) 76 | { 77 | $lang_set_ext = $event['lang_set_ext']; 78 | $lang_set_ext[] = array( 79 | 'ext_name' => 'pico/reputation', 80 | 'lang_set' => 'reputation_common', 81 | ); 82 | $event['lang_set_ext'] = $lang_set_ext; 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /config/routing.yml: -------------------------------------------------------------------------------- 1 | reputation_clear_post_controller: 2 | pattern: /reputation/clear/post/{post_id} 3 | defaults: { _controller: pico.reputation.action.controller:clear_post } 4 | requirements: 5 | post_id: \d+ 6 | 7 | reputation_clear_user_controller: 8 | pattern: /reputation/clear/user/{uid} 9 | defaults: { _controller: pico.reputation.action.controller:clear_user } 10 | requirements: 11 | uid: \d+ 12 | 13 | reputation_delete_controller: 14 | pattern: /reputation/delete/{rid} 15 | defaults: { _controller: pico.reputation.action.controller:delete } 16 | requirements: 17 | rid: \d+ 18 | 19 | reputation_details_controller: 20 | pattern: /reputation/{uid}/{sort_key}/{sort_dir}/{page} 21 | defaults: { _controller: pico.reputation.details.controller:details, sort_key: id, sort_dir: dsc, page: 1 } 22 | requirements: 23 | uid: \d+ 24 | sort_key: id|username|time|point|action 25 | sort_dir: asc|dsc 26 | 27 | reputation_post_details_controller: 28 | pattern: /reputation/details/post/{post_id}/{sort_key}/{sort_dir} 29 | defaults: { _controller: pico.reputation.details.controller:postdetails, sort_key: id, sort_dir: dsc } 30 | requirements: 31 | post_id: \d+ 32 | sort_key: id|username|time|point 33 | sort_dir: asc|dsc 34 | 35 | reputation_post_rating_controller: 36 | pattern: /reputation/rate/post/{mode}/{post_id} 37 | defaults: { _controller: pico.reputation.rating.controller:post } 38 | requirements: 39 | mode: positive|negative 40 | post_id: \d+ 41 | 42 | reputation_user_details_controller: 43 | pattern: /reputation/details/user/{uid}/{sort_key}/{sort_dir} 44 | defaults: { _controller: pico.reputation.details.controller:userdetails, sort_key: id, sort_dir: dsc } 45 | requirements: 46 | uid: \d+ 47 | sort_key: id|username|time|point|action 48 | sort_dir: asc|dsc 49 | 50 | reputation_user_rating_controller: 51 | pattern: /reputation/rate/user/{uid} 52 | defaults: { _controller: pico.reputation.rating.controller:user } 53 | requirements: 54 | uid: \d+ 55 | -------------------------------------------------------------------------------- /core/reputation_manager_interface.php: -------------------------------------------------------------------------------- 1 | Manage extensions`. 22 | 6. Look for `Reputation System` under the Disabled Extensions list, and click its `Enable` link. 23 | 7. Set up and configure Reputation System by navigating in the ACP to `Extensions` -> `Reputation System`. 24 | 25 | ## Uninstall 26 | 1. Navigate in the ACP to `Customise -> Extension Management -> Extensions`. 27 | 2. Look for `Reputation System` under the Enabled Extensions list, and click its `Disable` link. 28 | 3. To permanently uninstall, click `Delete Data` and then delete the `/ext/pico/reputation` folder. 29 | 30 | ## To-Do List 31 | - [x] Link to post on details pages 32 | - [x] Group reputation power 33 | - [x] Delete reputation 34 | - [x] Clear user/post reputations 35 | - [ ] ACP synchronization functions 36 | - [ ] MCP reputation modules 37 | - [ ] UCP reputation modules 38 | - [x] Notifications 39 | - [ ] Responsive design 40 | - [ ] Reputation ranks 41 | - [x] Updater from version for phpBB 3.0.x to release for phpBB 3.1.x - in progress (testing phase) 42 | 43 | ## License 44 | [GNU General Public License v2](http://opensource.org/licenses/GPL-2.0) 45 | -------------------------------------------------------------------------------- /styles/prosilver/template/postdetails.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 |

    {L_RS_POST_REPUTATION} - {POST_SUBJECT}

    6 | 7 |

    {L_POST} {L_POST_BY_AUTHOR} {POST_AUTHOR}

    8 | 9 |
    10 | 11 | 12 |
    13 | 14 |
    15 | 16 | {reputation.AVATAR} 17 | 18 | 19 | 20 |
    21 | 22 |
    23 | {L_DELETE} 24 |
    {reputation.POINTS}
    25 |
    {reputation.USERNAME} » {reputation.TIME}
    26 | 27 |
    28 | {L_RS_COMMENT}: 29 |
    {reputation.COMMENT}
    30 |
    31 | 32 |
    33 |
    34 | 35 | 36 |
    37 | {L_RS_EMPTY_DATA} 38 |
    39 | 40 |
    41 | 42 | 43 | 50 | 51 | 52 | 53 | 54 | -------------------------------------------------------------------------------- /language/en/info_acp_reputation.php: -------------------------------------------------------------------------------- 1 | 'Reputation System', 42 | 'ACP_REPUTATION_OVERVIEW' => 'Overview', 43 | 'ACP_REPUTATION_SETTINGS' => 'Settings', 44 | 'ACP_REPUTATION_RATE' => 'Rate', 45 | 'ACP_REPUTATION_SYNC' => 'Synchronise', 46 | 47 | 'RS_FORUM_REPUTATION' => 'Enable post rating (reputation)', 48 | 'RS_FORUM_REPUTATION_EXPLAIN' => 'Allow members to rate posts made by other users in that forum.', 49 | 50 | 'RS_GROUP_POWER' => 'Group reputation power', 51 | 'RS_GROUP_POWER_EXPLAIN' => 'If this field is filled, the reputation power of members will be overwritten and will not be based on posts etc.', 52 | 53 | 'LOG_REPUTATION_DELETED' => 'Deleted reputation
    From user: %1$s
    To user: %2$s
    Points: %3$s
    Type: %4$s
    Item ID: %5$s', 54 | 'LOG_POST_REPUTATION_CLEARED' => 'Cleared post reputation
    Post author: %1$s
    Post subject: %2$s', 55 | 'LOG_USER_REPUTATION_CLEARED' => 'Cleared user reputation
    User: %1$s', 56 | 'LOG_REPUTATION_SYNC' => 'Reputation System resynchronised', 57 | 'LOG_REPUTATION_TRUNCATE' => 'Cleared reputations', 58 | )); 59 | -------------------------------------------------------------------------------- /migrations/v10x/m2_initial_data.php: -------------------------------------------------------------------------------- 1 | auth = $auth; 41 | $this->config = $config; 42 | $this->helper = $helper; 43 | } 44 | 45 | /** 46 | * Assign functions defined in this class to event listeners in the core 47 | * 48 | * @return array 49 | * @static 50 | * @access public 51 | */ 52 | static public function getSubscribedEvents() 53 | { 54 | return array( 55 | 'core.memberlist_prepare_profile_data' => 'prepare_user_reputation_data', 56 | ); 57 | } 58 | 59 | /** 60 | * Display user reputation on user profile page 61 | * 62 | * @param object $event The event object 63 | * @return null 64 | * @access public 65 | */ 66 | public function prepare_user_reputation_data($event) 67 | { 68 | $data = $event['data']; 69 | $template_data = $event['template_data']; 70 | 71 | $template_data = array_merge($template_data, array( 72 | 'USER_REPUTATION' => $data['user_reputation'], 73 | 74 | 'U_VIEW_USER_REPUTATION' => $this->helper->route('reputation_details_controller', array('uid' => $data['user_id'])), 75 | 'U_RATE_USER' => $this->helper->route('reputation_user_rating_controller', array('uid' => $data['user_id'])), 76 | 'U_REPUTATION_REFERER' => $this->helper->get_current_url(), 77 | 78 | 'S_RATE_USER' => ($this->config['rs_user_rating'] && $this->auth->acl_get('u_rs_rate')) ? true : false, 79 | 'S_VIEW_REPUTATION' => ($this->auth->acl_get('u_rs_view')) ? true : false, 80 | )); 81 | 82 | $event['template_data'] = $template_data; 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /styles/prosilver/template/userdetails.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 |

    {L_RS_USER_REPUTATION} {L_RS_MORE_DETAILS}

    6 | 7 |
    8 | 9 | 10 |
    11 | 12 |
    13 | 14 | {reputation.AVATAR} 15 | 16 | 17 | 18 |
    19 | 20 |
    21 | {L_DELETE} 22 |
    {reputation.POINTS}
    23 |
    {reputation.USERNAME} » {reputation.TIME}
    24 |
    25 | {reputation.ACTION} 26 | 27 | 28 |
    » 29 | 30 | {reputation.post.POST_SUBJECT} 31 | 32 | 33 | 34 |
    35 | 36 |
    37 | {L_RS_COMMENT}: 38 |
    {reputation.COMMENT}
    39 |
    40 | 41 |
    42 |
    43 | 44 | 45 |
    46 | {L_RS_EMPTY_DATA} 47 |
    48 | 49 |
    50 | 51 | 52 | 60 | 61 | 62 | 63 | 64 | -------------------------------------------------------------------------------- /language/en/reputation_rating.php: -------------------------------------------------------------------------------- 1 | 'You cannot give reputation points so soon. You may try again later.', 42 | 'RS_COMMENT_TOO_LONG' => 'Your comment contains %1$s characters and is too long.
    The maximum allowed characters: %2$s.', 43 | 'RS_NEGATIVE' => 'Negative', 44 | 'RS_NO_COMMENT' => 'You cannot leave the comment field blank.', 45 | 'RS_NO_POST' => 'There is no such post.', 46 | 'RS_NO_POWER' => 'Your reputation power is too low.', 47 | 'RS_NO_POWER_LEFT' => 'Not enough reputation power points.
    Wait until they renew.
    Your reputation power is %s', 48 | 'RS_NO_USER_ID' => 'The requested user does not exist.', 49 | 'RS_POSITIVE' => 'Positive', 50 | 'RS_POST_RATING' => 'Rating post', 51 | 'RS_RATE_BUTTON' => 'Rate', 52 | 'RS_SAME_POST' => 'You have already rated this post.
    You gave %s reputation points.', 53 | 'RS_SAME_USER' => 'You have already rated this user.', 54 | 'RS_SELF' => 'You cannot give reputation points to yourself', 55 | 'RS_USER_ANONYMOUS' => 'You are not allowed to give reputation points to anonymous users.', 56 | 'RS_USER_BANNED' => 'You are not allowed to give reputation points to banned users.', 57 | 'RS_USER_CANNOT_DELETE' => 'You do not have permission to delete that reputation.', 58 | 'RS_USER_DISABLED' => 'You are not allowed to give reputation point.', 59 | 'RS_USER_GAP' => 'You cannot rate the same user so soon. You can try again in %s.', 60 | 'RS_USER_NEGATIVE' => 'You are not allowed to give negative reputation points.
    Your reputation has to be higher than %s.', 61 | 'RS_USER_RATING' => 'Rating user', 62 | 'RS_VIEW_DISALLOWED' => 'You are not allowed to view reputation points.', 63 | 'RS_VOTE_POWER_LEFT_OF_MAX' => '%1$d reputation power points left of %2$d.
    Maximum per vote: %3$d', 64 | 'RS_VOTE_SAVED' => 'Vote saved', 65 | 'RS_WARNING_RATING' => 'Warning', 66 | )); 67 | -------------------------------------------------------------------------------- /migrations/converter/c2_convert_data.php: -------------------------------------------------------------------------------- 1 | 7 | * @license GNU General Public License, version 2 (GPL-2.0) 8 | * 9 | */ 10 | 11 | namespace pico\reputation\migrations\converter; 12 | 13 | class c2_convert_data extends \phpbb\db\migration\migration 14 | { 15 | 16 | public function effectively_installed() 17 | { 18 | return !$this->db_tools->sql_table_exists($this->table_prefix . 'reputations_mod_backup'); 19 | } 20 | 21 | static public function depends_on() 22 | { 23 | return array( 24 | '\pico\reputation\migrations\converter\c1_convert_table', 25 | '\pico\reputation\migrations\v10x\m1_initial_schema', 26 | '\pico\reputation\migrations\v10x\m6_main_reputation_types', 27 | ); 28 | } 29 | 30 | public function update_data() 31 | { 32 | return array( 33 | array('custom', array(array($this, 'convert_reputations_data'))), 34 | ); 35 | } 36 | 37 | public function convert_reputations_data() 38 | { 39 | $types = $import_data = array(); 40 | 41 | $sql = 'SELECT * FROM ' . $this->table_prefix . 'reputation_types'; 42 | $result = $this->db->sql_query($sql); 43 | while ($row = $this->db->sql_fetchrow($result)) 44 | { 45 | $types[(string) $row['reputation_type_name']] = (int) $row['reputation_type_id']; 46 | } 47 | $this->db->sql_freeresult($result); 48 | 49 | $actions = array( 50 | 1 => 'post', 51 | 2 => 'user', 52 | 3 => 'warning', 53 | 4 => 'ban', 54 | 5 => 'likes', 55 | ); 56 | 57 | $sql = 'SELECT * FROM ' . $this->table_prefix . 'reputations_mod_backup'; 58 | $result = $this->db->sql_query($sql); 59 | 60 | while ($row = $this->db->sql_fetchrow($result)) 61 | { 62 | $action = $actions[$row['action']]; 63 | 64 | if (!isset($types[$action])) 65 | { 66 | continue; 67 | } 68 | 69 | $import_data[$row['rep_id']]['user_id_from'] = isset($row['rep_from']) ? (int) $row['rep_from'] : 0; 70 | $import_data[$row['rep_id']]['user_id_to'] = isset($row['rep_to']) ? (int) $row['rep_to'] : 0; 71 | $import_data[$row['rep_id']]['reputation_time'] = isset($row['time']) ? $row['time'] : 0; 72 | $import_data[$row['rep_id']]['reputation_type_id'] = isset($row['action']) ? (int) $types[$action] : 0; 73 | $import_data[$row['rep_id']]['reputation_item_id'] = (isset($row['post_id']) && ($action == 'post' || $action == 'likes')) ? (int) $row['post_id'] : 0; 74 | $import_data[$row['rep_id']]['reputation_points'] = isset($row['point']) ? $row['point'] : 0; 75 | $import_data[$row['rep_id']]['reputation_comment'] = isset($row['comment']) ? $row['comment'] : ''; 76 | } 77 | $this->db->sql_freeresult($result); 78 | 79 | if (!empty($import_data)) 80 | { 81 | $insert_buffer = new \phpbb\db\sql_insert_buffer($this->db, $this->table_prefix . 'reputations'); 82 | 83 | foreach ($import_data as $reputation_data) 84 | { 85 | $insert_buffer->insert($reputation_data); 86 | } 87 | 88 | $insert_buffer->flush(); 89 | } 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /config/services.yml: -------------------------------------------------------------------------------- 1 | imports: 2 | - { resource: listeners.yml} 3 | - { resource: notifications.yml} 4 | - { resource: tables.yml } 5 | 6 | services: 7 | pico.reputation.acp.controller: 8 | class: pico\reputation\controller\acp_controller 9 | arguments: 10 | - @config 11 | - @dbal.conn 12 | - @request 13 | - @template 14 | - @user 15 | - @pico.reputation.manager 16 | - %tables.reputations% 17 | - %core.root_path% 18 | - %core.adm_relative_path% 19 | - %core.php_ext% 20 | 21 | pico.reputation.action.controller: 22 | class: pico\reputation\controller\action_controller 23 | arguments: 24 | - @auth 25 | - @controller.helper 26 | - @dbal.conn 27 | - @request 28 | - @user 29 | - @pico.reputation.helper 30 | - @pico.reputation.manager 31 | - %tables.reputations% 32 | - %tables.reputation_types% 33 | - %core.root_path% 34 | - %core.php_ext% 35 | 36 | pico.reputation.details.controller: 37 | class: pico\reputation\controller\details_controller 38 | arguments: 39 | - @auth 40 | - @config 41 | - @controller.helper 42 | - @dbal.conn 43 | - @pagination 44 | - @request 45 | - @symfony_request 46 | - @template 47 | - @user 48 | - @pico.reputation.helper 49 | - @pico.reputation.manager 50 | - @pico.reputation.power 51 | - %tables.reputations% 52 | - %tables.reputation_types% 53 | - %core.root_path% 54 | - %core.php_ext% 55 | 56 | pico.reputation.rating.controller: 57 | class: pico\reputation\controller\rating_controller 58 | arguments: 59 | - @auth 60 | - @config 61 | - @controller.helper 62 | - @dbal.conn 63 | - @request 64 | - @symfony_request 65 | - @template 66 | - @user 67 | - @pico.reputation.helper 68 | - @pico.reputation.manager 69 | - @pico.reputation.power 70 | - %tables.reputations% 71 | - %core.root_path% 72 | - %core.php_ext% 73 | 74 | pico.reputation.helper: 75 | class: pico\reputation\core\reputation_helper 76 | 77 | pico.reputation.manager: 78 | class: pico\reputation\core\reputation_manager 79 | arguments: 80 | - @auth 81 | - @cache 82 | - @config 83 | - @dbal.conn 84 | - @log 85 | - @notification_manager 86 | - @template 87 | - @user 88 | - %tables.reputations% 89 | - %tables.reputation_types% 90 | - %core.root_path% 91 | - %core.php_ext% 92 | 93 | pico.reputation.power: 94 | class: pico\reputation\core\reputation_power 95 | arguments: 96 | - @config 97 | - @dbal.conn 98 | - %tables.reputations% -------------------------------------------------------------------------------- /ext.php: -------------------------------------------------------------------------------- 1 | container->get('notification_manager'); 38 | foreach ($this->reputation_notification_types as $reputation_notification_type) 39 | { 40 | $phpbb_notifications->enable_notifications($reputation_notification_type); 41 | } 42 | return 'notifications'; 43 | break; 44 | default: 45 | // Run parent enable step method 46 | return parent::enable_step($old_state); 47 | break; 48 | } 49 | } 50 | /** 51 | * Overwrite disable_step to disable reputation notifications 52 | * before the extension is disabled. 53 | * 54 | * @param mixed $old_state State returned by previous call of this method 55 | * @return mixed Returns false after last step, otherwise temporary state 56 | */ 57 | function disable_step($old_state) 58 | { 59 | switch ($old_state) 60 | { 61 | case '': // Empty means nothing has run yet 62 | // Disable reputation notifications 63 | $phpbb_notifications = $this->container->get('notification_manager'); 64 | foreach ($this->reputation_notification_types as $reputation_notification_type) 65 | { 66 | $phpbb_notifications->disable_notifications($reputation_notification_type); 67 | } 68 | return 'notifications'; 69 | break; 70 | default: 71 | // Run parent disable step method 72 | return parent::disable_step($old_state); 73 | break; 74 | } 75 | } 76 | /** 77 | * Overwrite purge_step to purge reputation notifications before 78 | * any included and installed migrations are reverted. 79 | * 80 | * @param mixed $old_state State returned by previous call of this method 81 | * @return mixed Returns false after last step, otherwise temporary state 82 | */ 83 | function purge_step($old_state) 84 | { 85 | switch ($old_state) 86 | { 87 | case '': // Empty means nothing has run yet 88 | // Purge reputation notifications 89 | $phpbb_notifications = $this->container->get('notification_manager'); 90 | foreach ($this->reputation_notification_types as $reputation_notification_type) 91 | { 92 | $phpbb_notifications->purge_notifications($reputation_notification_type); 93 | } 94 | return 'notifications'; 95 | break; 96 | default: 97 | // Run parent purge step method 98 | return parent::purge_step($old_state); 99 | break; 100 | } 101 | } 102 | } 103 | -------------------------------------------------------------------------------- /event/index_listener.php: -------------------------------------------------------------------------------- 1 | auth = $auth; 53 | $this->config = $config; 54 | $this->db = $db; 55 | $this->helper = $helper; 56 | $this->template = $template; 57 | $this->user = $user; 58 | } 59 | 60 | /** 61 | * Assign functions defined in this class to event listeners in the core 62 | * 63 | * @return array 64 | * @static 65 | * @access public 66 | */ 67 | static public function getSubscribedEvents() 68 | { 69 | return array( 70 | 'core.index_modify_page_title' => 'reputation_toplist', 71 | ); 72 | } 73 | 74 | /** 75 | * Display reputation toplist 76 | * 77 | * @return null 78 | * @access public 79 | */ 80 | public function reputation_toplist() 81 | { 82 | if ($this->config['rs_enable'] && $this->config['rs_enable_toplist'] && $this->config['rs_toplist_num']) 83 | { 84 | $this->user->add_lang_ext('pico/reputation', 'reputation_toplist'); 85 | 86 | $sql = 'SELECT user_id, username, user_colour, user_reputation 87 | FROM ' . USERS_TABLE . ' 88 | WHERE user_reputation > 0 89 | ORDER BY user_reputation DESC'; 90 | $result = $this->db->sql_query_limit($sql, $this->config['rs_toplist_num']); 91 | 92 | while ($row = $this->db->sql_fetchrow($result)) 93 | { 94 | $this->template->assign_block_vars('toplist', array( 95 | 'USERNAME_FULL' => get_username_string('full', $row['user_id'], $row['username'], $row['user_colour']), 96 | 'USER_REPUTATION' => $row['user_reputation'], 97 | 98 | 'U_VIEW_USER_REPUTATION' => $this->helper->route('reputation_details_controller', array('uid' => $row['user_id'])), 99 | 100 | 'S_DIRECTION' => ($this->config['rs_toplist_direction']) ? true : false, 101 | )); 102 | } 103 | $this->db->sql_freeresult($result); 104 | 105 | $this->template->assign_vars(array( 106 | 'S_RS_TOPLIST' => true, 107 | 'S_VIEW_REPUTATION' => ($this->auth->acl_get('u_rs_view')) ? true : false, 108 | )); 109 | } 110 | } 111 | } 112 | -------------------------------------------------------------------------------- /language/en/reputation_system.php: -------------------------------------------------------------------------------- 1 | 'Reputation System', 41 | 42 | 'RS_ACTION' => 'Action', 43 | 'RS_DATE' => 'Date', 44 | 'RS_DETAILS' => 'User reputation details', 45 | 'RS_FROM' => 'From', 46 | 'RS_LIST' => 'User reputation points list', 47 | 'RS_POST_COUNT' => 'Points for post', 48 | 'RS_POST_REPUTATION' => 'Post reputation', 49 | 'RS_USER_COUNT' => 'Points from user', 50 | 'RS_POSITIVE_COUNT' => 'Positive', 51 | 'RS_NEGATIVE_COUNT' => 'Negative', 52 | 'RS_STATS' => 'Statistics', 53 | 'RS_WEEK' => 'Last week', 54 | 'RS_MONTH' => 'Last month', 55 | 'RS_6MONTHS' => 'Last 6 months', 56 | 'RS_POINT' => 'Point', 57 | 'RS_POINTS_TITLE' => array( 58 | 1 => 'Point: %d', 59 | 2 => 'Points: %d', 60 | ), 61 | 'RS_POST_DELETE' => 'Post deleted', 62 | 'RS_POWER' => 'Reputation power', 63 | 'RS_TIME' => 'Time', 64 | 'RS_TO' => 'to', 65 | 'RS_TO_USER' => 'To', 66 | 'RS_VOTING_POWER' => 'Remaining power points', 67 | 68 | 'RS_EMPTY_DATA' => 'There are no reputation points.', 69 | 'RS_NA' => 'n/a', 70 | 'RS_NO_ID' => 'No ID', 71 | 'RS_NO_REPUTATION' => 'There is no such reputation.', 72 | 73 | 'NO_REPUTATION_SELECTED' => 'You did not select reputation point.', 74 | 75 | 'RS_REPUTATION_DELETE_CONFIRM' => 'Do you really want to delete this reputation?', 76 | 'RS_REPUTATIONS_DELETE_CONFIRM' => 'Do you really want to delete these reputation?', 77 | 'RS_POINTS_DELETED' => array( 78 | 1 => 'The reputation has been deleted.', 79 | 2 => 'The reputations have been deleted.', 80 | ), 81 | 82 | 'RS_CLEAR_POST' => 'Clear post reputation', 83 | 'RS_CLEAR_POST_CONFIRM' => 'Do you really want to delete all reputation points for that post?', 84 | 'RS_CLEARED_POST' => 'The post reputation has been cleared.', 85 | 'RS_CLEAR_USER' => 'Clear user reputation', 86 | 'RS_CLEAR_USER_CONFIRM' => 'Do you really want to delete all reputation points for that user?', 87 | 'RS_CLEARED_USER' => 'The user reputation has been cleared.', 88 | 89 | 'RS_LATEST_REPUTATIONS' => 'Latest reputations', 90 | 'LIST_REPUTATIONS' => array( 91 | 1 => '%d reputation', 92 | 2 => '%d reputations', 93 | ), 94 | 'ALL_REPUTATIONS' => 'All reputations', 95 | 96 | 'RS_NEW_REPUTATIONS' => 'New reputation points', 97 | 'RS_NEW_REP' => 'You received 1 new reputation comment', 98 | 'RS_NEW_REPS' => 'You received %s new reputation comments', 99 | 'RS_CLICK_TO_VIEW' => 'Go to received points', 100 | 101 | 'RS_MORE_DETAILS' => '» more details', 102 | 103 | 'RS_USER_REPUTATION' => '%s\'s reputation', 104 | 105 | 'RS_VOTE_POWER_LEFT' => '%1$d of %2$d', 106 | 107 | 'RS_POWER_DETAILS' => 'How reputation power should be calculated', 108 | 'RS_POWER_DETAIL_AGE' => 'By registration date', 109 | 'RS_POWER_DETAIL_POSTS' => 'By number of posts', 110 | 'RS_POWER_DETAIL_REPUTAION' => 'By reputation', 111 | 'RS_POWER_DETAIL_WARNINGS' => 'By warnings', 112 | 'RS_POWER_DETAIL_MIN' => 'Minimum reputation power for all users', 113 | 'RS_POWER_DETAIL_MAX' => 'Reputation power capped at maximum allowed', 114 | 'RS_POWER_DETAIL_GROUP_POWER' => 'Reputation power based on user group', 115 | 'RS_GROUP_POWER' => 'Reputation power based on user group', 116 | )); 117 | -------------------------------------------------------------------------------- /exception/base.php: -------------------------------------------------------------------------------- 1 | message = (string) $message[0]; 45 | } 46 | else 47 | { 48 | $this->message = $message; 49 | } 50 | $this->message_full = $message; 51 | 52 | $this->code = $code; 53 | $this->previous = $previous; 54 | } 55 | 56 | /** 57 | * Basic message translation for our exceptions 58 | * 59 | * @param \phpbb\user $user 60 | * @return string 61 | * @access public 62 | */ 63 | public function get_message(\phpbb\user $user) 64 | { 65 | // Make sure our language file has been loaded 66 | $this->add_lang($user); 67 | 68 | if (is_array($this->message_full)) 69 | { 70 | return call_user_func_array(array($user, 'lang'), $this->message_full); 71 | } 72 | 73 | return $user->lang($this->message_full); 74 | } 75 | 76 | /** 77 | * Translate all portions of the message sent to the exception 78 | * 79 | * Goes through each element of the array and tries to translate them 80 | * 81 | * @param \phpbb\user $user 82 | * @param array $message_portions The message portions to translate 83 | * @param string|null $parent_message Send a string to translate all of the 84 | * portions with the parent message (typically used to format a string 85 | * with the given message portions). Null to ignore. Default: Null 86 | * @return array|string Array if $parent_message === null else a string 87 | * @access protected 88 | */ 89 | protected function translate_portions(\phpbb\user $user, $message_portions, $parent_message = null) 90 | { 91 | // Make sure our language file has been loaded 92 | $this->add_lang($user); 93 | 94 | // Ensure we have an array 95 | if (!is_array($message_portions)) 96 | { 97 | $message_portions = array($message_portions); 98 | } 99 | 100 | // Translate each message portion 101 | foreach ($message_portions as &$message) 102 | { 103 | // Attempt to translate each portion 104 | $translated_message = $user->lang('EXCEPTION_' . $message); 105 | 106 | // Check if translating did anything 107 | if ($translated_message !== 'EXCEPTION_' . $message) 108 | { 109 | // It did, so replace message with the translated version 110 | $message = $translated_message; 111 | } 112 | } 113 | // Always unset a variable passed by reference in a foreach loop 114 | unset($message); 115 | 116 | if ($parent_message !== null) 117 | { 118 | // Prepend the parent message to the message portions 119 | array_unshift($message_portions, (string) $parent_message); 120 | 121 | // We return a string 122 | return call_user_func_array(array($user, 'lang'), $message_portions); 123 | } 124 | 125 | // We return an array 126 | return $message_portions; 127 | } 128 | 129 | /** 130 | * Add our language file 131 | * 132 | * @param \phpbb\user $user 133 | * @return null 134 | * @access public 135 | */ 136 | public function add_lang(\phpbb\user $user) 137 | { 138 | static $is_loaded = false; 139 | 140 | // We only need to load the language file once 141 | if ($is_loaded) 142 | { 143 | return; 144 | } 145 | 146 | // Add our language file 147 | $user->add_lang_ext('pico/reputation', 'exceptions'); 148 | 149 | // So the language file is only loaded once 150 | $is_loaded = true; 151 | } 152 | 153 | /** 154 | * Output a string of this error message 155 | * 156 | * This will hopefully be never called, always catch the expected exceptions 157 | * and call get_message to translate them into an error that a user can 158 | * understand 159 | * 160 | * @return string 161 | * @access public 162 | */ 163 | public function __toString() 164 | { 165 | return (is_array($this->message_full)) ? var_export($this->message_full, true) : (string) $this->message_full; 166 | } 167 | } 168 | -------------------------------------------------------------------------------- /event/mcp_listener.php: -------------------------------------------------------------------------------- 1 | auth = $auth; 53 | $this->config = $config; 54 | $this->request = $request; 55 | $this->template = $template; 56 | $this->user = $user; 57 | $this->reputation_manager = $reputation_manager; 58 | } 59 | 60 | /** 61 | * Assign functions defined in this class to event listeners in the core 62 | * 63 | * @return array 64 | * @static 65 | * @access public 66 | */ 67 | static public function getSubscribedEvents() 68 | { 69 | return array( 70 | 'core.mcp_warn_post_after' => 'warning_post', 71 | 'core.mcp_warn_user_after' => 'warning_user', 72 | 'core.modify_mcp_modules_display_option' => 'reputation_warning_options', 73 | ); 74 | } 75 | 76 | /** 77 | * 78 | * 79 | * @param object $event The event object 80 | * @return null 81 | * @access public 82 | */ 83 | public function warning_post($event) 84 | { 85 | if($this->request->is_set_post('add_reputation')) 86 | { 87 | $data = array( 88 | 'user_id_from' => $this->user->data['user_id'], 89 | 'user_id_to' => $event['user_row']['poster_id'], 90 | 'reputation_type' => 'warning', 91 | 'reputation_item_id' => $event['post_id'], 92 | 'reputation_points' => $this->request->variable('points', ''), 93 | 'reputation_comment' => $this->request->variable('comment', '', true), 94 | ); 95 | 96 | try 97 | { 98 | $this->reputation_manager->store_reputation($data); 99 | } 100 | catch (\pico\reputation\exception\base $e) 101 | { 102 | // Catch exception 103 | $error = $e->get_message($this->user); 104 | } 105 | } 106 | } 107 | 108 | /** 109 | * 110 | * 111 | * @param object $event The event object 112 | * @return null 113 | * @access public 114 | */ 115 | public function warning_user($event) 116 | { 117 | if($this->request->is_set_post('add_reputation')) 118 | { 119 | $data = array( 120 | 'user_id_from' => $this->user->data['user_id'], 121 | 'user_id_to' => $event['user_row']['user_id'], 122 | 'reputation_type' => 'warning', 123 | 'reputation_item_id' => 0, 124 | 'reputation_points' => $this->request->variable('points', ''), 125 | 'reputation_comment' => $this->request->variable('comment', '', true), 126 | ); 127 | 128 | try 129 | { 130 | $this->reputation_manager->store_reputation($data); 131 | } 132 | catch (\pico\reputation\exception\base $e) 133 | { 134 | // Catch exception 135 | $error = $e->get_message($this->user); 136 | } 137 | } 138 | } 139 | 140 | /** 141 | * 142 | * 143 | * @param object $event The event object 144 | * @return null 145 | * @access public 146 | */ 147 | public function reputation_warning_options($event) 148 | { 149 | $mode = $event['mode']; 150 | 151 | if ($this->config['rs_warning'] && $this->auth->acl_get('m_rs_moderate') && ($mode == 'warn_post' || $mode == 'warn_user')) 152 | { 153 | $this->user->add_lang_ext('pico/reputation', 'reputation_warning'); 154 | 155 | //Preparing HTML for voting by manual spending of user power 156 | for($i = 1; $i <= $this->config['rs_max_power_warning']; ++$i) 157 | { 158 | $this->template->assign_block_vars('power', array( 159 | 'POINTS' => -$i, 160 | 'TITLE' => $this->user->lang('MCP_RS_POINTS', $i), 161 | )); 162 | } 163 | 164 | $this->template->assign_vars(array( 165 | 'S_RS_WARNING' => true, 166 | )); 167 | } 168 | } 169 | } 170 | -------------------------------------------------------------------------------- /styles/prosilver/theme/reputation_common.css: -------------------------------------------------------------------------------- 1 | #reputation-popup { 2 | font-size: 0.9em; 3 | z-index: 500; 4 | display: none; 5 | background: white; 6 | box-shadow: 2px 2px 4px #555555; 7 | border-radius: 11px; 8 | padding: 5px; 9 | border: 5px solid #12A3EB; 10 | } 11 | 12 | @media only screen and (max-width: 700px), only screen and (max-device-width: 700px) { 13 | #reputation-popup { 14 | width: 300px !important; 15 | } 16 | } 17 | 18 | #reputation-popup div.error { 19 | text-align: center; 20 | font-size: 1.2em; 21 | } 22 | 23 | /* Fix - do not show white space at the bottom of reputation popup */ 24 | #reputation-popup div.panel { margin-bottom: 0px; } 25 | 26 | #reputation-popup h3 { 27 | font-size: 1.4em; 28 | padding-left: 10px; 29 | text-transform: none; 30 | font-family: "Trebuchet MS", Verdana, Helvetica, Arial, sans-serif; 31 | margin: 0; 32 | border: none; 33 | } 34 | 35 | #reputation-popup p { padding: 0 10px; } 36 | 37 | #post-reputation-list { 38 | border-top: 1px solid #CCC; 39 | border-bottom: 1px solid #CCC; 40 | } 41 | 42 | #user-reputation-list { 43 | float: right; 44 | width: 58%; 45 | } 46 | 47 | .small-popup { 48 | width: 330px; 49 | position: absolute; 50 | } 51 | 52 | .normal-popup { 53 | width: 570px; 54 | position: fixed; 55 | } 56 | 57 | .normal-popup #post-reputation-list { 58 | max-height: 350px; 59 | overflow: auto; 60 | } 61 | 62 | .footer-popup { padding: 2px 10px 0 10px; } 63 | 64 | .clear-reputation { float: right; } 65 | 66 | .progress-bar { 67 | width: 100%; 68 | height: 10px; 69 | border-radius: 3px; 70 | border: 1px solid #a4bdcb; 71 | background: #a4bdcb; 72 | background: -moz-linear-gradient(left, #dc4a5b 0%, #ffb489 8%, #fcfaba 18%, #54d077 70%); 73 | background: -webkit-gradient(linear, left top, right top, color-stop(0%,#dc4a5b), color-stop(8%,#ffb489), color-stop(18%,#fcfaba), color-stop(70%,#54d077)); 74 | background: -webkit-linear-gradient(left, #dc4a5b 0%,#ffb489 8%,#fcfaba 18%,#54d077 70%); 75 | background: -o-linear-gradient(left, #dc4a5b 0%,#ffb489 8%,#fcfaba 18%,#54d077 70%); 76 | background: -ms-linear-gradient(left, #dc4a5b 0%,#ffb489 8%,#fcfaba 18%,#54d077 70%); 77 | background: linear-gradient(to right, #dc4a5b 0%,#ffb489 8%,#fcfaba 18%,#54d077 70%); 78 | filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#dc4a5b', endColorstr='#54d077',GradientType=1 ); 79 | } 80 | 81 | .empty-progress { 82 | background: white; 83 | height: 10px; 84 | float: right; 85 | } 86 | 87 | .reputation-list { 88 | border: 1px #dadada solid; 89 | -moz-border-radius: 5px; 90 | border-radius: 5px; 91 | display: block; 92 | margin: 5px; 93 | padding: 6px; 94 | overflow: hidden; 95 | } 96 | 97 | .empty { text-align: center; } 98 | 99 | .reputation-detail { padding-left: 5px; } 100 | 101 | .reputation-avatar { 102 | float: left; 103 | padding: 2px; 104 | margin-right: 12px; 105 | background-color: white; 106 | border-radius: 5px; 107 | border: 1px solid #D5D5D5; 108 | box-shadow: 0 2px 2px rgba(0, 0, 0, 0.1); 109 | } 110 | .reputation-avatar img { 111 | display: block !important; 112 | width: 60px; 113 | height: initial; 114 | } 115 | 116 | .reputation-rating { 117 | display: block; 118 | float: right; 119 | font-weight: bold; 120 | font-size: 1.4em; 121 | padding-right: 10px; 122 | } 123 | 124 | .reputation-rating.positive.image, 125 | .reputation-rating.negative.image { 126 | background-repeat: no-repeat; 127 | font-size: 0px; 128 | width: 16px; 129 | height: 16px; 130 | } 131 | 132 | .reputation-rating.positive.image { background-image: url("./images/pos.png"); } 133 | 134 | .reputation-rating.negative.image { background-image: url("./images/neg.png"); } 135 | 136 | .reputation-action { 137 | margin-bottom: 5px; 138 | margin-top: 3px; 139 | } 140 | 141 | .type-title { font-weight: bold; } 142 | 143 | .comment_message { 144 | float: left; 145 | display: block; 146 | } 147 | 148 | .comment_message div { 149 | border: 1px #dadada solid; 150 | border-radius: 5px; 151 | display: block; 152 | margin: 5px; 153 | background-color: white; 154 | padding: 5px; 155 | } 156 | 157 | .reputation-delete { 158 | background-image: url("./images/reputation_delete.png"); 159 | background-repeat: no-repeat; 160 | font-size: 0px; 161 | width: 16px; 162 | height: 16px; 163 | padding: 0; 164 | float: right; 165 | opacity: 0.3; 166 | } 167 | 168 | .reputation-delete:hover { opacity: 1.0; } 169 | 170 | .sorting { float: left; } 171 | 172 | .stats-positive, 173 | .stats-negative { font-weight: bold; } 174 | 175 | .reputation-rating.positive, 176 | .stats-positive { 177 | color: #6F8F52; 178 | } 179 | 180 | .reputation-rating.negative, 181 | .stats-negative { 182 | color: #B82929; 183 | } 184 | 185 | .reputation { 186 | display: inline-block; 187 | padding: 2px 6px; 188 | text-align: center; 189 | font-weight: bold; 190 | border: 1px solid transparent; 191 | border-radius: 4px; 192 | } 193 | 194 | .reputation.positive { background: #6F8F52; } 195 | 196 | .reputation.negative { background: #B82929; } 197 | 198 | .reputation.neutral { background: #fff;} 199 | 200 | .reputation.positive, .reputation.negative { color: #fff; } 201 | 202 | #post-reputation-list::-webkit-scrollbar { 203 | width: 8px; 204 | height: 8px; 205 | -webkit-appearance: none; 206 | background: rgba(0, 0, 0, .1); 207 | border-radius: 3px; 208 | } 209 | 210 | #post-reputation-list::-webkit-scrollbar-thumb { 211 | border-radius: 10px; 212 | -webkit-box-shadow: inset 0 0 6px rgba(0,0,0,0.5); 213 | } -------------------------------------------------------------------------------- /core/reputation_power.php: -------------------------------------------------------------------------------- 1 | config = $config; 40 | $this->db = $db; 41 | $this->reputation_table = $reputation_table; 42 | } 43 | 44 | /** 45 | * Function returns maximum reputation power of one user 46 | * 47 | * @param int $posts User posts 48 | * @param timestamp $regdate User registration date 49 | * @param int $reputation User reputation 50 | * @param int $warnings User warnings 51 | * @param int $user_group_id User group ID 52 | * @return int User power reputation 53 | * @access public 54 | */ 55 | public function get($posts, $regdate, $reputation, $warnings, $user_group_id) 56 | { 57 | $now = time(); 58 | $user_power = array(); 59 | 60 | // Increasing power for number of posts 61 | if ($this->config['rs_total_posts']) 62 | { 63 | $user_power['FOR_NUMBER_OF_POSTS'] = intval($posts / $this->config['rs_total_posts']); 64 | } 65 | 66 | // Increasing power for the age of the user 67 | if ($this->config['rs_membership_days']) 68 | { 69 | $user_power['FOR_USER_AGE'] = intval(intval(($now - $regdate) / 86400) / $this->config['rs_membership_days']); 70 | } 71 | 72 | // Increasing power for total reputation 73 | if ($this->config['rs_power_rep_point']) 74 | { 75 | $user_power['FOR_REPUTATION'] = intval($reputation / $this->config['rs_power_rep_point']); 76 | } 77 | 78 | // Decreasing power for warnings 79 | if ($this->config['rs_power_lose_warn'] > 0) 80 | { 81 | $user_power['FOR_WARNINGS'] = -$warnings * $this->config['rs_power_lose_warn']; 82 | } 83 | 84 | // Max user power 85 | if (empty($user_power)) 86 | { 87 | $user_max_power = $this->config['rs_max_power']; 88 | } 89 | else 90 | { 91 | $user_max_power = array_sum($user_power); 92 | $user_max_power = $user_max_power + $this->config['rs_min_power']; 93 | } 94 | 95 | // Check min power - if it is set, inform about it 96 | if ($this->config['rs_min_power']) 97 | { 98 | $user_power['MINIMUM_VOTING_POWER'] = $this->config['rs_min_power']; 99 | } 100 | 101 | // Checking if user reputation power is not lower than minimum power set in ACP 102 | if ($user_max_power < $this->config['rs_min_power']) 103 | { 104 | $user_max_power = max($this->config['rs_min_power'], $user_max_power); 105 | } 106 | 107 | // Checking if user reputation power is not higher than maximum power set in ACP 108 | if ($user_max_power > $this->config['rs_max_power']) 109 | { 110 | $user_power['MAXIMUM_VOTING_POWER'] = $this->config['rs_max_power']; 111 | $user_max_power = min($this->config['rs_max_power'], $user_max_power); 112 | } 113 | 114 | // Group reputation power 115 | // Calculating group power, if necessary 116 | if ($user_group_id) 117 | { 118 | $sql = 'SELECT group_reputation_power 119 | FROM ' . GROUPS_TABLE . " 120 | WHERE group_id = $user_group_id"; 121 | $result = $this->db->sql_query($sql); 122 | $group_power = (int)$this->db->sql_fetchfield('group_reputation_power'); 123 | $this->db->sql_freeresult($result); 124 | 125 | if (!empty($group_power)) 126 | { 127 | unset($user_power); 128 | 129 | $user_power = array(); 130 | 131 | $user_max_power = $user_power['GROUP_VOTING_POWER'] = $group_power; 132 | } 133 | } 134 | 135 | // Put the structure of the user power into $this->explanation 136 | $this->explanation = $user_power; 137 | 138 | return $user_max_power; 139 | } 140 | 141 | /** 142 | * Function returns an array explaining structure of the user reputation power 143 | * 144 | * @return array User reputation power with the explanation 145 | * @access public 146 | */ 147 | public function explain() 148 | { 149 | return $this->explanation; 150 | } 151 | 152 | /** 153 | * Function returns a reputation power used by an user 154 | * 155 | * @param $user_id User ID 156 | * @return int Power used 157 | * @access public 158 | */ 159 | public function used($user_id) 160 | { 161 | $time = time(); 162 | $power_used = 0; 163 | 164 | if ($this->config['rs_power_renewal']) 165 | { 166 | // Until what time stamp should we count user votes 167 | $renewal_timeout = $time - $this->config['rs_power_renewal'] * 3600; 168 | 169 | // Let's get all voting data on this user. 170 | $sql = 'SELECT reputation_points 171 | FROM ' . $this->reputation_table . " 172 | WHERE user_id_from = {$user_id} 173 | AND reputation_time > $renewal_timeout"; 174 | $result = $this->db->sql_query($sql); 175 | 176 | // Let's run through the rows and make statistics 177 | while($renewal = $this->db->sql_fetchrow($result)) 178 | { 179 | // How much power a user spent in a specified period of time 180 | $power_used += (int) $renewal['reputation_points']; 181 | } 182 | $this->db->sql_freeresult($result); 183 | } 184 | 185 | return (int) $power_used; 186 | } 187 | } 188 | -------------------------------------------------------------------------------- /event/acp_listener.php: -------------------------------------------------------------------------------- 1 | request = $request; 37 | $this->template = $template; 38 | } 39 | 40 | /** 41 | * Assign functions defined in this class to event listeners in the core 42 | * 43 | * @return array 44 | * @static 45 | * @access public 46 | */ 47 | static public function getSubscribedEvents() 48 | { 49 | return array( 50 | 'core.acp_manage_forums_request_data' => 'forum_reputation_request', 51 | 'core.acp_manage_forums_initialise_data' => 'forum_initialise_reputation', 52 | 'core.acp_manage_forums_display_form' => 'forum_display_reputation', 53 | 'core.acp_manage_group_request_data' => 'group_request_data', 54 | 'core.acp_manage_group_initialise_data' => 'group_initialise_data', 55 | 'core.acp_manage_group_display_form' => 'group_display_form', 56 | 'core.permissions' => 'add_reputation_permissions', 57 | ); 58 | } 59 | 60 | /** 61 | * Add reputation forum request data 62 | * 63 | * @param object $event The event object 64 | * @return null 65 | * @access public 66 | */ 67 | public function forum_reputation_request($event) 68 | { 69 | $forum_data = $event['forum_data']; 70 | $forum_data['reputation_enabled'] = $this->request->variable('reputation_enabled', 0); 71 | $event['forum_data'] = $forum_data; 72 | } 73 | 74 | /** 75 | * Initialise reputation data while creating a new forum 76 | * 77 | * @param object $event The event object 78 | * @return null 79 | * @access public 80 | */ 81 | public function forum_initialise_reputation($event) 82 | { 83 | if($event['action'] == 'add') 84 | { 85 | $forum_data = $event['forum_data']; 86 | $forum_data = array_merge($forum_data, array( 87 | 'reputation_enabled' => false, 88 | )); 89 | $event['forum_data'] = $forum_data; 90 | } 91 | } 92 | 93 | /** 94 | * Assign reputation data to forum template 95 | * 96 | * @param object $event The event object 97 | * @return null 98 | * @access public 99 | */ 100 | public function forum_display_reputation($event) 101 | { 102 | $template_data = $event['template_data']; 103 | $template_data['S_ENABLE_REPUTATION'] = $event['forum_data']['reputation_enabled']; 104 | $event['template_data'] = $template_data; 105 | } 106 | 107 | /** 108 | * Add reputation group request data 109 | * 110 | * @param object $event The event object 111 | * @return null 112 | * @access public 113 | */ 114 | public function group_request_data($event) 115 | { 116 | $submit_ary = $event['submit_ary']; 117 | $submit_ary['reputation_power'] = $this->request->variable('group_reputation_power', 0); 118 | $event['submit_ary'] = $submit_ary; 119 | 120 | $validation_checks = $event['validation_checks']; 121 | $validation_checks['reputation_power'] = array('num', false, 0, 999); 122 | $event['validation_checks'] = $validation_checks; 123 | } 124 | 125 | /** 126 | * Add group test variable 127 | * 128 | * @param object $event The event object 129 | * @return null 130 | * @access public 131 | */ 132 | public function group_initialise_data($event) 133 | { 134 | $test_variables = $event['test_variables']; 135 | $test_variables['reputation_power'] = 'int'; 136 | $event['test_variables'] = $test_variables; 137 | } 138 | 139 | /** 140 | * Assign reputation data to group template 141 | * 142 | * @param object $event The event object 143 | * @return null 144 | * @access public 145 | */ 146 | public function group_display_form($event) 147 | { 148 | $group_row = $event['group_row']; 149 | 150 | $this->template->assign_vars(array( 151 | 'GROUP_REPUTATION_POWER' => (isset($group_row['group_reputation_power'])) ? $group_row['group_reputation_power'] : 0, 152 | )); 153 | } 154 | 155 | /** 156 | * Add reputation permissions 157 | * 158 | * @param object $event The event object 159 | * @return null 160 | * @access public 161 | */ 162 | public function add_reputation_permissions($event) 163 | { 164 | // Create reputation category 165 | $categories = $event['categories']; 166 | $categories['reputation'] = 'ACL_CAT_REPUTATION'; 167 | $event['categories'] = $categories; 168 | 169 | // Assign permissions to categories 170 | $permissions = $event['permissions']; 171 | $permissions = array_merge($permissions, array( 172 | // Admin permissions 173 | 'a_reputation' => array('lang' => 'ACL_A_REPUTATION', 'cat' => 'misc'), 174 | 175 | // Forum permissions 176 | 'f_rs_rate' => array('lang' => 'ACL_F_RS_RATE', 'cat' => 'reputation'), 177 | 'f_rs_rate_negative' => array('lang' => 'ACL_F_RS_RATE_NEGATIVE', 'cat' => 'reputation'), 178 | 179 | // Moderator permissions 180 | 'm_rs_moderate' => array('lang' => 'ACL_M_RS_MODERATE', 'cat' => 'reputation'), 181 | 'm_rs_rate' => array('lang' => 'ACL_M_RS_RATE', 'cat' => 'reputation'), 182 | 183 | // User permissions 184 | 'u_rs_rate' => array('lang' => 'ACL_U_RS_RATE', 'cat' => 'reputation'), 185 | 'u_rs_rate_negative' => array('lang' => 'ACL_U_RS_RATE_NEGATIVE', 'cat' => 'reputation'), 186 | 'u_rs_view' => array('lang' => 'ACL_U_RS_VIEW', 'cat' => 'reputation'), 187 | 'u_rs_rate_post' => array('lang' => 'ACL_U_RS_RATE_POST', 'cat' => 'reputation'), 188 | 'u_rs_delete' => array('lang' => 'ACL_U_RS_DELETE', 'cat' => 'reputation'), 189 | )); 190 | $event['permissions'] = $permissions; 191 | } 192 | } 193 | -------------------------------------------------------------------------------- /event/viewtopic_listener.php: -------------------------------------------------------------------------------- 1 | auth = $auth; 57 | $this->config = $config; 58 | $this->helper = $helper; 59 | $this->template = $template; 60 | $this->user = $user; 61 | $this->reputation_helper = $reputation_helper; 62 | $this->reputations_table = $reputations_table; 63 | } 64 | 65 | /** 66 | * Assign functions defined in this class to event listeners in the core 67 | * 68 | * @return array 69 | * @static 70 | * @access public 71 | */ 72 | static public function getSubscribedEvents() 73 | { 74 | return array( 75 | 'core.viewtopic_assign_template_vars_before' => 'assign_reputation', 76 | 'core.viewtopic_get_post_data' => 'modify_sql_array', 77 | 'core.viewtopic_post_rowset_data' => 'post_rowset_reputation_data', 78 | 'core.viewtopic_cache_guest_data' => 'cache_reputation_data', 79 | 'core.viewtopic_cache_user_data' => 'cache_reputation_data', 80 | 'core.viewtopic_modify_post_row' => 'post_row_reputation', 81 | ); 82 | } 83 | 84 | /** 85 | * Add global template var for reputation in forums 86 | * 87 | * @param object $event The event object 88 | * @return null 89 | * @access public 90 | */ 91 | public function assign_reputation($event) 92 | { 93 | if ($this->config['rs_enable']) 94 | { 95 | $topic_data = $event['topic_data']; 96 | 97 | // Author note 98 | // Post rating is not allowed in the global announcements 99 | // because there is no option to set proper permissions for such topics 100 | $this->template->assign_vars(array( 101 | 'S_FORUM_REPUTATION' => ($topic_data['reputation_enabled'] && $this->config['rs_post_rating'] && ($topic_data['topic_type'] != POST_GLOBAL)) ? true : false, 102 | 103 | 'U_REPUTATION_REFERER' => $this->helper->get_current_url(), 104 | )); 105 | } 106 | } 107 | 108 | /** 109 | * Modify sql array by adding reputations table 110 | * 111 | * @param object $event The event object 112 | * @return null 113 | * @access public 114 | */ 115 | public function modify_sql_array($event) 116 | { 117 | // Modify sql array when the extension and its post rating are enabled 118 | // Otherwise do nothing 119 | if ($this->config['rs_enable'] && $this->config['rs_post_rating']) 120 | { 121 | $sql_ary = $event['sql_ary']; 122 | 123 | $sql_ary['LEFT_JOIN'][] = array( 124 | 'FROM' => array($this->reputations_table => 'r'), 125 | 'ON' => 'r.reputation_item_id = p.post_id 126 | AND r.reputation_type_id = 1 127 | AND r.user_id_from =' . $this->user->data['user_id'], 128 | ); 129 | $sql_ary['SELECT'] .= ', r.reputation_id, r.reputation_points'; 130 | 131 | $event['sql_ary'] = $sql_ary; 132 | } 133 | } 134 | 135 | /** 136 | * Add reputation data to rowset 137 | * 138 | * @param object $event The event object 139 | * @return null 140 | * @access public 141 | */ 142 | public function post_rowset_reputation_data($event) 143 | { 144 | if ($this->config['rs_enable'] && $this->config['rs_post_rating']) 145 | { 146 | $rowset_data = $event['rowset_data']; 147 | $row = $event['row']; 148 | 149 | $rowset_data = array_merge($rowset_data, array( 150 | 'post_reputation' => $row['post_reputation'], 151 | 'user_voted' => $row['reputation_id'], 152 | 'reputation_points' => $row['reputation_points'], 153 | )); 154 | 155 | $event['rowset_data'] = $rowset_data; 156 | } 157 | } 158 | 159 | /** 160 | * Add guest user's and user's data to display their reputation 161 | * 162 | * @param object $event The event object 163 | * @return null 164 | * @access public 165 | */ 166 | public function cache_reputation_data($event) 167 | { 168 | if ($this->config['rs_enable'] && $this->config['rs_post_rating']) 169 | { 170 | $user_cache_data = $event['user_cache_data']; 171 | $user_cache_data['reputation'] = $event['row']['user_reputation']; 172 | $event['user_cache_data'] = $user_cache_data; 173 | } 174 | } 175 | 176 | /** 177 | * Add post row data for displaying reputation 178 | * 179 | * @param object $event The event object 180 | * @return null 181 | * @access public 182 | */ 183 | public function post_row_reputation($event) 184 | { 185 | if ($this->config['rs_enable'] && $this->config['rs_post_rating']) 186 | { 187 | $row = $event['row']; 188 | $user_poster_data = $event['user_poster_data']; 189 | $post_row = $event['post_row']; 190 | $post_id = $row['post_id']; 191 | $poster_id = $event['poster_id']; 192 | 193 | // Check post status and return its status as class 194 | // Is it own post, rated good or rated bad? 195 | if ($this->user->data['user_id'] == $poster_id) 196 | { 197 | $post_vote_class = 'own'; 198 | } 199 | else 200 | { 201 | $post_vote_class = $row['user_voted'] ? (($row['reputation_points'] > 0) ? 'rated_good' : 'rated_bad') : ''; 202 | } 203 | 204 | $post_row = array_merge($post_row, array( 205 | 'S_VIEW_REPUTATION' => ($this->auth->acl_get('u_rs_view')) ? true : false, 206 | 'S_RATE_POST' => ($this->auth->acl_get('f_rs_rate', $row['forum_id']) && $this->auth->acl_get('u_rs_rate_post') && $poster_id != ANONYMOUS) ? true : false, 207 | 'S_RATE_POST_NEGATIVE' => ($this->auth->acl_get('f_rs_rate_negative', $row['forum_id']) && $this->config['rs_negative_point']) ? true : false, 208 | 209 | 'RS_RATE_POST_NEGATIVE' => $row['user_voted'] ? $this->user->lang('RS_POST_RATED') : $this->user->lang('RS_RATE_POST_NEGATIVE'), 210 | 'RS_RATE_POST_POSITIVE' => $row['user_voted'] ? $this->user->lang('RS_POST_RATED') : $this->user->lang('RS_RATE_POST_POSITIVE'), 211 | 212 | 'U_RATE_POST_POSITIVE' => $this->helper->route('reputation_post_rating_controller', array('mode' => 'positive', 'post_id' => $post_id)), 213 | 'U_RATE_POST_NEGATIVE' => $this->helper->route('reputation_post_rating_controller', array('mode' => 'negative', 'post_id' => $post_id)), 214 | 'U_VIEW_POST_REPUTATION' => $this->helper->route('reputation_post_details_controller', array('post_id' => $post_id)), 215 | 'U_VIEW_USER_REPUTATION' => $this->helper->route('reputation_user_details_controller', array('uid' => $poster_id)), 216 | 217 | 'POST_REPUTATION' => $row['post_reputation'], 218 | 'POST_REPUTATION_CLASS' => $this->reputation_helper->reputation_class($row['post_reputation']), 219 | 'POST_VOTE_CLASS' => $post_vote_class, 220 | 'USER_REPUTATION' => $user_poster_data['reputation'], 221 | )); 222 | 223 | $event['post_row'] = $post_row; 224 | } 225 | } 226 | } 227 | -------------------------------------------------------------------------------- /styles/prosilver/template/details.html: -------------------------------------------------------------------------------- 1 | 2 | 3 |

    {L_RS_DETAILS} - {USERNAME}

    4 | 5 |
    6 | 7 |
    8 |
    9 | 10 |

    {USERNAME_FULL}

    11 | 12 | 13 |
    14 |
    {AVATAR_IMG}
    15 |
    {RANK_TITLE}
    16 |
    {RANK_IMG}
    17 |
    18 | 19 | 20 |
    21 | 22 |
    {L_RANK}:
    {RANK_TITLE}
    23 |
     {L_RANK}:
    {RANK_IMG}
    24 | 25 |
    {L_REPUTATION}:
    {REPUTATION} 26 | 27 |
    {L_RS_POWER}:
    {RS_POWER}
    28 |
    {L_RS_VOTING_POWER}:
    {RS_POWER_LEFT}
    29 | 30 |
    {L_RS_POST_COUNT}:
    {POST_COUNT}
    31 |
    {L_RS_USER_COUNT}:
    {USER_COUNT}
    32 |
    {L_RS_POSITIVE_COUNT}:
    {POSITIVE_COUNT} ({L_RS_POINTS}: {POSITIVE_SUM})
    33 |
    {L_RS_NEGATIVE_COUNT}:
    {NEGATIVE_COUNT} ({L_RS_POINTS}: {NEGATIVE_SUM})
    34 |
     
    [ {L_RS_CLEAR_USER} ]
    35 |
    36 | 37 |
    38 |
    39 | 40 |
    41 |
    42 | 43 | 44 |
    45 | 46 |

    {L_RS_POWER_DETAILS}

    47 | 48 |
    49 | 50 |
    {L_RS_POWER_DETAIL_AGE}:
    {FOR_USER_AGE}
    51 |
    {L_RS_POWER_DETAIL_POSTS}:
    {FOR_NUMBER_OF_POSTS}
    52 |
    {L_RS_POWER_DETAIL_REPUTAION}:
    {FOR_REPUTATION}
    53 |
    {L_RS_POWER_DETAIL_WARNINGS}:
    {FOR_WARNINGS}
    54 |
    {L_RS_POWER_DETAIL_BANS}:
    {FOR_BANS}
    55 |
    {L_RS_POWER_DETAIL_MIN}:
    {MINIMUM_VOTING_POWER}
    56 |
    {L_RS_POWER_DETAIL_MAX}:
    {MAXIMUM_VOTING_POWER}
    57 | 58 |
    {L_RS_GROUP_POWER}:
    {GROUP_VOTING_POWER}
    59 | 60 |
    61 |
    62 | 63 |
    64 | 65 | 66 |

    {L_RS_STATS}

    67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 |
     {L_RS_POSITIVE}{L_RS_NEGATIVE}
    {L_RS_WEEK}{POSITIVE_WEEK}{NEGATIVE_WEEK}
    {L_RS_MONTH}{POSITIVE_MONTH}{NEGATIVE_MONTH}
    {L_RS_6MONTHS}{POSITIVE_6MONTHS}{NEGATIVE_6MONTHS}
    90 | 91 |
    92 | 93 | 94 |
    95 |
    96 | 97 |
    98 | 99 |
    100 | 101 | 102 |
    103 |
    104 | 105 | {L_USERNAME} • 106 | {L_TIME} • 107 | {L_RS_POINTS} • 108 | {L_RS_ACTION} 109 |
    110 | 118 |
    119 |
    120 | 121 | 122 |
    123 | 124 | 125 |
    126 | 127 |
    128 | 129 | {reputation.AVATAR} 130 | 131 | 132 | 133 |
    134 | 135 |
    136 | {L_DELETE} 137 |
    {reputation.POINTS}
    138 |
    {reputation.USERNAME} » {reputation.TIME}
    139 |
    140 | {reputation.ACTION} 141 | 142 | 143 |
    » 144 | 145 | {reputation.post.POST_SUBJECT} 146 | 147 | 148 | 149 |
    150 | 151 |
    152 | {L_RS_COMMENT}: 153 |
    {reputation.COMMENT}
    154 |
    155 | 156 |
    157 |
    158 | 159 | 160 |
    161 | {L_RS_EMPTY_DATA} 162 |
    163 | 164 |
    165 | 166 | 167 |
    168 |
    169 | 170 | {L_USERNAME} • 171 | {L_TIME} • 172 | {L_RS_POINTS} • 173 | {L_RS_ACTION} 174 |
    175 | 183 |
    184 |
    185 | 186 |
    187 | 188 |
    189 | 190 | -------------------------------------------------------------------------------- /notification/type/rate_post_positive.php: -------------------------------------------------------------------------------- 1 | 'pico.reputation.notification', 46 | 'lang' => 'NOTIFICATION_TYPE_REPUTATION', 47 | 'group' => 'NOTIFICATION_GROUP_MISCELLANEOUS', 48 | ); 49 | 50 | /** 51 | * Is this type available to the current user (defines whether or not it will be shown in the UCP Edit notification options) 52 | * 53 | * @return bool True/False whether or not this is available to the user 54 | */ 55 | public function is_available() 56 | { 57 | return true; 58 | } 59 | 60 | /** 61 | * Get the id of the notification 62 | * 63 | * @param array $data The data for the reputation 64 | */ 65 | public static function get_item_id($data) 66 | { 67 | return (int) $data['reputation_id']; 68 | } 69 | 70 | /** 71 | * Get the id of the parent 72 | * 73 | * @param array $data The data for the reputation 74 | */ 75 | public static function get_item_parent_id($data) 76 | { 77 | return 0; 78 | } 79 | 80 | /** 81 | * Find the users who will receive notifications 82 | * 83 | * @param array $data The type specific data for the updated 84 | * @param array $options Options for finding users for notification 85 | * 86 | * @return array 87 | */ 88 | public function find_users_for_notification($data, $options = array()) 89 | { 90 | $options = array_merge(array( 91 | 'ignore_users' => array(), 92 | ), $options); 93 | $users = array((int) $data['user_id_to']); 94 | 95 | $notify_users = $this->check_user_notification_options($users, $options); 96 | 97 | // Try to find the users who already have been notified about replies and have not read the topic since and just update their notifications 98 | $sql = 'SELECT n.* 99 | FROM ' . $this->notifications_table . ' n, ' . $this->notification_types_table . ' nt 100 | WHERE n.notification_type_id = ' . (int) $this->notification_type_id . ' 101 | AND n.item_parent_id = ' . (int) self::get_item_parent_id($data) . ' 102 | AND n.notification_read = 0 103 | AND nt.notification_type_id = n.notification_type_id 104 | AND nt.notification_type_enabled = 1'; 105 | $result = $this->db->sql_query($sql); 106 | while ($row = $this->db->sql_fetchrow($result)) 107 | { 108 | $row_data = unserialize($row['notification_data']); 109 | 110 | // Compare post id 111 | if ($row_data['post_id'] == $data['post_id']) 112 | { 113 | // Do not create a new notification 114 | unset($notify_users[$row['user_id']]); 115 | 116 | $notification = $this->notification_manager->get_item_type_class($this->get_type(), $row); 117 | $update_voting_users = $notification->add_voting_users($data); 118 | if (!empty($update_voting_users)) 119 | { 120 | $sql = 'UPDATE ' . $this->notifications_table . ' 121 | SET ' . $this->db->sql_build_array('UPDATE', $update_voting_users) . ' 122 | WHERE notification_id = ' . $row['notification_id']; 123 | $this->db->sql_query($sql); 124 | } 125 | } 126 | } 127 | $this->db->sql_freeresult($result); 128 | 129 | return $notify_users; 130 | } 131 | 132 | /** 133 | * Users needed to query before this notification can be displayed 134 | * 135 | * @return array Array of user_ids 136 | */ 137 | public function users_to_query() 138 | { 139 | $voting_users = $this->get_data('voting_users'); 140 | 141 | $users = array( 142 | $this->get_data('user_id_from'), 143 | ); 144 | 145 | if (is_array($voting_users)) 146 | { 147 | foreach ($voting_users as $voting_user) 148 | { 149 | $users[] = $voting_user['user_id_from']; 150 | } 151 | } 152 | 153 | return $users; 154 | } 155 | 156 | /** 157 | * Get the user's avatar 158 | */ 159 | public function get_avatar() 160 | { 161 | return $this->user_loader->get_avatar($this->get_data('user_id_from')); 162 | } 163 | 164 | /** 165 | * Get the HTML formatted title of this notification 166 | * 167 | * @return string 168 | */ 169 | public function get_title() 170 | { 171 | $voting_users = $this->get_data('voting_users'); 172 | $usernames = array(); 173 | 174 | if (!is_array($voting_users)) 175 | { 176 | $voting_users = array(); 177 | } 178 | 179 | $voting_users = array_merge(array(array( 180 | 'user_id_from' => $this->get_data('user_id_from'), 181 | )), $voting_users); 182 | 183 | $voting_users_cnt = sizeof($voting_users); 184 | $voting_users = $this->trim_user_ary($voting_users); 185 | $trimmed_voting_users_cnt = $voting_users_cnt - sizeof($voting_users); 186 | 187 | foreach ($voting_users as $voting_user) 188 | { 189 | $usernames[] = $this->user_loader->get_username($voting_user['user_id_from'], 'no_profile'); 190 | } 191 | 192 | if ($trimmed_voting_users_cnt > 20) 193 | { 194 | $usernames[] = $this->user->lang('NOTIFICATION_MANY_OTHERS'); 195 | } 196 | else if ($trimmed_voting_users_cnt) 197 | { 198 | $usernames[] = $this->user->lang('NOTIFICATION_X_OTHERS', $trimmed_voting_users_cnt); 199 | } 200 | 201 | return $this->user->lang( 202 | $this->language_key, 203 | phpbb_generate_string_list($usernames, $this->user), 204 | $trimmed_voting_users_cnt 205 | ); 206 | } 207 | 208 | /** 209 | * Get the HTML formatted reference of the notification 210 | * 211 | * @return string 212 | */ 213 | public function get_reference() 214 | { 215 | return $this->user->lang( 216 | 'NOTIFICATION_REFERENCE', 217 | censor_text($this->get_data('post_subject')) 218 | ); 219 | } 220 | 221 | /** 222 | * Get the url to this item 223 | * 224 | * @return string URL 225 | */ 226 | public function get_url() 227 | { 228 | return append_sid($this->phpbb_root_path . 'viewtopic.' . $this->php_ext, "p={$this->get_data('post_id')}#p{$this->get_data('post_id')}"); 229 | } 230 | 231 | /** 232 | * Trim the user array passed down to 3 users if the array contains 233 | * more than 4 users. 234 | * 235 | * @param array $users Array of users 236 | * @return array Trimmed array of user_ids 237 | */ 238 | public function trim_user_ary($users) 239 | { 240 | if (sizeof($users) > 4) 241 | { 242 | array_splice($users, 3); 243 | } 244 | return $users; 245 | } 246 | 247 | /** 248 | * Get email template 249 | * 250 | * @return string|bool 251 | */ 252 | public function get_email_template() 253 | { 254 | return false; 255 | } 256 | 257 | /** 258 | * Get email template variables 259 | * 260 | * @return array 261 | */ 262 | public function get_email_template_variables() 263 | { 264 | return array(); 265 | } 266 | 267 | /** 268 | * Function for preparing the data for insertion in an SQL query 269 | * (The service handles insertion) 270 | * 271 | * @param array $data The data for the reputation 272 | * @param array $pre_create_data Data from pre_create_insert_array() 273 | * 274 | * @return array Array of data ready to be inserted into the database 275 | */ 276 | public function create_insert_array($data, $pre_create_data = array()) 277 | { 278 | $this->set_data('user_id_from', $data['user_id_from']); 279 | $this->set_data('post_id', $data['post_id']); 280 | $this->set_data('post_subject', $data['post_subject']); 281 | 282 | return parent::create_insert_array($data, $pre_create_data); 283 | } 284 | 285 | /** 286 | * Add voting users to the notification 287 | * 288 | * @param mixed $user 289 | */ 290 | public function add_voting_users($user) 291 | { 292 | if ($this->get_data('user_id_from') == $user['user_id_from']) 293 | { 294 | return array(); 295 | } 296 | 297 | $voting_users = $this->get_data('voting_users'); 298 | 299 | $voting_users = ($voting_users === null) ? array() : $voting_users; 300 | 301 | if (sizeof($voting_users) > 25) 302 | { 303 | return array(); 304 | } 305 | 306 | foreach ($voting_users as $voting_user) 307 | { 308 | if ($voting_user['user_id_from'] == $user['user_id_from']) 309 | { 310 | return array(); 311 | } 312 | } 313 | 314 | $voting_users[] = array( 315 | 'user_id_from' => $user['user_id_from'], 316 | ); 317 | 318 | $this->set_data('voting_users', $voting_users); 319 | 320 | $serialized_data = serialize($this->get_data(false)); 321 | 322 | if (utf8_strlen($serialized_data) >= 4000) 323 | { 324 | return array(); 325 | } 326 | 327 | return array('notification_data' => $serialized_data); 328 | } 329 | } 330 | -------------------------------------------------------------------------------- /notification/type/rate_user.php: -------------------------------------------------------------------------------- 1 | user_loader = $user_loader; 44 | $this->db = $db; 45 | $this->cache = $cache; 46 | $this->user = $user; 47 | $this->auth = $auth; 48 | $this->config = $config; 49 | $this->helper = $helper; 50 | $this->phpbb_root_path = $phpbb_root_path; 51 | $this->php_ext = $php_ext; 52 | $this->notification_types_table = $notification_types_table; 53 | $this->notifications_table = $notifications_table; 54 | $this->user_notifications_table = $user_notifications_table; 55 | } 56 | 57 | /** 58 | * Get notification type name 59 | * 60 | * @return string 61 | */ 62 | public function get_type() 63 | { 64 | return 'pico.reputation.notification.type.rate_user'; 65 | } 66 | 67 | /** 68 | * Language key used to output the text 69 | * 70 | * @var string 71 | */ 72 | protected $language_key = 'NOTIFICATION_RATE_USER'; 73 | 74 | /** 75 | * Notification option data (for outputting to the user) 76 | * 77 | * @var bool|array False if the service should use it's default data 78 | * Array of data (including keys 'id', 'lang', and 'group') 79 | */ 80 | public static $notification_option = array( 81 | 'id' => 'pico.reputation.notification', 82 | 'lang' => 'NOTIFICATION_TYPE_REPUTATION', 83 | 'group' => 'NOTIFICATION_GROUP_MISCELLANEOUS', 84 | ); 85 | 86 | /** 87 | * Is this type available to the current user (defines whether or not it will be shown in the UCP Edit notification options) 88 | * 89 | * @return bool True/False whether or not this is available to the user 90 | */ 91 | public function is_available() 92 | { 93 | return true; 94 | } 95 | 96 | /** 97 | * Get the id of the notification 98 | * 99 | * @param array $data The data for the reputation 100 | */ 101 | public static function get_item_id($data) 102 | { 103 | return (int) $data['reputation_id']; 104 | } 105 | 106 | /** 107 | * Get the id of the parent 108 | * 109 | * @param array $data The data for the reputation 110 | */ 111 | public static function get_item_parent_id($data) 112 | { 113 | return 0; 114 | } 115 | 116 | /** 117 | * Find the users who will receive notifications 118 | * 119 | * @param array $data The type specific data for the updated 120 | * @param array $options Options for finding users for notification 121 | * 122 | * @return array 123 | */ 124 | public function find_users_for_notification($data, $options = array()) 125 | { 126 | $options = array_merge(array( 127 | 'ignore_users' => array(), 128 | ), $options); 129 | $users = array((int) $data['user_id_to']); 130 | 131 | $notify_users = $this->check_user_notification_options($users, $options); 132 | 133 | // Try to find the users who already have been notified about replies and have not read the topic since and just update their notifications 134 | $sql = 'SELECT n.* 135 | FROM ' . $this->notifications_table . ' n, ' . $this->notification_types_table . ' nt 136 | WHERE n.notification_type_id = ' . (int) $this->notification_type_id . ' 137 | AND n.item_parent_id = ' . (int) self::get_item_parent_id($data) . ' 138 | AND n.notification_read = 0 139 | AND n.user_id = ' . $data['user_id_to'] . ' 140 | AND nt.notification_type_id = n.notification_type_id 141 | AND nt.notification_type_enabled = 1'; 142 | $result = $this->db->sql_query($sql); 143 | while ($row = $this->db->sql_fetchrow($result)) 144 | { 145 | $row_data = unserialize($row['notification_data']); 146 | 147 | // Do not create a new notification 148 | unset($notify_users[$row['user_id']]); 149 | 150 | $notification = $this->notification_manager->get_item_type_class($this->get_type(), $row); 151 | $update_responders = $notification->add_voting_users($data); 152 | if (!empty($update_responders)) 153 | { 154 | $sql = 'UPDATE ' . $this->notifications_table . ' 155 | SET ' . $this->db->sql_build_array('UPDATE', $update_responders) . ' 156 | WHERE notification_id = ' . $row['notification_id']; 157 | $this->db->sql_query($sql); 158 | } 159 | } 160 | $this->db->sql_freeresult($result); 161 | 162 | return $notify_users; 163 | } 164 | 165 | /** 166 | * Users needed to query before this notification can be displayed 167 | * 168 | * @return array Array of user_ids 169 | */ 170 | public function users_to_query() 171 | { 172 | $voting_users = $this->get_data('voting_users'); 173 | 174 | $users = array( 175 | $this->get_data('user_id_from'), 176 | ); 177 | 178 | if (is_array($voting_users)) 179 | { 180 | foreach ($voting_users as $voting_user) 181 | { 182 | $users[] = $voting_user['user_id_from']; 183 | } 184 | } 185 | 186 | return $users; 187 | } 188 | 189 | /** 190 | * Get the user's avatar 191 | */ 192 | public function get_avatar() 193 | { 194 | return $this->user_loader->get_avatar($this->get_data('user_id_from')); 195 | } 196 | 197 | /** 198 | * Get the HTML formatted title of this notification 199 | * 200 | * @return string 201 | */ 202 | public function get_title() 203 | { 204 | $voting_users = $this->get_data('voting_users'); 205 | $usernames = array(); 206 | 207 | if (!is_array($voting_users)) 208 | { 209 | $voting_users = array(); 210 | } 211 | 212 | $voting_users = array_merge(array(array( 213 | 'user_id_from' => $this->get_data('user_id_from'), 214 | )), $voting_users); 215 | 216 | $voting_users_cnt = sizeof($voting_users); 217 | $voting_users = $this->trim_user_ary($voting_users); 218 | $trimmed_voting_users_cnt = $voting_users_cnt - sizeof($voting_users); 219 | 220 | foreach ($voting_users as $voting_user) 221 | { 222 | $usernames[] = $this->user_loader->get_username($voting_user['user_id_from'], 'no_profile'); 223 | } 224 | 225 | if ($trimmed_voting_users_cnt > 20) 226 | { 227 | $usernames[] = $this->user->lang('NOTIFICATION_MANY_OTHERS'); 228 | } 229 | else if ($trimmed_voting_users_cnt) 230 | { 231 | $usernames[] = $this->user->lang('NOTIFICATION_X_OTHERS', $trimmed_voting_users_cnt); 232 | } 233 | 234 | return $this->user->lang( 235 | $this->language_key, 236 | phpbb_generate_string_list($usernames, $this->user), 237 | $trimmed_voting_users_cnt 238 | ); 239 | } 240 | 241 | /** 242 | * Get the url to this item 243 | * 244 | * @return string URL 245 | */ 246 | public function get_url() 247 | { 248 | return $this->helper->route('reputation_details_controller', array('uid' => $this->user->data['user_id'])); 249 | } 250 | 251 | /** 252 | * Trim the user array passed down to 3 users if the array contains 253 | * more than 4 users. 254 | * 255 | * @param array $users Array of users 256 | * @return array Trimmed array of user_ids 257 | */ 258 | public function trim_user_ary($users) 259 | { 260 | if (sizeof($users) > 4) 261 | { 262 | array_splice($users, 3); 263 | } 264 | return $users; 265 | } 266 | 267 | /** 268 | * Get email template 269 | * 270 | * @return string|bool 271 | */ 272 | public function get_email_template() 273 | { 274 | return false; 275 | } 276 | 277 | /** 278 | * Get email template variables 279 | * 280 | * @return array 281 | */ 282 | public function get_email_template_variables() 283 | { 284 | return array(); 285 | } 286 | 287 | /** 288 | * Function for preparing the data for insertion in an SQL query 289 | * (The service handles insertion) 290 | * 291 | * @param array $data The data for the reputation 292 | * @param array $pre_create_data Data from pre_create_insert_array() 293 | * 294 | * @return array Array of data ready to be inserted into the database 295 | */ 296 | public function create_insert_array($data, $pre_create_data = array()) 297 | { 298 | $this->set_data('user_id_from', $data['user_id_from']); 299 | 300 | return parent::create_insert_array($data, $pre_create_data); 301 | } 302 | 303 | /** 304 | * Add voting users to the notification 305 | * 306 | * @param mixed $user 307 | */ 308 | public function add_voting_users($user) 309 | { 310 | if ($this->get_data('user_id_from') == $user['user_id_from']) 311 | { 312 | return array(); 313 | } 314 | 315 | $voting_users = $this->get_data('voting_users'); 316 | 317 | $voting_users = ($voting_users === null) ? array() : $voting_users; 318 | 319 | if (sizeof($voting_users) > 25) 320 | { 321 | return array(); 322 | } 323 | 324 | foreach ($voting_users as $voting_user) 325 | { 326 | if ($voting_user['user_id_from'] == $user['user_id_from']) 327 | { 328 | return array(); 329 | } 330 | } 331 | 332 | $voting_users[] = array( 333 | 'user_id_from' => $user['user_id_from'], 334 | ); 335 | 336 | $this->set_data('voting_users', $voting_users); 337 | 338 | $serialized_data = serialize($this->get_data(false)); 339 | 340 | if (utf8_strlen($serialized_data) >= 4000) 341 | { 342 | return array(); 343 | } 344 | 345 | return array('notification_data' => $serialized_data); 346 | } 347 | } 348 | -------------------------------------------------------------------------------- /styles/prosilver/template/reputation.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @package Reputation System 3 | * @copyright (c) 2014 Pico 4 | * @license http://opensource.org/licenses/gpl-license.php GNU Public License 5 | */ 6 | var reputation = {}; 7 | reputation.requestSent = false; 8 | 9 | (function ($) { // Avoid conflicts with other libraries 10 | 11 | /*$(document).ready(function() { 12 | //TO-DO Highlighting and hiding post 13 | $('.positive').each(function() { 14 | $(this).parents('.post').addClass("hidden"); 15 | }); 16 | });*/ 17 | 18 | // Close reputation popup 19 | $('body').click(function() { 20 | if (!reputation.requestSent) { 21 | $("#reputation-popup").fadeOut('fast'); 22 | } 23 | }); 24 | 25 | // Stop propagation 26 | $('#reputation-popup').click(function(e) { 27 | e.stopPropagation(); 28 | }); 29 | 30 | // Rating user 31 | $('#rate-user').click(function(event) { 32 | reputation.show_popup(this.href, event, 'user', $(this).attr('data-referer')); 33 | }); 34 | 35 | // Rating post - positive 36 | $('a.rate-good-icon').click(function(event) { 37 | reputation.show_popup(this.href, event, 'post', $(this).attr('data-referer')); 38 | }); 39 | 40 | // Rating post - negative 41 | $('a.rate-bad-icon').click(function(event) { 42 | reputation.show_popup(this.href, event, 'post', $(this).attr('data-referer')); 43 | }); 44 | 45 | // Display post reputation details 46 | $('a.post-reputation').click(function(event) { 47 | reputation.show_popup(this.href, event, 'details', $(this).attr('data-referer')); 48 | }); 49 | 50 | // Display user reputation details 51 | $('.user-reputation a').click(function(event) { 52 | reputation.show_popup(this.href, event, 'details', $(this).attr('data-referer')); 53 | }); 54 | 55 | // Save vote 56 | $('#reputation-popup').on("click", '.button1', function(event) { 57 | event.stopPropagation(); 58 | event.preventDefault(); 59 | 60 | reputation.submit_action($('#reputation-popup > form').attr('action'), $('#reputation-popup > form').attr('data-rate')); 61 | }); 62 | 63 | // Cancel rating 64 | $('#reputation-popup').on("click", '.button2', function(event) { 65 | event.stopPropagation(); 66 | event.preventDefault(); 67 | 68 | $('#reputation-popup').fadeOut('fast').queue(function() { 69 | $(this).empty(); 70 | $(this).dequeue(); 71 | }); 72 | }); 73 | 74 | // Sort reputation by 75 | $('#reputation-popup').on("click", 'a.sort_order', function(event) { 76 | event.stopPropagation(); 77 | event.preventDefault(); 78 | 79 | reputation.sort_order_by(this.href, $('.footer-popup').attr('data-referer')); 80 | }); 81 | 82 | // Delete reputation 83 | $('#reputation-popup').on("click", '.reputation-delete', function(event) { 84 | event.stopPropagation(); 85 | event.preventDefault(); 86 | 87 | var confirmation = $('a.reputation-delete').attr('data-lang-confirm'); 88 | 89 | if (confirm(confirmation)) { 90 | reputation.submit_action(this.href, 'delete'); 91 | } 92 | }); 93 | 94 | // Clear reputation 95 | $('#reputation-popup').on("click", '.clear-reputation', function(event) { 96 | event.stopPropagation(); 97 | event.preventDefault(); 98 | 99 | var confirmation = $('a.clear-reputation').attr('data-lang-confirm'); 100 | 101 | if (confirm(confirmation)) { 102 | reputation.submit_action(this.href, 'clear'); 103 | } 104 | }); 105 | 106 | /** 107 | * Show the reputation popup with proper data 108 | */ 109 | reputation.show_popup = function(href, event, mode, ref) { 110 | event.stopPropagation(); 111 | event.preventDefault(); 112 | 113 | if (!reputation.requestSent) { 114 | reputation.requestSent = true; 115 | 116 | $.ajax({ 117 | url: href, 118 | data: ref, 119 | dataType: 'html', 120 | beforeSend: function() { 121 | $('#reputation-popup').hide().empty().removeClass('small-popup normal-popup'); 122 | }, 123 | success: function(data) { 124 | // Fix - do not display the empty popup when comment and reputation power are disabled 125 | if (data.substr(0,1) != '{') { 126 | $('#reputation-popup').append(data).fadeIn('fast'); 127 | } 128 | 129 | switch(mode) { 130 | case 'details': 131 | $('#reputation-popup').addClass('normal-popup'); 132 | targetleft = ($(window).width() - $('#reputation-popup').outerWidth()) / 2; 133 | targettop = ($(window).height() - $('#reputation-popup').outerHeight()) / 2; 134 | break; 135 | 136 | default: 137 | $('#reputation-popup').addClass('small-popup'); 138 | // Center popup relative to clicked coordinate 139 | targetleft = event.pageX - $('#reputation-popup').outerWidth() / 2; 140 | // Popup can not be too close or behind the right border of the screen 141 | targetleft = Math.min (targetleft, $(document).width() - 20 - $('#reputation-popup').outerWidth()); 142 | targetleft = Math.max (targetleft, 20); 143 | targettop = event.pageY + 10; 144 | break; 145 | } 146 | 147 | $('#reputation-popup').css({'top': targettop + 'px', 'left': targetleft + 'px'}); 148 | 149 | // It's JSON! Probably an error. Lets clean the reputation popup and show the error there 150 | if (data.substr(0,1) == '{') { 151 | reputation.response(jQuery.parseJSON(data), mode); 152 | } 153 | }, 154 | complete: function() { 155 | reputation.requestSent = false; 156 | } 157 | }); 158 | } 159 | } 160 | 161 | /** 162 | * Submit reputation action 163 | */ 164 | reputation.submit_action = function(href, mode) { 165 | switch(mode) { 166 | case 'post': 167 | case 'user': 168 | data = $('#reputation-popup form').serialize(); 169 | break; 170 | 171 | default: 172 | data = ''; 173 | break; 174 | } 175 | 176 | $.ajax({ 177 | url: href, 178 | data: data, 179 | dataType: 'json', 180 | type: 'POST', 181 | success: function(r) { 182 | reputation.response(r, mode); 183 | } 184 | }); 185 | } 186 | 187 | /** 188 | * Reputation response 189 | */ 190 | reputation.response = function(data, mode) { 191 | // If there is an error, show it 192 | if (data.error_msg) { 193 | $('#reputation-popup').empty().append('
    ' + data.error_msg + '
    ').fadeIn(); 194 | } 195 | // If there is a comment error, show it 196 | else if (data.comment_error) { 197 | $('.error').detach(); 198 | $('.comment').append('
    ' + data.comment_error + '
    '); 199 | } 200 | // Otherwise modify the board outlook 201 | else { 202 | switch (mode) { 203 | case 'post': 204 | var post_id = data.post_id; 205 | var poster_id = data.poster_id; 206 | 207 | $('#reputation-popup').empty().append('
    ' + data.success_msg + '
    ').delay(500).fadeOut('fast').queue(function() { 208 | $('#profile-' + poster_id + ' span').text(data.user_reputation); 209 | $('#p' + post_id + ' .post-reputation span').text(data.post_reputation); 210 | $('#p' + post_id + ' .post-reputation').removeClass('neutral negative positive').addClass(data.reputation_class); 211 | $('#p' + post_id + ' .rate-good-icon').removeClass('rated_good rated_bad').addClass(data.reputation_vote); 212 | $('#p' + post_id + ' .rate-bad-icon').removeClass('rated_good rated_bad').addClass(data.reputation_vote); 213 | $(this).empty().dequeue(); 214 | }); 215 | break; 216 | 217 | case 'user': 218 | $('#reputation-popup').empty().append('
    ' + data.success_msg + '
    ').delay(500).fadeOut('fast').queue(function() { 219 | $('#user-reputation').html(data.user_reputation); 220 | $(this).empty().dequeue(); 221 | }); 222 | break; 223 | 224 | case 'delete': 225 | var post_id = data.post_id; 226 | var poster_id = data.poster_id; 227 | var rid = data.rid; 228 | 229 | $('#r' + rid).hide('fast', function() { 230 | $('#r' + rid).detach(); 231 | if ($('.reputation-list').length == 0) { 232 | $('#reputation-popup').fadeOut('fast').empty(); 233 | } 234 | }); 235 | $('#profile-' + poster_id + ' span').text(data.user_reputation); 236 | $('#p' + post_id + ' .post-reputation span').text(data.post_reputation); 237 | $('#p' + post_id + ' .post-reputation').removeClass('neutral negative positive').addClass(data.reputation_class); 238 | 239 | if (data.own_vote) { 240 | $('#p' + post_id + ' .rate-good-icon').removeClass('rated_good rated_bad'); 241 | $('#p' + post_id + ' .rate-bad-icon').removeClass('rated_good rated_bad'); 242 | } 243 | break; 244 | 245 | case 'clear': 246 | if (data.clear_post) { 247 | var post_id = data.post_id; 248 | var poster_id = data.poster_id; 249 | 250 | $('.reputation-list').slideUp(function() { 251 | $('#reputation-popup').fadeOut('fast').empty().delay(300).queue(function() { 252 | $('#profile-' + poster_id + ' span').text(data.user_reputation); 253 | $('#p' + post_id + ' .post-reputation span').text(data.post_reputation); 254 | $('#p' + post_id + ' .post-reputation').removeClass('neutral negative positive').addClass(data.reputation_class); 255 | $('#p' + post_id + ' .rate-good-icon').removeClass('rated_good rated_bad'); 256 | $('#p' + post_id + ' .rate-bad-icon').removeClass('rated_good rated_bad'); 257 | }).dequeue(); 258 | }); 259 | 260 | } 261 | else if (data.clear_user) { 262 | var post_ids = data.post_ids; 263 | var poster_id = data.poster_id; 264 | 265 | $('.reputation-list').slideUp(function() { 266 | $('#reputation-popup').fadeOut('fast').empty().delay(300).queue(function() { 267 | $('#profile-' + poster_id + ' span').text(data.user_reputation); 268 | 269 | $.each(post_ids, function(i, post_id) { 270 | $('#p' + post_id + ' .post-reputation span').text(data.post_reputation); 271 | $('#p' + post_id + ' .post-reputation').removeClass('neutral negative positive').addClass(data.reputation_class); 272 | $('#p' + post_id + ' .rate-good-icon').removeClass('rated_good rated_bad'); 273 | $('#p' + post_id + ' .rate-bad-icon').removeClass('rated_good rated_bad'); 274 | }); 275 | }).dequeue(); 276 | }); 277 | } 278 | break; 279 | } 280 | } 281 | } 282 | 283 | /** 284 | * Sort reputations 285 | */ 286 | reputation.sort_order_by = function(href, ref) { 287 | $.ajax({ 288 | url: href, 289 | data: ref, 290 | dataType: 'html', 291 | success: function(s) { 292 | $('#reputation-popup').empty().append(s); 293 | } 294 | }); 295 | } 296 | 297 | })(jQuery); // Avoid conflicts with other libraries 298 | -------------------------------------------------------------------------------- /language/en/reputation_acp.php: -------------------------------------------------------------------------------- 1 | 'Here you can configure Reputation System’s settings. They are divided into groups.', 42 | 'ACP_REPUTATION_RATE_EXPLAIN' => 'Here you can award additional reputation points to any users.', 43 | 44 | 'RS_ENABLE' => 'Enable Reputation System', 45 | 46 | 'RS_SYNC' => 'Synchronise Reputation System', 47 | 'RS_SYNC_EXPLAIN' => 'You can synchronise reputation points after a mass removal of posts/topics/users, changing reputation settings, changing post authors, conversions from others systems. This may take a while. You will be notified when the process is completed.
    Warning! All reputation points that do not match the reputation settings will be deleted during synchronization . It is recommended to make backup of the reputation table (DB) before synchronisation.', 48 | 'RS_SYNC_REPUTATION_CONFIRM' => 'Are you sure you wish to synchronise reputations?', 49 | 50 | 'RS_TRUNCATE' => 'Clear Reputation System', 51 | 'RS_TRUNCATE_EXPLAIN' => 'This procedure completely removes all data.
    Action is not reversible!', 52 | 'RS_TRUNCATE_CONFIRM' => 'Are you sure you wish to clear Reputation System?', 53 | 'RS_TRUNCATE_DONE' => 'Reputations were cleared.', 54 | 55 | 'REPUTATION_SETTINGS_CHANGED' => 'Altered Reputation System settings', 56 | 57 | // Setting legend 58 | 'ACP_RS_MAIN' => 'General', 59 | 'ACP_RS_DISPLAY' => 'Display settings', 60 | 'ACP_RS_POSTS_RATING' => 'Post rating', 61 | 'ACP_RS_USERS_RATING' => 'User rating', 62 | 'ACP_RS_COMMENT' => 'Comments', 63 | 'ACP_RS_POWER' => 'Reputation power', 64 | 'ACP_RS_TOPLIST' => 'Toplist', 65 | 66 | // General 67 | 'RS_NEGATIVE_POINT' => 'Allow negative points', 68 | 'RS_NEGATIVE_POINT_EXPLAIN' => 'When disabled users can not give negative points.', 69 | 'RS_MIN_REP_NEGATIVE' => 'Minimum reputation for negative voting', 70 | 'RS_MIN_REP_NEGATIVE_EXPLAIN' => 'How much reputation is required to give negative points. Setting the value to 0 disables this behaviour.', 71 | 'RS_WARNING' => 'Enable warnings', 72 | 'RS_WARNING_EXPLAIN' => 'Users with proper permissions can give negative points when warning users.', 73 | 'RS_WARNING_MAX_POWER' => 'Maximum reputation power for warnings', 74 | 'RS_WARNING_MAX_POWER_EXPLAIN' => 'Maximum reputation power allowed for warnings.', 75 | 'RS_MIN_POINT' => 'Minimum points', 76 | 'RS_MIN_POINT_EXPLAIN' => 'Limits the minimum reputation points a user can receive. Setting the value to 0 disables this behaviour.', 77 | 'RS_MAX_POINT' => 'Maximum points', 78 | 'RS_MAX_POINT_EXPLAIN' => 'Limits the maximum reputation points a user can receive. Setting the value to 0 disables this behaviour.', 79 | 'RS_PREVENT_OVERRATING' => 'Prevent overrating', 80 | 'RS_PREVENT_OVERRATING_EXPLAIN' => 'Block users from rating the same user.
    Example: if user A has more than 10 reputation entries and 85% of them come from user B, user B can not rate that user until his votes ratio is higher than 85%.
    To disable this feature set one or both values to 0.', 81 | 'RS_PREVENT_NUM' => 'Total reputation entries of user A is equal to or higher than', 82 | 'RS_PREVENT_PERC' => '
    and ratio of user B votes is equal to or higher than', 83 | 'RS_PER_PAGE' => 'Reputations per page', 84 | 'RS_PER_PAGE_EXPLAIN' => 'How many rows should we display in tables of reputation points?', 85 | 'RS_DISPLAY_AVATAR' => 'Display avatars', 86 | 'RS_POINT_TYPE' => 'Method for displaying points', 87 | 'RS_POINT_TYPE_EXPLAIN' => 'Viewing reputation points can be displayed as either the exact value of reputation points a user gave or as an image showing a plus or minus for positive or negative points. The Image method is useful if you set up reputation points so that one rating always equals to one point.', 88 | 'RS_POINT_VALUE' => 'Value', 89 | 'RS_POINT_IMG' => 'Image', 90 | 91 | // Post rating 92 | 'RS_POST_RATING' => 'Enable post rating', 93 | 'RS_POST_RATING_EXPLAIN' => 'Allow users to rate other user posts.
    On each forums management page you can enable or disable reputations.', 94 | 'RS_ALLOW_REPUTATION_BUTTON' => 'Submit and enable Reputation System in all forums', 95 | 'RS_ANTISPAM' => 'Anti-Spam', 96 | 'RS_ANTISPAM_EXPLAIN' => 'Block users from rating any more posts after they have rated the defined number of posts within the defined number of hours. To disable this feature set one or both values to 0.', 97 | 'RS_POSTS' => 'Number of rated posts', 98 | 'RS_HOURS' => 'in the last hours', 99 | 'RS_ANTISPAM_METHOD' => 'Anti-Spam check method', 100 | 'RS_ANTISPAM_METHOD_EXPLAIN' => 'Method for checking Anti-Spam. “Same user” method checks reputation given to the same user. “All users” method checks reputation regardless of who received points.', 101 | 'RS_SAME_USER' => 'Same user', 102 | 'RS_ALL_USERS' => 'All users', 103 | 104 | // User rating 105 | 'RS_USER_RATING' => 'Allow rating of users from their profile page', 106 | 'RS_USER_RATING_GAP' => 'Voting gap', 107 | 'RS_USER_RATING_GAP_EXPLAIN' => 'Time period a user must wait before they can give another rating to a user they have already rated. Setting the value to 0 disables this behaviour and users can rate other users once each.', 108 | 109 | // Comments 110 | 'RS_ENABLE_COMMENT' => 'Enable comments', 111 | 'RS_ENABLE_COMMENT_EXPLAIN' => 'When enabled, users will be able to add a personal comment with their rating.', 112 | 'RS_FORCE_COMMENT' => 'Force user to enter comment', 113 | 'RS_FORCE_COMMENT_EXPLAIN' => 'Users will be required to add a comment with their rating.', 114 | 'RS_COMMENT_NO' => 'No', 115 | 'RS_COMMENT_BOTH' => 'Both user and post ratings', 116 | 'RS_COMMENT_POST' => 'Only post ratings', 117 | 'RS_COMMENT_USER' => 'Only user ratings', 118 | 'RS_COMMEN_LENGTH' => 'Comment length', 119 | 'RS_COMMEN_LENGTH_EXPLAIN' => 'The number of characters allowed within a comment. Set to 0 for unlimited characters.', 120 | 121 | // Reputation power 122 | 'RS_ENABLE_POWER' => 'Enable reputation power', 123 | 'RS_ENABLE_POWER_EXPLAIN' => 'Reputation power is something that users earn and spend on voting. New users have low power, active and veteran users gain more power. The more power you have the more you can vote during a specified period of time and the more influence you can have on the rating of another user or post.
    Users can choose during voting how much power they will spend on a vote, giving more points to interesting posts.', 124 | 'RS_POWER_RENEWAL' => 'Power renewal time', 125 | 'RS_POWER_RENEWAL_EXPLAIN' => 'This controls how users can spend earned power.
    If you set this option, users must wait for the given time interval before they can vote again. The more reputation power a user has, the more points they can spend in the set time.
    Setting the value to 0 disables this behaviour and users can vote without waiting.', 126 | 'RS_MIN_POWER' => 'Starting/Minimum reputation power', 127 | 'RS_MIN_POWER_EXPLAIN' => 'This is how much reputation power newly registered users, banned users and users with low reputation or other criteria have. Users can’t go lower than this minimum voting power.
    Allowed 0-10. Recommended 1.', 128 | 'RS_MAX_POWER' => 'Maximum power spending per vote', 129 | 'RS_MAX_POWER_EXPLAIN' => 'Maximum amount of power that a user can spend per vote. Even if a user has millions of points, they’ll still be limited by this maximum number when voting.
    Users will select this from dropdown menu: 1 to X
    Allowed 1-20. Recommended: 3.', 130 | 'RS_POWER_EXPLAIN' => 'Reputation power explanation', 131 | 'RS_POWER_EXPLAIN_EXPLAIN' => 'Explain how reputation power is calculated to users.', 132 | 'RS_TOTAL_POSTS' => 'Gain power with number of posts', 133 | 'RS_TOTAL_POSTS_EXPLAIN' => 'User will gain 1 reputation power every X number of posts set here.', 134 | 'RS_MEMBERSHIP_DAYS' => 'Gain power with length of the user’s membership', 135 | 'RS_MEMBERSHIP_DAYS_EXPLAIN' => 'User will gain 1 reputation power every X number of days set here', 136 | 'RS_POWER_REP_POINT' => 'Gain power with the user’s reputation', 137 | 'RS_POWER_REP_POINT_EXPLAIN' => 'User will gain 1 reputation power every X number of reputation points they earn set here.', 138 | 'RS_LOSE_POWER_WARN' => 'Lose power with warnings', 139 | 'RS_LOSE_POWER_WARN_EXPLAIN' => 'Each warning decreases reputation power by this amount of points. Warnings expire in accordance with the settings in General -> Board Configuration -> Board settings', 140 | 141 | // Toplist 142 | 'RS_ENABLE_TOPLIST' => 'Enable Toplist', 143 | 'RS_ENABLE_TOPLIST_EXPLAIN' => 'Display a list of users with the most reputation points on the index page.', 144 | 'RS_TOPLIST_DIRECTION' => 'Direction of list', 145 | 'RS_TOPLIST_DIRECTION_EXPLAIN' => 'Display the users in the list in a horizontal or vertical direction.', 146 | 'RS_TL_HORIZONTAL' => 'Horizontal', 147 | 'RS_TL_VERTICAL' => 'Vertical', 148 | 'RS_TOPLIST_NUM' => 'Number of Users to Display', 149 | 'RS_TOPLIST_NUM_EXPLAIN' => 'Number of users displayed on the toplist.', 150 | 151 | // Rate module 152 | 'POINTS_INVALID' => 'Points field has to contain only numbers.', 153 | 'RS_VOTE_SAVED' => 'Your vote has been saved successfully', 154 | )); 155 | -------------------------------------------------------------------------------- /controller/action_controller.php: -------------------------------------------------------------------------------- 1 | auth = $auth; 67 | $this->db = $db; 68 | $this->helper = $helper; 69 | $this->request = $request; 70 | $this->user = $user; 71 | $this->reputation_helper = $reputation_helper; 72 | $this->reputation_manager = $reputation_manager; 73 | $this->reputations_table = $reputations_table; 74 | $this->reputation_types_table = $reputation_types_table; 75 | $this->root_path = $root_path; 76 | $this->php_ext = $php_ext; 77 | } 78 | 79 | /** 80 | * Delete reputation page/action 81 | * 82 | * @param int $rid Reputation ID taken from the URL 83 | * @return null 84 | * @access public 85 | */ 86 | public function delete($rid) 87 | { 88 | $this->user->add_lang_ext('pico/reputation', 'reputation_system'); 89 | $is_ajax = $this->request->is_ajax(); 90 | $submit = false; 91 | 92 | $post_type_id = (int) $this->reputation_manager->get_reputation_type_id('post'); 93 | 94 | $sql_array = array( 95 | 'SELECT' => 'r.*, rt.reputation_type_name, p.post_id, uf.username AS username_from, ut.username AS username_to', 96 | 'FROM' => array( 97 | $this->reputations_table => 'r', 98 | $this->reputation_types_table => 'rt', 99 | ), 100 | 'LEFT_JOIN' => array( 101 | array( 102 | 'FROM' => array(POSTS_TABLE => 'p'), 103 | 'ON' => 'p.post_id = r.reputation_item_id 104 | AND r.reputation_type_id = ' . $post_type_id, 105 | ), 106 | array( 107 | 'FROM' => array(USERS_TABLE => 'uf'), 108 | 'ON' => 'r.user_id_from = uf.user_id ', 109 | ), 110 | array( 111 | 'FROM' => array(USERS_TABLE => 'ut'), 112 | 'ON' => 'r.user_id_to = ut.user_id ', 113 | ), 114 | ), 115 | 'WHERE' => 'r.reputation_id = ' . $rid, 116 | ); 117 | $sql = $this->db->sql_build_query('SELECT', $sql_array); 118 | $result = $this->db->sql_query($sql); 119 | $row = $this->db->sql_fetchrow($result); 120 | $this->db->sql_freeresult($result); 121 | 122 | //We couldn't find this reputation. May be it was deleted meanwhile? 123 | if (empty($row)) 124 | { 125 | $message = $this->user->lang('RS_NO_REPUTATION'); 126 | $json_data = array( 127 | 'error_msg' => $message, 128 | ); 129 | $redirect = append_sid("{$this->root_path}index.$this->php_ext"); 130 | $redirect_text = 'RETURN_INDEX'; 131 | 132 | $this->reputation_manager->response($message, $json_data, $redirect, $redirect_text, $is_ajax); 133 | } 134 | 135 | if ($this->request->is_set_post('cancel')) 136 | { 137 | redirect($this->helper->route('reputation_details_controller', array('uid' => $row['user_id_to']))); 138 | } 139 | 140 | if ($this->auth->acl_gets('m_rs_moderate') || (($row['user_id_from'] == $this->user->data['user_id']) && $this->auth->acl_get('u_rs_delete'))) 141 | { 142 | if ($is_ajax) 143 | { 144 | $submit = true; 145 | } 146 | else 147 | { 148 | $s_hidden_fields = build_hidden_fields(array( 149 | 'r' => $rid, 150 | )); 151 | 152 | if (confirm_box(true)) 153 | { 154 | $submit = true; 155 | } 156 | else 157 | { 158 | confirm_box(false, $this->user->lang('RS_REPUTATION_DELETE_CONFIRM'), $s_hidden_fields); 159 | } 160 | } 161 | } 162 | else 163 | { 164 | $message = $this->user->lang('RS_USER_CANNOT_DELETE'); 165 | $json_data = array( 166 | 'error_msg' => $message, 167 | ); 168 | $redirect = $this->helper->route('reputation_details_controller', array('uid' => $row['user_id_to'])); 169 | $redirect_text = 'RETURN_PAGE'; 170 | 171 | $this->reputation_manager->response($message, $json_data, $redirect, $redirect_text, $is_ajax); 172 | } 173 | 174 | if ($submit) 175 | { 176 | try 177 | { 178 | $this->reputation_manager->delete_reputation($row); 179 | } 180 | catch (\pico\reputation\exception\base $e) 181 | { 182 | // Catch exception 183 | trigger_error($e->get_message($this->user)); 184 | } 185 | 186 | $user_reputation = $this->reputation_manager->get_user_reputation($row['user_id_to']); 187 | 188 | $message = $this->user->lang('RS_POINTS_DELETED'); 189 | $json_data = array( 190 | 'rid' => $rid, 191 | 'user_reputation' => $user_reputation, 192 | ); 193 | 194 | if (isset($row['post_id'])) 195 | { 196 | $post_reputation = $this->reputation_manager->get_post_reputation($row['post_id']); 197 | 198 | $json_data = array_merge($json_data, array( 199 | 'poster_id' => $row['user_id_to'], 200 | 'post_id' => $row['post_id'], 201 | 'post_reputation' => $post_reputation, 202 | 'reputation_class' => $this->reputation_helper->reputation_class($post_reputation), 203 | 'own_vote' => ($row['user_id_from'] == $this->user->data['user_id']) ? true : false, 204 | )); 205 | } 206 | 207 | $redirect = $this->helper->route('reputation_details_controller', array('uid' => $row['user_id_to'])); 208 | $redirect_text = 'RETURN_PAGE'; 209 | 210 | $this->reputation_manager->response($message, $json_data, $redirect, $redirect_text, $is_ajax); 211 | } 212 | } 213 | 214 | /** 215 | * Clear post reputation 216 | * 217 | * @param int $post_id Post ID 218 | * @return null 219 | * @access public 220 | */ 221 | public function clear_post($post_id) 222 | { 223 | $this->user->add_lang_ext('pico/reputation', 'reputation_system'); 224 | $is_ajax = $this->request->is_ajax(); 225 | $submit = false; 226 | $post_type_id = (int) $this->reputation_manager->get_reputation_type_id('post'); 227 | 228 | $sql_array = array( 229 | 'SELECT' => 'r.*, p.post_subject, p.post_reputation, ut.username AS username_to', 230 | 'FROM' => array( 231 | $this->reputations_table => 'r', 232 | POSTS_TABLE => 'p', 233 | ), 234 | 'LEFT_JOIN' => array( 235 | array( 236 | 'FROM' => array(USERS_TABLE => 'ut'), 237 | 'ON' => 'r.user_id_to = ut.user_id ', 238 | ), 239 | ), 240 | 'WHERE' => 'r.reputation_item_id = ' . $post_id . ' 241 | AND r.reputation_type_id = ' . $post_type_id . ' 242 | AND p.post_id = r.reputation_item_id', 243 | ); 244 | $sql = $this->db->sql_build_query('SELECT', $sql_array); 245 | $result = $this->db->sql_query($sql); 246 | $row = $this->db->sql_fetchrow($result); 247 | $this->db->sql_freeresult($result); 248 | 249 | //We couldn't find this reputation. May be it was deleted meanwhile? 250 | if (empty($row)) 251 | { 252 | $message = $this->user->lang('RS_NO_REPUTATION'); 253 | $json_data = array( 254 | 'error_msg' => $message, 255 | ); 256 | $redirect = append_sid("{$this->root_path}index.$this->php_ext"); 257 | $redirect_text = 'RETURN_INDEX'; 258 | 259 | $this->reputation_manager->response($message, $json_data, $redirect, $redirect_text, $is_ajax); 260 | } 261 | 262 | $redirect = $this->helper->route('reputation_post_details_controller', array('post_id' => $post_id)); 263 | 264 | if ($this->request->is_set_post('cancel')) 265 | { 266 | redirect($redirect); 267 | } 268 | 269 | $redirect_text = 'RETURN_PAGE'; 270 | 271 | if ($this->auth->acl_gets('m_rs_moderate')) 272 | { 273 | if ($is_ajax) 274 | { 275 | $submit = true; 276 | } 277 | else 278 | { 279 | $s_hidden_fields = build_hidden_fields(array( 280 | 'p' => $post_id, 281 | )); 282 | 283 | if (confirm_box(true)) 284 | { 285 | $submit = true; 286 | } 287 | else 288 | { 289 | confirm_box(false, $this->user->lang('RS_CLEAR_POST_CONFIRM'), $s_hidden_fields); 290 | } 291 | } 292 | } 293 | else 294 | { 295 | $message = $this->user->lang('RS_USER_CANNOT_DELETE'); 296 | $json_data = array( 297 | 'error_msg' => $message, 298 | ); 299 | 300 | $this->reputation_manager->response($message, $json_data, $redirect, $redirect_text, $is_ajax); 301 | } 302 | 303 | if ($submit) 304 | { 305 | try 306 | { 307 | $this->reputation_manager->clear_post_reputation($post_id, $row); 308 | } 309 | catch (\pico\reputation\exception\base $e) 310 | { 311 | // Catch exception 312 | trigger_error($e->get_message($this->user)); 313 | } 314 | 315 | $message = $this->user->lang('RS_CLEARED_POST'); 316 | $json_data = array( 317 | 'clear_post' => true, 318 | 'post_id' => $post_id, 319 | 'poster_id' => $row['user_id_to'], 320 | 'user_reputation' => $this->reputation_manager->get_user_reputation($row['user_id_to']), 321 | 'post_reputation' => 0, 322 | 'reputation_class' => 'neutral', 323 | ); 324 | 325 | $this->reputation_manager->response($message, $json_data, $redirect, $redirect_text, $is_ajax); 326 | } 327 | } 328 | 329 | /** 330 | * Clear user reputation 331 | * 332 | * @param int $uid User ID 333 | * @return null 334 | * @access public 335 | */ 336 | public function clear_user($uid) 337 | { 338 | $this->user->add_lang_ext('pico/reputation', 'reputation_system'); 339 | $is_ajax = $this->request->is_ajax(); 340 | $submit = false; 341 | 342 | $sql_array = array( 343 | 'SELECT' => 'r.*, ut.username AS username_to', 344 | 'FROM' => array( 345 | $this->reputations_table => 'r', 346 | ), 347 | 'LEFT_JOIN' => array( 348 | array( 349 | 'FROM' => array(USERS_TABLE => 'ut'), 350 | 'ON' => 'r.user_id_to = ut.user_id ', 351 | ), 352 | ), 353 | 'WHERE' => 'r.user_id_to = ' . $uid 354 | ); 355 | $sql = $this->db->sql_build_query('SELECT', $sql_array); 356 | $result = $this->db->sql_query($sql); 357 | $row = $this->db->sql_fetchrow($result); 358 | $this->db->sql_freeresult($result); 359 | 360 | //We couldn't find this reputation. May be it was deleted meanwhile? 361 | if (empty($row)) 362 | { 363 | $message = $this->user->lang('RS_NO_REPUTATION'); 364 | $json_data = array( 365 | 'error_msg' => $message, 366 | ); 367 | $redirect = append_sid("{$this->root_path}index.$this->php_ext"); 368 | $redirect_text = 'RETURN_INDEX'; 369 | 370 | $this->reputation_manager->response($message, $json_data, $redirect, $redirect_text, $is_ajax); 371 | } 372 | 373 | $redirect = $this->helper->route('reputation_details_controller', array('uid' => $uid)); 374 | 375 | if ($this->request->is_set_post('cancel')) 376 | { 377 | redirect($redirect); 378 | } 379 | 380 | $post_ids = array(); 381 | $post_type_id = (int) $this->reputation_manager->get_reputation_type_id('post'); 382 | 383 | $sql = 'SELECT reputation_item_id 384 | FROM ' . $this->reputations_table . " 385 | WHERE user_id_to = {$uid} 386 | AND reputation_type_id = {$post_type_id} 387 | GROUP BY reputation_item_id"; 388 | $result = $this->db->sql_query($sql); 389 | 390 | while ($post_row = $this->db->sql_fetchrow($result)) 391 | { 392 | $post_ids[] = $post_row['reputation_item_id']; 393 | } 394 | $this->db->sql_freeresult($result); 395 | 396 | $redirect_text = 'RETURN_PAGE'; 397 | 398 | if ($this->auth->acl_gets('m_rs_moderate')) 399 | { 400 | if ($is_ajax) 401 | { 402 | $submit = true; 403 | } 404 | else 405 | { 406 | $s_hidden_fields = build_hidden_fields(array( 407 | 'u' => $uid, 408 | )); 409 | 410 | if (confirm_box(true)) 411 | { 412 | $submit = true; 413 | } 414 | else 415 | { 416 | confirm_box(false, $this->user->lang('RS_CLEAR_POST_CONFIRM'), $s_hidden_fields); 417 | } 418 | } 419 | } 420 | else 421 | { 422 | $message = $this->user->lang('RS_USER_CANNOT_DELETE'); 423 | $json_data = array( 424 | 'error_msg' => $message, 425 | ); 426 | 427 | $this->reputation_manager->response($message, $json_data, $redirect, $redirect_text, $is_ajax); 428 | } 429 | 430 | if ($submit) 431 | { 432 | try 433 | { 434 | $this->reputation_manager->clear_user_reputation($uid, $row, $post_ids); 435 | } 436 | catch (\pico\reputation\exception\base $e) 437 | { 438 | // Catch exception 439 | trigger_error($e->get_message($this->user)); 440 | } 441 | 442 | $message = $this->user->lang('RS_CLEARED_USER'); 443 | $json_data = array( 444 | 'clear_user' => true, 445 | 'post_ids' => $post_ids, 446 | 'poster_id' => $uid, 447 | 'user_reputation' => 0, 448 | 'post_reputation' => 0, 449 | 'reputation_class' => 'neutral', 450 | ); 451 | 452 | $this->reputation_manager->response($message, $json_data, $redirect, $redirect_text, $is_ajax); 453 | } 454 | } 455 | } 456 | -------------------------------------------------------------------------------- /core/reputation_manager.php: -------------------------------------------------------------------------------- 1 | auth = $auth; 80 | $this->cache = $cache; 81 | $this->config = $config; 82 | $this->db = $db; 83 | $this->log = $log; 84 | $this->notification_manager = $notification_manager; 85 | $this->template = $template; 86 | $this->user = $user; 87 | $this->reputations_table = $reputations_table; 88 | $this->reputation_types_table = $reputation_types_table; 89 | $this->root_path = $root_path; 90 | $this->php_ext = $php_ext; 91 | } 92 | 93 | /** 94 | * Get the reputation types 95 | * 96 | * @return array Reputation types 97 | * @access public 98 | */ 99 | public function get_reputation_types() 100 | { 101 | $reputation_type_ids = $this->cache->get('reputation_type_ids'); 102 | 103 | if ($reputation_type_ids === false) 104 | { 105 | $reputation_type_ids = array(); 106 | 107 | $sql = 'SELECT * 108 | FROM ' . $this->reputation_types_table; 109 | $result = $this->db->sql_query($sql); 110 | while ($row = $this->db->sql_fetchrow($result)) 111 | { 112 | $reputation_type_ids[(int) $row['reputation_type_id']] = (string) $row['reputation_type_name']; 113 | } 114 | $this->db->sql_freeresult($result); 115 | 116 | $this->cache->put('reputation_type_ids', $reputation_type_ids); 117 | } 118 | 119 | return $reputation_type_ids; 120 | } 121 | 122 | /** 123 | * Get reputation type id from string 124 | * 125 | * @param string $type_string 126 | * @return int $type_id 127 | * @access public 128 | */ 129 | public function get_reputation_type_id($type_string) 130 | { 131 | $types = $this->get_reputation_types(); 132 | 133 | $type_id = array_search($type_string, $types); 134 | 135 | if (empty($type_id)) 136 | { 137 | throw new \pico\reputation\exception\invalid_argument(array('reputation_type', 'INVALID_TYPE')); 138 | } 139 | 140 | return $type_id; 141 | } 142 | 143 | /** 144 | * The main function for recording reputation vote. 145 | * 146 | * @param array $data Reputation data 147 | * @access public 148 | * @return null 149 | */ 150 | public function store_reputation($data) 151 | { 152 | $data['reputation_time'] = time(); 153 | 154 | $fields = array( 155 | 'user_id_from' => 'integer', 156 | 'user_id_to' => 'integer', 157 | 'reputation_time' => 'integer', 158 | 'reputation_type' => 'string', 159 | 'reputation_item_id' => 'integer', 160 | 'reputation_points' => 'integer', 161 | 'reputation_comment' => 'string', 162 | ); 163 | 164 | foreach ($fields as $field => $type) 165 | { 166 | if (!isset($data[$field])) 167 | { 168 | throw new \pico\reputation\exception\invalid_argument(array($field, 'FIELD_MISSING')); 169 | } 170 | 171 | $value = $data[$field]; 172 | 173 | settype($value, $type); 174 | 175 | $data[$field] = $value; 176 | } 177 | 178 | // Get reputation type id 179 | $data['reputation_type_id'] = $this->get_reputation_type_id($data['reputation_type']); 180 | 181 | // Unset reputation type - it is not stored in DB 182 | unset($data['reputation_type']); 183 | 184 | $validate_unsigned = array( 185 | 'user_id_from', 186 | 'user_id_to', 187 | 'reputation_time', 188 | 'reputation_type_id', 189 | 'reputation_item_id', 190 | ); 191 | 192 | foreach ($validate_unsigned as $field) 193 | { 194 | if ($data[$field] < 0) 195 | { 196 | throw new \pico\reputation\exception\out_of_bounds($field); 197 | } 198 | } 199 | 200 | // Save reputation vote 201 | $sql = 'INSERT INTO ' . $this->reputations_table . ' ' . $this->db->sql_build_array('INSERT', $data); 202 | $this->db->sql_query($sql); 203 | 204 | unset($this->reputation_id); 205 | $this->reputation_id = $this->db->sql_nextid(); 206 | 207 | // Update post reputation 208 | if ($data['reputation_type_id'] == $this->get_reputation_type_id('post')) 209 | { 210 | $sql = 'UPDATE ' . POSTS_TABLE . " 211 | SET post_reputation = post_reputation + {$data['reputation_points']} 212 | WHERE post_id = {$data['reputation_item_id']}"; 213 | $this->db->sql_query($sql); 214 | } 215 | 216 | // Update user reputation 217 | $sql = 'UPDATE ' . USERS_TABLE . " 218 | SET user_reputation = user_reputation + {$data['reputation_points']} 219 | WHERE user_id = {$data['user_id_to']}"; 220 | $this->db->sql_query($sql); 221 | 222 | // Check max/min user points 223 | if ($this->config['rs_max_point'] || $this->config['rs_min_point']) 224 | { 225 | $this->check_max_min($data['user_id_to']); 226 | } 227 | } 228 | 229 | /** 230 | * Check user reputation 231 | * 232 | * If it is higher than allowed, decrease it to maximum. 233 | * If it is lower than allowed, increase it to minimum. 234 | * 235 | * @param int $user_id User ID 236 | * @access public 237 | * @return null 238 | */ 239 | private function check_max_min($user_id) 240 | { 241 | $sql = 'SELECT SUM(reputation_points) AS points 242 | FROM ' . $this->reputations_table . ' 243 | WHERE user_id_to = ' . (int) $user_id; 244 | $result = $this->db->sql_query($sql); 245 | $points = $this->db->sql_fetchfield('points'); 246 | $this->db->sql_freeresult($result); 247 | 248 | // Maximum user reputation 249 | if (($points > $this->config['rs_max_point']) && $this->config['rs_max_point']) 250 | { 251 | $sql = 'UPDATE ' . USERS_TABLE . " 252 | SET user_reputation = {$this->config['rs_max_point']} 253 | WHERE user_id = $user_id"; 254 | $this->db->sql_query($sql); 255 | } 256 | 257 | // Minimum user reputation 258 | if (($points < $this->config['rs_min_point']) && $this->config['rs_min_point']) 259 | { 260 | $sql = 'UPDATE ' . USERS_TABLE . " 261 | SET user_reputation = {$this->config['rs_min_point']} 262 | WHERE user_id = $user_id"; 263 | $this->db->sql_query($sql); 264 | } 265 | } 266 | 267 | /** 268 | * Notify user about reputation 269 | * 270 | * @param string $notification_type_name Notification type name 271 | * @param array $data Notification data 272 | * @access public 273 | * @return null 274 | */ 275 | public function add_notification($notification_type_name, $data) 276 | { 277 | $data = array_merge( 278 | array('reputation_id' => $this->reputation_id), 279 | $data 280 | ); 281 | $this->notification_manager->add_notifications($notification_type_name, $data); 282 | } 283 | 284 | /** 285 | * Response method for displaying reputation messages 286 | * 287 | * @param string $message_lang Message user lang 288 | * @param array $json_data Json data for ajax request 289 | * @param string $redirect_link Redirect link 290 | * @param string $redirect_text Redirect text 291 | * @param bool $is_ajax Ajax request 292 | * @access public 293 | * @return string 294 | */ 295 | public function response($message_lang, $json_data, $redirect_link, $redirect_text, $is_ajax = false) 296 | { 297 | $redirect = $redirect_link; 298 | 299 | meta_refresh(3, $redirect); 300 | 301 | $message = $message_lang; 302 | 303 | if ($is_ajax) 304 | { 305 | $json_response = new \phpbb\json_response(); 306 | $json_response->send($json_data); 307 | } 308 | 309 | $message .= '

    ' . $this->user->lang($redirect_text, '', ''); 310 | trigger_error($message); 311 | } 312 | 313 | /** 314 | * Return post reputation 315 | * 316 | * @param int $post_id Post ID 317 | * @access public 318 | * @return int post reputation 319 | */ 320 | public function get_post_reputation($post_id) 321 | { 322 | $sql = 'SELECT post_reputation 323 | FROM ' . POSTS_TABLE . " 324 | WHERE post_id = $post_id"; 325 | $result = $this->db->sql_query($sql); 326 | $row = $this->db->sql_fetchrow($result); 327 | $this->db->sql_freeresult($result); 328 | 329 | return $row['post_reputation']; 330 | } 331 | 332 | /** 333 | * Return user reputation 334 | * 335 | * @param int $user_id User ID 336 | * @access public 337 | * @return int user reputation 338 | */ 339 | public function get_user_reputation($user_id) 340 | { 341 | $sql = 'SELECT user_reputation 342 | FROM ' . USERS_TABLE . " 343 | WHERE user_id = $user_id"; 344 | $result = $this->db->sql_query($sql); 345 | $row = $this->db->sql_fetchrow($result); 346 | $this->db->sql_freeresult($result); 347 | 348 | return $row['user_reputation']; 349 | } 350 | 351 | /** 352 | * Prevent overrating one user by another user 353 | * 354 | * @param int $user_id User ID 355 | * @access public 356 | * @return bool 357 | */ 358 | public function prevent_rating($user_id) 359 | { 360 | if (!$this->config['rs_prevent_num'] || !$this->config['rs_prevent_perc']) 361 | { 362 | return false; 363 | } 364 | 365 | $total_reps = $same_user = 0; 366 | 367 | $post_type = (int) $this->get_reputation_type_id('post'); 368 | $user_type = (int) $this->get_reputation_type_id('user'); 369 | 370 | $sql = 'SELECT user_id_from 371 | FROM ' . $this->reputations_table . " 372 | WHERE user_id_to = {$user_id} 373 | AND (reputation_type_id = {$post_type} OR reputation_type_id = {$user_type})"; 374 | $result = $this->db->sql_query($sql); 375 | 376 | while ($row = $this->db->sql_fetchrow($result)) 377 | { 378 | $total_reps++; 379 | 380 | if ($row['user_id_from'] == $this->user->data['user_id']) 381 | { 382 | $same_user++; 383 | } 384 | } 385 | $this->db->sql_freeresult($result); 386 | 387 | if (($total_reps >= $this->config['rs_prevent_num']) && ($same_user / $total_reps * 100 >= $this->config['rs_prevent_perc'])) 388 | { 389 | return true; 390 | } 391 | 392 | return false; 393 | } 394 | 395 | /** 396 | * Generet post URL 397 | * 398 | * @param array $row Array with data 399 | * @access public 400 | * @return null 401 | */ 402 | public function generate_post_link($row) 403 | { 404 | $post_subject = $post_url = ''; 405 | 406 | // Post was deleted 407 | if (!isset($row['post_subject']) && !isset($row['post_id'])) 408 | { 409 | $post_subject = $this->user->lang('RS_POST_DELETE'); 410 | } 411 | 412 | // Post exists 413 | if (isset($row['post_id'])) 414 | { 415 | // Check forum read permission 416 | if ($this->auth->acl_get('f_read', $row['forum_id'])) 417 | { 418 | $post_subject = $row['post_subject'] . ' [#p' . $row['post_id'] . ']'; 419 | $post_url = append_sid("{$this->root_path}viewtopic.$this->php_ext", 'f=' . $row['forum_id'] . '&p=' . $row['post_id'] . '#p' . $row['post_id']); 420 | } 421 | } 422 | 423 | $this->template->assign_block_vars('reputation.post', array( 424 | 'POST_SUBJECT' => $post_subject, 425 | 'U_POST' => $post_url, 426 | 'S_POST' => $row['reputation_type_id'] == $this->get_reputation_type_id('post'), 427 | )); 428 | } 429 | 430 | /** 431 | * Delete single reputation 432 | * 433 | * @param array $data Reputation data 434 | * @access public 435 | * @return null 436 | */ 437 | public function delete_reputation($data) 438 | { 439 | // Required fields 440 | $fields = array( 441 | 'user_id_from', 442 | 'user_id_to', 443 | 'reputation_item_id', 444 | 'reputation_points', 445 | 'reputation_type_name', 446 | ); 447 | 448 | foreach ($fields as $field) 449 | { 450 | if (!isset($data[$field])) 451 | { 452 | throw new \pico\reputation\exception\invalid_argument(array($field, 'FIELD_MISSING')); 453 | } 454 | } 455 | 456 | if ($data['reputation_type_id'] == $this->get_reputation_type_id('post')) 457 | { 458 | $sql = 'UPDATE ' . POSTS_TABLE . " 459 | SET post_reputation = post_reputation - {$data['reputation_points']} 460 | WHERE post_id = {$data['reputation_item_id']}"; 461 | $this->db->sql_query($sql); 462 | } 463 | 464 | $sql = 'DELETE FROM ' . $this->reputations_table . " 465 | WHERE reputation_id = {$data['reputation_id']}"; 466 | $this->db->sql_query($sql); 467 | 468 | $sql = 'UPDATE ' . USERS_TABLE . " 469 | SET user_reputation = user_reputation - {$data['reputation_points']} 470 | WHERE user_id = {$data['user_id_to']}"; 471 | $this->db->sql_query($sql); 472 | 473 | // Check max/min points 474 | if ($this->config['rs_max_point'] || $this->config['rs_min_point']) 475 | { 476 | $this->check_max_min($data['user_id_to']); 477 | } 478 | 479 | $this->log->add('admin', $this->user->data['user_id'], $this->user->ip, 'LOG_REPUTATION_DELETED', false, array( 480 | 'user_id_from' => (isset($data['username_from'])) ? $data['username_from'] : $data['user_id_from'], 481 | 'user_id_to' => (isset($data['username_to'])) ? $data['username_to'] : $data['user_id_to'], 482 | 'points' => $data['reputation_points'], 483 | 'type_name' => $data['reputation_type_name'], 484 | 'item_id' => $data['reputation_item_id'], 485 | )); 486 | } 487 | 488 | /** 489 | * Clear post reputation 490 | * 491 | * @param int $post_id Post id 492 | * @param array $data Reputation data 493 | * @access public 494 | * @return null 495 | */ 496 | public function clear_post_reputation($post_id, $data) 497 | { 498 | // Required fields 499 | $fields = array( 500 | 'user_id_to', 501 | 'reputation_item_id', 502 | 'reputation_type_id', 503 | 'post_reputation', 504 | ); 505 | 506 | foreach ($fields as $field) 507 | { 508 | if (!isset($data[$field])) 509 | { 510 | throw new \pico\reputation\exception\invalid_argument(array($field, 'FIELD_MISSING')); 511 | } 512 | } 513 | 514 | $sql = 'UPDATE ' . POSTS_TABLE . " 515 | SET post_reputation = 0 516 | WHERE post_id = {$post_id}"; 517 | $this->db->sql_query($sql); 518 | 519 | $sql = 'UPDATE ' . USERS_TABLE . " 520 | SET user_reputation = user_reputation - {$data['post_reputation']} 521 | WHERE user_id = {$data['user_id_to']}"; 522 | $this->db->sql_query($sql); 523 | 524 | // Check max/min points 525 | if ($this->config['rs_max_point'] || $this->config['rs_min_point']) 526 | { 527 | $this->check_max_min($data['user_id_to']); 528 | } 529 | 530 | $sql = 'DELETE FROM ' . $this->reputations_table . " 531 | WHERE reputation_item_id = {$post_id} 532 | AND reputation_type_id = {$data['reputation_type_id']}"; 533 | $this->db->sql_query($sql); 534 | 535 | $this->log->add('admin', $this->user->data['user_id'], $this->user->ip, 'LOG_POST_REPUTATION_CLEARED', false, array( 536 | 'user_id_to' => (isset($data['username_to'])) ? $data['username_to'] : $data['user_id_to'], 537 | 'post_subject' => (isset($data['post_subject'])) ? $data['post_subject'] : $data['reputation_item_id'], 538 | )); 539 | } 540 | 541 | /** 542 | * Clear user reputation 543 | * 544 | * @param int $user_id User id 545 | * @param array $data Reputation data 546 | * @param arrat $post_ids Post IDs 547 | * @access public 548 | * @return null 549 | */ 550 | public function clear_user_reputation($user_id, $data, $post_ids) 551 | { 552 | // Required fields 553 | $fields = array( 554 | 'user_id_to', 555 | 'reputation_item_id', 556 | ); 557 | 558 | foreach ($fields as $field) 559 | { 560 | if (!isset($data[$field])) 561 | { 562 | throw new \pico\reputation\exception\invalid_argument(array($field, 'FIELD_MISSING')); 563 | } 564 | } 565 | 566 | $sql = 'UPDATE ' . USERS_TABLE . " 567 | SET user_reputation = 0 568 | WHERE user_id = {$user_id}"; 569 | $this->db->sql_query($sql); 570 | 571 | $sql = 'UPDATE ' . POSTS_TABLE . ' 572 | SET post_reputation = 0 573 | WHERE ' . $this->db->sql_in_set('post_id', $post_ids, false, true); 574 | $this->db->sql_query($sql); 575 | 576 | $sql = 'DELETE FROM ' . $this->reputations_table . " 577 | WHERE user_id_to = {$user_id}"; 578 | $this->db->sql_query($sql); 579 | 580 | $this->log->add('admin', $this->user->data['user_id'], $this->user->ip, 'LOG_USER_REPUTATION_CLEARED', false, array( 581 | 'user_id_to' => (isset($data['username_to'])) ? $data['username_to'] : $data['user_id_to'], 582 | )); 583 | } 584 | } 585 | --------------------------------------------------------------------------------