Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 0 additions & 45 deletions .github/workflows/ci.yml

This file was deleted.

22 changes: 22 additions & 0 deletions .github/workflows/lint.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
name: CI

on:
push:
workflow_dispatch:

jobs:
lint:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
with:
ref: ${{ github.head_ref || github.ref_name }}

- name: Set up Ruby
uses: ruby/setup-ruby@v1
with:
bundler-cache: true

- name: Run linter
run: bin/lint
23 changes: 11 additions & 12 deletions .rubocop.yml
Original file line number Diff line number Diff line change
@@ -1,17 +1,19 @@
AllCops:
NewCops: enable
TargetRubyVersion: 3.2
Include:
- "app/**/*.rb"
- "Gemfile"
NewCops: enable
Exclude:
- "db/**/*"
- "bin/**/*"
- "config/**/*"
- "script/**/*"
- "test/**/*"
- "vendor/**/*"
- "lib/**/*"

Metrics:
Enabled: false

Naming/VariableNumber:
CheckMethodNames: false
CheckSymbols: false

Style/Documentation:
Enabled: false
Expand All @@ -22,12 +24,6 @@ Style/FrozenStringLiteralComment:
Style/StringLiterals:
EnforcedStyle: double_quotes

Metrics/MethodLength:
Max: 20

Metrics/AbcSize:
Max: 25

Style/SymbolArray:
EnforcedStyle: brackets

Expand All @@ -37,5 +33,8 @@ Style/GuardClause:
Style/IfUnlessModifier:
Enabled: false

Style/TrailingCommaInHashLiteral:
Enabled: false

Style/Proc:
Enabled: false
5 changes: 4 additions & 1 deletion bin/lint
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,11 @@

set -e

echo "Installing Rubocop..."
gem install 'rubocop:~> 1.76.0' 'rubocop-rails:~> 2.32.0' 'rubocop-performance:~> 1.25.0'

echo "Running Rubocop linter..."
rubocop --ignore-parent-exclusion --force-exclusion app/ Gemfile $@
rubocop --ignore-parent-exclusion --force-exclusion $@

exit_code=$?

Expand Down
5 changes: 3 additions & 2 deletions init.rb
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@
Redmine::Plugin.register :redmine_semantic_search do
name "Semantic Search"
author "Sami Hindi @ Renuo"
description "This redmine plugin allows you to search issues using natural language, by storing the issue content in a vector database."
description "This redmine plugin allows you to search issues using natural language, " \
"by storing the issue content in a vector database."
version "0.0.1"
url "https://github.com/renuo/redmine_semantic_search"
author_url "https://github.com/renuo"
Expand All @@ -31,7 +32,7 @@
caption: :label_redmine_semantic_search,
if: Proc.new {
user = User.current
Setting.plugin_redmine_semantic_search['enabled'] == '1' &&
Setting.plugin_redmine_semantic_search["enabled"] == "1" &&
user.logged? &&
user.allowed_to?(:use_semantic_search, nil, global: true)
}
Expand Down
4 changes: 2 additions & 2 deletions lib/redmine_semantic_search/hooks/view_hooks.rb
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
module RedmineSemanticSearch
module Hooks
class ViewHooks < Redmine::Hook::ViewListener
render_on :view_issues_index_top, partial: 'redmine_semantic_search/issues_sync_button'
render_on :view_issues_index_top, partial: "redmine_semantic_search/issues_sync_button"

render_on :view_issues_list_header, partial: 'redmine_semantic_search/issues_sync_button_toolbar'
render_on :view_issues_list_header, partial: "redmine_semantic_search/issues_sync_button_toolbar"
end
end
end
4 changes: 2 additions & 2 deletions lib/redmine_semantic_search/issue_hooks.rb
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,14 @@ def controller_issues_edit_after_save(context = {})

def controller_journals_edit_post(context = {})
journal = context[:journal]
if journal.present? && journal.journalized_type == 'Issue' && plugin_enabled?
if journal.present? && journal.journalized_type == "Issue" && plugin_enabled?
schedule_embedding_job(journal.journalized_id)
end
end

