diff --git a/app/controllers/api/v1/project_topics_controller.rb b/app/controllers/api/v1/project_topics_controller.rb new file mode 100644 index 000000000..3a23fde4a --- /dev/null +++ b/app/controllers/api/v1/project_topics_controller.rb @@ -0,0 +1,31 @@ +class Api::V1::ProjectTopicsController < Api::V1::BaseController + + def index + @project_topics = ProjectTopic + @project_topics = @project_topics.ransack(name_cont: params[:keyword]) if params[:keyword].present? + @project_topics = @project_topics.includes(:projects) + @project_topics = kaminary_select_paginate(@project_topics) + end + + def create + ActiveRecord::Base.transaction do + @project = Project.find_by_id(create_params[:project_id]) + return render_not_found unless @project.present? + return render_error("请输入项目搜索标签名称.") unless create_params[:name].present? + + @project_topic = ProjectTopic.find_or_create_by!(name: create_params[:name].downcase) + @project_topic_ralate = @project_topic.project_topic_ralates.find_or_create_by!(project_id: create_params[:project_id]) + + if @project_topic.present? && @project_topic_ralate.present? + render_ok + else + render_error("项目关联搜索标签失败.") + end + end + end + + private + def create_params + params.permit(:project_id, :name) + end +end \ No newline at end of file diff --git a/app/controllers/projects_controller.rb b/app/controllers/projects_controller.rb index 2d9ddc014..7639f2677 100644 --- a/app/controllers/projects_controller.rb +++ b/app/controllers/projects_controller.rb @@ -34,7 +34,7 @@ class ProjectsController < ApplicationController def index scope = current_user.logged? ? Projects::ListQuery.call(params, current_user.id) : Projects::ListQuery.call(params) - @projects = kaminari_paginate(scope.includes(:project_category, :project_language, :repository, :project_educoder, :owner, :project_units)) + @projects = kaminari_paginate(scope.includes(:project_category, :project_language, :repository, :project_educoder, :owner, :project_units, :project_topics)) # @projects = paginate scope.includes(:project_category, :project_language, :repository, :project_educoder, :owner, :project_units) category_id = params[:category_id] diff --git a/app/models/concerns/matchable.rb b/app/models/concerns/matchable.rb index 5c013f951..0640e7c74 100644 --- a/app/models/concerns/matchable.rb +++ b/app/models/concerns/matchable.rb @@ -6,6 +6,7 @@ module Matchable scope :with_project_language, ->(language_id) { where(project_language_id: language_id) unless language_id.blank? } scope :with_project_type, ->(project_type) { where(project_type: project_type) if Project.project_types.include?(project_type) } scope :by_name_or_identifier, ->(search) { where("name like :search or identifier LIKE :search", :search => "%#{search.split(" ").join('|')}%") unless search.blank? } + scope :with_project_topic, ->(topic_id) {joins(:project_topics).where(project_topics: {id: topic_id}) unless topic_id.blank?} end end diff --git a/app/models/project.rb b/app/models/project.rb index 54d6ac520..555269e5e 100644 --- a/app/models/project.rb +++ b/app/models/project.rb @@ -126,6 +126,8 @@ class Project < ApplicationRecord has_many :webhooks, class_name: "Gitea::Webhook", primary_key: :gpid, foreign_key: :repo_id has_many :user_trace_tasks, dependent: :destroy has_many :project_invite_links, dependent: :destroy + has_many :project_topic_ralates, dependent: :destroy + has_many :project_topics, through: :project_topic_ralates after_create :incre_user_statistic, :incre_platform_statistic after_save :check_project_members before_save :set_invite_code, :reset_unmember_followed, :set_recommend_and_is_pinned, :reset_cache_data diff --git a/app/models/project_topic.rb b/app/models/project_topic.rb new file mode 100644 index 000000000..94c9df9c7 --- /dev/null +++ b/app/models/project_topic.rb @@ -0,0 +1,25 @@ +# == Schema Information +# +# Table name: project_topics +# +# id :integer not null, primary key +# user_id :integer +# name :string(255) +# position :integer default("0") +# projects_count :integer default("0") +# created_at :datetime not null +# updated_at :datetime not null +# +# Indexes +# +# index_project_topics_on_user_id (user_id) +# + +class ProjectTopic < ApplicationRecord + + belongs_to :user, optional: true + has_many :project_topic_ralates, dependent: :destroy + has_many :projects, through: :project_topic_ralates + + validates :name, uniqueness: { case_sensitive: false } +end diff --git a/app/models/project_topic_ralate.rb b/app/models/project_topic_ralate.rb new file mode 100644 index 000000000..d8638699f --- /dev/null +++ b/app/models/project_topic_ralate.rb @@ -0,0 +1,22 @@ +# == Schema Information +# +# Table name: project_topic_ralates +# +# id :integer not null, primary key +# project_topic_id :integer +# project_id :integer +# created_at :datetime not null +# updated_at :datetime not null +# +# Indexes +# +# index_project_topic_ralates_on_project_id (project_id) +# index_project_topic_ralates_on_project_topic_id (project_topic_id) +# + +class ProjectTopicRalate < ApplicationRecord + + belongs_to :project_topic, counter_cache: :projects_count + belongs_to :project + +end diff --git a/app/models/user.rb b/app/models/user.rb index 1818bccb1..c3c62f9eb 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -182,6 +182,7 @@ class User < Owner has_many :assigned_issues, through: :issue_assigners, source: :issue has_many :issue_participants, foreign_key: :participant_id has_many :participant_issues, through: :issue_participants, source: :issue + has_many :project_topics # Groups and active users scope :active, lambda { where(status: [STATUS_ACTIVE, STATUS_EDIT_INFO]) } scope :like, lambda { |keywords| diff --git a/app/queries/projects/list_query.rb b/app/queries/projects/list_query.rb index 2b048bd87..72776f7a2 100644 --- a/app/queries/projects/list_query.rb +++ b/app/queries/projects/list_query.rb @@ -3,7 +3,7 @@ class Projects::ListQuery < ApplicationQuery attr_reader :params, :current_user_id - sort_columns :updated_on, :created_on, :forked_count, :praises_count, default_by: :updated_on, default_direction: :desc + sort_columns :updated_on, :created_on, :forked_count, :praises_count, default_by: :updated_on, default_direction: :desc, default_table: 'projects' def initialize(params, current_user_id=nil) @params = params @@ -32,6 +32,7 @@ class Projects::ListQuery < ApplicationQuery collection = by_project_type(collection) collection = by_project_category(collection) collection = by_project_language(collection) + collection = by_project_topic(collection) collection end @@ -74,6 +75,10 @@ class Projects::ListQuery < ApplicationQuery (params[:pinned].present? && params[:category_id].present?) ? items.pinned : items end + def by_project_topic(items) + items.with_project_topic(params[:topic_id]) + end + # 优化排序 def optimize_sorting(relations, sort_by) if sort_by == "updated_on" diff --git a/app/views/api/v1/project_topics/index.json.jbuilder b/app/views/api/v1/project_topics/index.json.jbuilder new file mode 100644 index 000000000..5a39aaa56 --- /dev/null +++ b/app/views/api/v1/project_topics/index.json.jbuilder @@ -0,0 +1,4 @@ +json.total_count @project_topics.total_count +json.project_topics @project_topics.each do |topic| + json.(topic, :id, :name, :projects_count) +end \ No newline at end of file diff --git a/app/views/projects/index.json.jbuilder b/app/views/projects/index.json.jbuilder index 31d0db9c5..d3b96ab18 100644 --- a/app/views/projects/index.json.jbuilder +++ b/app/views/projects/index.json.jbuilder @@ -48,4 +48,7 @@ json.projects @projects do |project| json.name project.project_language.name end end + json.topics project.project_topics.each do |topic| + json.(topic, :id, :name) + end end diff --git a/config/routes/api.rb b/config/routes/api.rb index 6e688a632..799783f0d 100644 --- a/config/routes/api.rb +++ b/config/routes/api.rb @@ -2,7 +2,7 @@ defaults format: :json do namespace :api do namespace :v1 do scope ':owner' do - resource :users, path: '/', only: [:show, :update, :edit, :destroy] do + resource :users, path: '/', only: [:update, :edit, :destroy] do collection do get :send_email_vefify_code post :check_password @@ -97,6 +97,7 @@ defaults format: :json do end resources :projects, only: [:index] + resources :project_topics, only: [:index, :create] end diff --git a/db/migrate/20230321022108_create_project_topics.rb b/db/migrate/20230321022108_create_project_topics.rb new file mode 100644 index 000000000..07a03e20d --- /dev/null +++ b/db/migrate/20230321022108_create_project_topics.rb @@ -0,0 +1,19 @@ +class CreateProjectTopics < ActiveRecord::Migration[5.2] + def change + create_table :project_topics do |t| + t.references :user + t.string :name + t.integer :position, default: 0 + t.integer :projects_count, default: 0 + + t.timestamps + end + + create_table :project_topic_ralates do |t| + t.belongs_to :project_topic, index: true + t.belongs_to :project, index: true + + t.timestamps + end + end +end