A MyBB-style user reputation system for Discourse. Allows community members to rate each other with positive, neutral, or negative ratings accompanied by comments.
- Features
- Quick Start
- Screenshots
- Installation
- Configuration
- Usage
- API Endpoints
- Database Schema
- Frontend Components
- Architecture
- Development
- Localization
- Troubleshooting
- Contributing
- License
- Three Rating Types: Positive (+1), Neutral (0), Negative (-1)
- One Rating Per Pair: Each user can only have one active rating per target user (can update/delete)
- Required Comments: Configurable minimum character requirement for rating comments
- Configurable Points: Admin-defined point values per rating type
- Moderation Tools: Staff can hide/unhide ratings with reason tracking
- Multiple Display Locations: Show reputation in user cards, posts, and profiles
- Interaction Requirement: Optional toggle to require topic interaction before rating
- Category Filtering: Limit interaction checks to specific categories
- Cooldown Period: Configurable days before a rating can be modified
- Soft Delete: Ratings are soft-deleted with full audit trail
- Localization: Supports multiple languages (English, Spanish included)
# 1. Clone into your Discourse plugins directory cd /var/discourse/plugins git clone https://github.com/JoaquinSantarcangelo/discourse-user-reputation.git # 2. Rebuild the container cd /var/discourse && ./launcher rebuild app # 3. Configure in Admin > Settings > search "user_reputation"For detailed installation options, see Installation.
Reputation score displayed on user profiles with "Rate this user" button.
Reputation breakdown shown in user hover cards.
Modal dialog for creating ratings with positive/neutral/negative options.
User activity page showing all ratings received with full details.
Plugin configuration in the admin panel.
-
Add the plugin to your container configuration
Edit your
app.ymlfile (usually at/var/discourse/containers/app.yml):hooks: after_code: - exec: cd: $home/plugins cmd: - git clone https://github.com/JoaquinSantarcangelo/discourse-user-reputation.git
-
Rebuild the container
cd /var/discourse ./launcher rebuild app -
Configure the plugin
Go to Admin > Settings and search for
user_reputationto configure.
-
Clone the plugin into your plugins directory
cd /path/to/discourse/plugins git clone https://github.com/JoaquinSantarcangelo/discourse-user-reputation.git -
Run database migrations
Important: Plugin migrations require the
LOAD_PLUGINS=1flag to be detected.LOAD_PLUGINS=1 bin/rails db:migrate
-
Restart your Discourse server
bin/rails server
-
Optional: Seed test data
# Create test users bundle exec rake reputation:seed # Create sample ratings bundle exec rake reputation:seed_ratings
Navigate to Admin > Settings and search for user_reputation:
| Setting | Default | Type | Description |
|---|---|---|---|
user_reputation_enabled | true | boolean | Enable/disable the reputation system |
user_reputation_min_trust_level_to_rate | 1 | integer (0-4) | Minimum trust level required to rate users |
user_reputation_min_comment_length | 10 | integer (1-500) | Minimum characters for rating comments |
user_reputation_positive_points | 1 | integer (1-10) | Points awarded for positive ratings |
user_reputation_negative_points | -1 | integer (-10 to -1) | Points deducted for negative ratings |
user_reputation_neutral_points | 0 | integer | Points for neutral ratings |
user_reputation_allow_self_rating | false | boolean | Allow users to rate themselves |
user_reputation_require_interaction | true | boolean | Require topic interaction before rating |
user_reputation_interaction_categories | "" | category_list | Categories where interaction is checked (empty = all) |
user_reputation_cooldown_days | 30 | integer (0-365) | Days before a rating can be modified |
user_reputation_show_in_posts | true | boolean | Display score next to post author name |
user_reputation_show_in_user_card | true | boolean | Display score in user hover cards |
- Rate from Posts: Click the star icon in the post menu to rate the post author
- Rate from Profile: Visit a user's profile and click the rate button (if enabled)
- View Reputation: See a user's full reputation history at
/u/{username}/activity/reputation - Edit/Delete: Modify your own ratings within the cooldown period
- Hide Ratings: Hide inappropriate ratings with optional reason
- Unhide Ratings: Restore hidden ratings
- View All: See hidden ratings and moderation history
Base path: /reputation
| Method | Endpoint | Auth | Description |
|---|---|---|---|
| GET | /users/:username | No | Get user's reputation profile |
| GET | /:id | No | Get a specific rating |
| POST | / | Yes | Create a new rating |
| PUT | /:id | Yes | Update a rating |
| DELETE | /:id | Yes | Delete a rating |
| POST | /:id/hide | Staff | Hide a rating |
| POST | /:id/unhide | Staff | Unhide a rating |
Create Rating:
POST /reputation { "target_user_id": 123, "rating_type": "positive", "comment": "Excellent seller, fast and reliable!", "topic_id": 456 }Response:
{ "id": 789, "author_id": 1, "target_user_id": 123, "rating_type": "positive", "points": 1, "comment": "Excellent seller, fast and reliable!", "created_at": "2024-01-15T10:00:00Z" }Get User Reputation:
GET /reputation/users/username { "score": 15, "breakdown": { "positive": 18, "neutral": 2, "negative": 3 }, "ratings": [...] }Table: user_reputations
| Column | Type | Description |
|---|---|---|
| id | integer | Primary key |
| author_id | integer | User giving the rating (FK to users) |
| target_user_id | integer | User receiving the rating (FK to users) |
| rating_type | integer | -1 (negative), 0 (neutral), 1 (positive) |
| points | integer | Calculated point value |
| comment | text | Required comment text |
| topic_id | integer | Optional linked topic (FK) |
| post_id | integer | Optional linked post (FK) |
| hidden | boolean | Hidden by moderator |
| hidden_by_id | integer | Staff who hid it (FK) |
| hidden_at | datetime | When hidden |
| hidden_reason | text | Reason for hiding |
| deleted_at | datetime | Soft delete timestamp |
| deleted_by_id | integer | User who deleted (FK) |
| created_at | datetime | Creation time |
| updated_at | datetime | Last update time |
Indexes:
author_id- Lookup by rating authortarget_user_id- Lookup by rated user(author_id, target_user_id)UNIQUE WHEREdeleted_at IS NULLtopic_id,rating_type,created_at,deleted_at
| Component | Description |
|---|---|
reputation-score | Score badge with color coding (positive/neutral/negative) |
reputation-rating-modal | Modal dialog for creating/editing ratings |
reputation-list-item | Individual rating display with actions |
rate-author-button | Post menu button to rate author |
post-reputation | Score display next to post author |
reputation-badge | Score in user hover cards |
rate-user-button | Profile button to rate user |
reputation-stat | Score in profile statistics |
reputation-nav | "Reputation" tab in user activity |
Route: /u/:username/activity/reputation
Displays:
- Total score with color coding
- Breakdown by rating type
- Paginated list of all ratings received
- Edit/delete controls for own ratings
- Hide/unhide controls for staff
flowchart TB subgraph Frontend["Frontend (Ember.js)"] UI[UI Components] API[reputation-api.js] Routes[Routes & Templates] end subgraph Backend["Backend (Rails)"] Controller[ReputationController] Engine[ReputationEngine] Model[UserReputation Model] Serializer[UserReputationSerializer] end subgraph Database DB[(user_reputations)] end UI --> API API -->|AJAX| Controller Controller --> Engine Controller --> Model Controller --> Serializer Engine --> Model Model --> DB Serializer -->|JSON| API sequenceDiagram actor User participant Modal as Rating Modal participant API as reputation-api.js participant Controller as ReputationController participant Engine as ReputationEngine participant Model as UserReputation participant DB as Database User->>Modal: Click "Rate User" Modal->>Modal: Select rating type + comment User->>Modal: Submit Modal->>API: createRating(data) API->>Controller: POST /reputation Controller->>Engine: can_rate?(author, target) Engine-->>Controller: true/false alt Can Rate Controller->>Model: create(params) Model->>DB: INSERT DB-->>Model: record Model-->>Controller: reputation Controller-->>API: JSON response API-->>Modal: Success Modal-->>User: Rating created else Cannot Rate Controller-->>API: Error + reason API-->>Modal: Error Modal-->>User: Show error message end erDiagram users ||--o{ user_reputations : "gives ratings" users ||--o{ user_reputations : "receives ratings" topics ||--o{ user_reputations : "optional link" posts ||--o{ user_reputations : "optional link" user_reputations { int id PK int author_id FK int target_user_id FK int rating_type "1/0/-1" int points text comment int topic_id FK int post_id FK boolean hidden int hidden_by_id FK datetime hidden_at text hidden_reason datetime deleted_at int deleted_by_id FK datetime created_at datetime updated_at } graph TD subgraph Profile["User Profile"] RUB[rate-user-button] RS[reputation-stat] end subgraph Card["User Card"] RB[reputation-badge] end subgraph Posts["Post Stream"] RAB[rate-author-button] PR[post-reputation] end subgraph Activity["Activity Page"] RLI[reputation-list-item] RSC[reputation-score] end subgraph Modal["Rating Modal"] RRM[reputation-rating-modal] end RUB -->|opens| RRM RAB -->|opens| RRM RRM -->|creates/updates| RLI discourse-user-reputation/ ├── plugin.rb # Main plugin file ├── README.md # Documentation ├── app/ │ ├── controllers/ │ │ └── reputation_controller.rb │ ├── models/ │ │ └── user_reputation.rb │ └── serializers/ │ └── user_reputation_serializer.rb ├── assets/ │ ├── javascripts/discourse/ │ │ ├── components/ # UI components │ │ ├── connectors/ # Plugin outlets │ │ ├── services/ │ │ │ └── reputation-api.js │ │ ├── routes/ │ │ └── templates/ │ └── stylesheets/ │ └── reputation.scss ├── config/ │ ├── settings.yml # Plugin settings │ └── locales/ # Translations (en, es) ├── db/migrate/ │ └── 20241220000001_create_user_reputations.rb └── lib/ ├── reputation_engine.rb # Business logic └── tasks/ └── seed.rake # Development seed data UserReputation Model:
- Scopes:
active,visible,for_user,by_user,positive_ratings,negative_ratings - Methods:
soft_delete!,hide!,unhide!,can_be_modified_by? - Class methods:
calculate_total_score,breakdown_for,existing_rating
ReputationEngine:
can_rate?(author, target)- Check if rating is allowedcannot_rate_reason(author, target)- Get denial reasonhas_interaction?(user1, user2)- Verify topic interactioncolor_class_for_score(score)- CSS class for styling
User Model Extensions:
reputation_score- Get user's total scorereputation_breakdown- Get count by typecan_rate_user?(target)- Permission check
# Create test users (6 users with different trust levels) bundle exec rake reputation:seed # Create sample reputation ratings between test users bundle exec rake reputation:seed_ratingsTest Users Created:
| Username | Trust Level | Role | Password |
|---|---|---|---|
| seller_trusted | TL3 | User | reputation_test_2024 |
| buyer_new | TL1 | User | reputation_test_2024 |
| user_active | TL2 | User | reputation_test_2024 |
| moderator_rep | TL4 | Moderator | reputation_test_2024 |
| user_problematic | TL0 | User | reputation_test_2024 |
| seller_new | TL2 | User | reputation_test_2024 |
# Ruby specs LOAD_PLUGINS=1 bin/rspec plugins/discourse-user-reputation/spec # JavaScript tests bin/qunit plugins/discourse-user-reputation/testbin/lint plugins/discourse-user-reputationTranslation files in config/locales/:
client.{locale}.yml- Frontend stringsserver.{locale}.yml- Backend strings
Included languages: English (en), Spanish (es)
To add a new language, create the corresponding locale files following the existing structure.
The plugin migrations haven't run. Run migrations with the plugin flag:
LOAD_PLUGINS=1 bin/rails db:migrateThen restart your Rails server.
- Check that the plugin is in the correct directory:
plugins/discourse-user-reputation/ - Ensure
plugin.rbexists in the plugin root - Check Discourse logs for errors:
./launcher logs app
- Verify the plugin is enabled: Admin > Settings > search
user_reputation_enabled - Check display settings:
user_reputation_show_in_posts,user_reputation_show_in_user_card
- Check your trust level meets the minimum requirement
- If interaction is required, ensure you've participated in topics with the user
- Verify you haven't already rated the user
Contributions are welcome! Here's how you can help:
- Search existing issues before creating a new one
- Include Discourse version, plugin version, and steps to reproduce
- Fork the repository
- Create a feature branch (
git checkout -b feature/my-feature) - Follow existing code style and conventions
- Test your changes locally (see Development)
- Submit a pull request with a clear description
- Copy
config/locales/client.en.ymltoclient.{locale}.yml - Copy
config/locales/server.en.ymltoserver.{locale}.yml - Translate all strings
- Submit a pull request
This project is licensed under the MIT License - see the LICENSE file for details.