def controller_journals_new_after_save(context = {})
journal = context[:journal]
if journal.present? && journal.journalized_type == 'Issue' && plugin_enabled?
if journal.present? && journal.journalized_type == "Issue" && plugin_enabled?
schedule_embedding_job(journal.journalized_id)
end
end
Expand Down
125 changes: 87 additions & 38 deletions lib/tasks/redmine_semantic_search_setup.rake
Original file line number Diff line number Diff line change
Expand Up @@ -13,19 +13,23 @@ namespace :redmine_semantic_search do

puts "#{colors[:cyan]}Starting Redmine development data setup for Semantic Search plugin...#{colors[:reset]}"

admin_user = User.find_by(admin: true) || User.find_by(login: 'admin') || User.first
admin_user = User.find_by(admin: true) || User.find_by(login: "admin") || User.first
unless admin_user
puts "#{colors[:red]}Error: Could not find an admin user to assign as author. Please ensure at least one user exists.#{colors[:reset]}"
puts "#{colors[:red]}Error: Could not find an admin user to assign as author. " \
"Please ensure at least one user exists.#{colors[:reset]}"
exit 1
end
puts "Using user '#{colors[:yellow]}#{admin_user.login}#{colors[:reset]}' (ID: #{admin_user.id}) as author for issues."
puts "Using user '#{colors[:yellow]}#{admin_user.login}#{colors[:reset]}' " \
"(ID: #{admin_user.id}) as author for issues."

initial_issue_status = IssueStatus.order(:position).first
unless initial_issue_status
puts "#{colors[:red]}Error: No issue statuses found in the system. Please ensure Redmine has default statuses configured (e.g., via Administration > Issue Statuses).#{colors[:reset]}"
puts "#{colors[:red]}Error: No issue statuses found in the system. Please ensure Redmine has default statuses " \
"configured (e.g., via Administration > Issue Statuses).#{colors[:reset]}"
exit 1
end
puts "Using initial issue status '#{colors[:yellow]}#{initial_issue_status.name}#{colors[:reset]}' (ID: #{initial_issue_status.id}) as the default for new trackers and new issues."
puts "Using initial issue status '#{colors[:yellow]}#{initial_issue_status.name}#{colors[:reset]}' " \
"(ID: #{initial_issue_status.id}) as the default for new trackers and new issues."

bug_tracker = Tracker.find_or_create_by!(name: "Bug") do |t|
t.default_status_id = initial_issue_status.id
Expand All @@ -41,75 +45,118 @@ namespace :redmine_semantic_search do

default_priority = IssuePriority.find_by(name: "Normal") || IssuePriority.order(:position).first
unless default_priority
puts "#{colors[:red]}Error: No issue priorities found. Please ensure Redmine has default priorities configured.#{colors[:reset]}"
puts "#{colors[:red]}Error: No issue priorities found. " \
"Please ensure Redmine has default priorities configured.#{colors[:reset]}"
exit 1
end
puts "Using default priority '#{colors[:yellow]}#{default_priority.name}#{colors[:reset]}' (ID: #{default_priority.id}) for new issues."
puts "Using default priority '#{colors[:yellow]}#{default_priority.name}#{colors[:reset]}' " \
"(ID: #{default_priority.id}) for new issues."

projects_data = [
{
name: "AI-Powered Content Moderation System",
identifier: "ai-content-mod-#{Time.now.to_i}",
description: "Develop an AI system to automatically moderate user-generated content, flag inappropriate submissions, and reduce manual review workload.",
description: "Develop an AI system to automatically moderate user-generated content, " \
"flag inappropriate submissions, and reduce manual review workload.",
issues: [
{ subject: "Develop hate speech detection model", description: "Research and implement a machine learning model for detecting hate speech in text.", tracker: feature_tracker },
{ subject: "Integrate profanity filter API", description: "Connect with a third-party profanity filter service.", tracker: feature_tracker },
{ subject: "Image recognition for inappropriate content", description: "Build or integrate a module to identify nudity or violence in images.", tracker: feature_tracker },
{ subject: "User reporting and appeal system", description: "Allow users to report content and appeal moderation decisions.", tracker: feature_tracker },
{ subject: "Dashboard for moderators", description: "Create an admin interface for moderators to review flagged content and manage rules.", tracker: feature_tracker },
{ subject: "Performance testing for high volume", description: "Ensure the system can handle a large number of submissions per second.", tracker: bug_tracker },
{ subject: "Multilingual support for text analysis", description: "Extend text analysis capabilities to support Spanish and French.", tracker: feature_tracker },
{ subject: "False positive rate analysis", description: "Monitor and work on reducing the false positive rate of the AI models.", tracker: bug_tracker },
{ subject: "Documentation for API endpoints", description: "Provide clear documentation for the system\'s APIs.", tracker: feature_tracker },
{ subject: "Setup CI/CD pipeline for model deployment", description: "Automate the training and deployment process for new model versions.", tracker: feature_tracker }
{ subject: "Develop hate speech detection model",
description: "Research and implement a machine learning model for detecting hate speech in text.",
tracker: feature_tracker },
{ subject: "Integrate profanity filter API",
description: "Connect with a third-party profanity filter service.", tracker: feature_tracker },
{ subject: "Image recognition for inappropriate content",
description: "Build or integrate a module to identify nudity or violence in images.",
tracker: feature_tracker },
{ subject: "User reporting and appeal system",
description: "Allow users to report content and appeal moderation decisions.", tracker: feature_tracker },
{ subject: "Dashboard for moderators",
description: "Create an admin interface for moderators to review flagged content and manage rules.",
tracker: feature_tracker },
{ subject: "Performance testing for high volume",
description: "Ensure the system can handle a large number of submissions per second.",
tracker: bug_tracker },
{ subject: "Multilingual support for text analysis",
description: "Extend text analysis capabilities to support Spanish and French.",
tracker: feature_tracker },
{ subject: "False positive rate analysis",
description: "Monitor and work on reducing the false positive rate of the AI models.",
tracker: bug_tracker },
{ subject: "Documentation for API endpoints",
description: "Provide clear documentation for the system's APIs.", tracker: feature_tracker },
{ subject: "Setup CI/CD pipeline for model deployment",
description: "Automate the training and deployment process for new model versions.",
tracker: feature_tracker }
]
},
{
name: "Smart City Environmental Monitoring",
identifier: "smartcity-envmon-#{Time.now.to_i}",
description: "A project to deploy IoT sensors across the city for real-time environmental data collection (air quality, noise pollution, temperature) and analysis.",
description: "A project to deploy IoT sensors across the city for real-time environmental data collection " \
"(air quality, noise pollution, temperature) and analysis.",
issues: [
{ subject: "Select and procure IoT sensor hardware", description: "Evaluate and purchase sensors for air quality, noise, and temperature.", tracker: feature_tracker },
{ subject: "Develop sensor data ingestion platform", description: "Build a scalable platform to receive and store data from thousands of sensors.", tracker: feature_tracker },
{ subject: "Create real-time data visualization dashboard", description: "Display sensor data on a map and through charts for public and city official access.", tracker: feature_tracker },
{ subject: "Implement alert system for pollution thresholds", description: "Notify authorities when pollution levels exceed predefined safety limits.", tracker: feature_tracker },
{ subject: "Data analytics for trend identification", description: "Develop algorithms to identify pollution trends and sources.", tracker: feature_tracker },
{ subject: "Mobile app for citizen reporting", description: "Allow citizens to report environmental issues via a mobile application.", tracker: bug_tracker },
{ subject: "Ensure data security and privacy", description: "Implement robust security measures for the collected data.", tracker: feature_tracker },
{ subject: "Integrate with existing city GIS systems", description: "Overlay environmental data on current city geographical information systems.", tracker: feature_tracker },
{ subject: "Power management for remote sensors", description: "Optimize power consumption for sensors in locations without direct power access.", tracker: bug_tracker },
{ subject: "Long-term data archiving strategy", description: "Plan for the storage and accessibility of historical environmental data.", tracker: feature_tracker }
{ subject: "Select and procure IoT sensor hardware",
description: "Evaluate and purchase sensors for air quality, noise, and temperature.",
tracker: feature_tracker },
{ subject: "Develop sensor data ingestion platform",
description: "Build a scalable platform to receive and store data from thousands of sensors.",
tracker: feature_tracker },
{ subject: "Create real-time data visualization dashboard",
description: "Display sensor data on a map and through charts for public and city official access.",
tracker: feature_tracker },
{ subject: "Implement alert system for pollution thresholds",
description: "Notify authorities when pollution levels exceed predefined safety limits.",
tracker: feature_tracker },
{ subject: "Data analytics for trend identification",
description: "Develop algorithms to identify pollution trends and sources.", tracker: feature_tracker },
{ subject: "Mobile app for citizen reporting",
description: "Allow citizens to report environmental issues via a mobile application.",
tracker: bug_tracker },
{ subject: "Ensure data security and privacy",
description: "Implement robust security measures for the collected data.", tracker: feature_tracker },
{ subject: "Integrate with existing city GIS systems",
description: "Overlay environmental data on current city geographical information systems.",
tracker: feature_tracker },
{ subject: "Power management for remote sensors",
description: "Optimize power consumption for sensors in locations without direct power access.",
tracker: bug_tracker },
{ subject: "Long-term data archiving strategy",
description: "Plan for the storage and accessibility of historical environmental data.",
tracker: feature_tracker }
]
}
]

projects_data.each_with_index do |p_data, index|
puts "\n#{colors[:blue]}--- Creating Project #{index + 1}: #{p_data[:name]} ---#{colors[:reset]}"
project = Project.find_by(identifier: p_data[:identifier])
unless project
if project
puts "#{colors[:yellow]}Project '#{p_data[:name]}' (identifier: #{p_data[:identifier]}) already exists. " \
"ID: #{project.id}.#{colors[:reset]}"
else
project = Project.new(
name: p_data[:name],
identifier: p_data[:identifier],
description: p_data[:description],
is_public: true,
enabled_module_names: ['issue_tracking']
enabled_module_names: ["issue_tracking"]
)
project.trackers = default_trackers
if project.save
puts "#{colors[:green]}Project '#{project.name}' created successfully with ID: #{project.id}.#{colors[:reset]}"
puts "#{colors[:green]}Project '#{project.name}' created successfully with ID: " \
"#{project.id}.#{colors[:reset]}"
else
puts "#{colors[:red]}Failed to create project '#{p_data[:name]}': #{project.errors.full_messages.join(', ')}#{colors[:reset]}"
puts "#{colors[:red]}Failed to create project '#{p_data[:name]}': " \
"#{project.errors.full_messages.join(', ')}#{colors[:reset]}"
next
end
else
puts "#{colors[:yellow]}Project '#{p_data[:name]}' (identifier: #{p_data[:identifier]}) already exists. ID: #{project.id}.#{colors[:reset]}"
end

puts "Creating issues for project '#{colors[:magenta]}#{p_data[:name]}#{colors[:reset]}' (ID: #{project.id})..."
p_data[:issues].each do |issue_data|
existing_issue = Issue.find_by(project_id: project.id, subject: issue_data[:subject])
if existing_issue
puts "#{colors[:yellow]}Issue '#{issue_data[:subject]}' already exists in project '#{project.name}'. Skipping.#{colors[:reset]}"
puts "#{colors[:yellow]}Issue '#{issue_data[:subject]}' already exists in project '#{project.name}'. " \
"Skipping.#{colors[:reset]}"
next
end

Expand All @@ -124,9 +171,11 @@ namespace :redmine_semantic_search do
start_date: Date.today
)
if issue.save
puts "#{colors[:green]}Issue '#{issue.subject}' created successfully for project '#{project.name}'.#{colors[:reset]}"
puts "#{colors[:green]}Issue '#{issue.subject}' created successfully for project " \
"'#{project.name}'.#{colors[:reset]}"
else
puts "#{colors[:red]}Failed to create issue '#{issue_data[:subject]}' for project '#{project.name}': #{issue.errors.full_messages.join(', ')}#{colors[:reset]}"
puts "#{colors[:red]}Failed to create issue '#{issue_data[:subject]}' for project " \
"'#{project.name}': #{issue.errors.full_messages.join(', ')}#{colors[:reset]}"
end
end
end
Expand Down
Loading
Loading