| @@ -0,0 +1,46 @@ | |||||
| 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 | |||||
| def destroy | |||||
| ActiveRecord::Base.transaction do | |||||
| @project = Project.find_by_id(create_params[:project_id]) | |||||
| return render_not_found unless @project.present? | |||||
| @project_topic = ProjectTopic.find_by_id(params[:id]) | |||||
| @project_topic_ralate = @project_topic.project_topic_ralates.find_by(project_id: @project.id) | |||||
| if @project_topic_ralate.destroy! | |||||
| render_ok | |||||
| else | |||||
| render_error("项目取消关联搜索标签失败.") | |||||
| end | |||||
| end | |||||
| end | |||||
| private | |||||
| def create_params | |||||
| params.permit(:project_id, :name) | |||||
| end | |||||
| end | |||||
| @@ -34,7 +34,7 @@ class ProjectsController < ApplicationController | |||||
| def index | def index | ||||
| scope = current_user.logged? ? Projects::ListQuery.call(params, current_user.id) : Projects::ListQuery.call(params) | 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) | # @projects = paginate scope.includes(:project_category, :project_language, :repository, :project_educoder, :owner, :project_units) | ||||
| category_id = params[:category_id] | category_id = params[:category_id] | ||||
| @@ -130,6 +130,13 @@ class ProjectsController < ApplicationController | |||||
| # TODO: | # TODO: | ||||
| # 临时特殊处理修改website、lesson_url操作方法 | # 临时特殊处理修改website、lesson_url操作方法 | ||||
| if project_params.has_key?("website") | if project_params.has_key?("website") | ||||
| if params[:project_topic_names].present? && params[:project_topic_names].is_a?(Array) | |||||
| ProjectTopicRalate.where(project: @project).destroy_all | |||||
| params[:project_topic_names].each do |name| | |||||
| project_topic = ProjectTopic.find_or_create_by!(name: name.downcase) | |||||
| project_topic.project_topic_ralates.find_or_create_by!(project: @project) | |||||
| end | |||||
| end | |||||
| @project.update(project_params) | @project.update(project_params) | ||||
| elsif project_params.has_key?("default_branch") | elsif project_params.has_key?("default_branch") | ||||
| @project.update(project_params) | @project.update(project_params) | ||||
| @@ -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_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 :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 :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 | ||||
| end | end | ||||
| @@ -126,6 +126,8 @@ class Project < ApplicationRecord | |||||
| has_many :webhooks, class_name: "Gitea::Webhook", primary_key: :gpid, foreign_key: :repo_id | has_many :webhooks, class_name: "Gitea::Webhook", primary_key: :gpid, foreign_key: :repo_id | ||||
| has_many :user_trace_tasks, dependent: :destroy | has_many :user_trace_tasks, dependent: :destroy | ||||
| has_many :project_invite_links, 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_create :incre_user_statistic, :incre_platform_statistic | ||||
| after_save :check_project_members | after_save :check_project_members | ||||
| before_save :set_invite_code, :reset_unmember_followed, :set_recommend_and_is_pinned, :reset_cache_data | before_save :set_invite_code, :reset_unmember_followed, :set_recommend_and_is_pinned, :reset_cache_data | ||||
| @@ -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 | |||||
| @@ -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 | |||||
| @@ -182,6 +182,7 @@ class User < Owner | |||||
| has_many :assigned_issues, through: :issue_assigners, source: :issue | has_many :assigned_issues, through: :issue_assigners, source: :issue | ||||
| has_many :issue_participants, foreign_key: :participant_id | has_many :issue_participants, foreign_key: :participant_id | ||||
| has_many :participant_issues, through: :issue_participants, source: :issue | has_many :participant_issues, through: :issue_participants, source: :issue | ||||
| has_many :project_topics | |||||
| # Groups and active users | # Groups and active users | ||||
| scope :active, lambda { where(status: [STATUS_ACTIVE, STATUS_EDIT_INFO]) } | scope :active, lambda { where(status: [STATUS_ACTIVE, STATUS_EDIT_INFO]) } | ||||
| scope :like, lambda { |keywords| | scope :like, lambda { |keywords| | ||||
| @@ -67,7 +67,7 @@ class Projects::ListMyQuery < ApplicationQuery | |||||
| keywords = params[:search].to_s.each_char.select { |c| c.bytes.first < 240 }.join('') | keywords = params[:search].to_s.each_char.select { |c| c.bytes.first < 240 }.join('') | ||||
| q = projects.ransack(name_or_identifier_cont: keywords) | q = projects.ransack(name_or_identifier_cont: keywords) | ||||
| scope = q.result.includes(:project_category, :project_language,:owner, :repository, :has_pinned_users) | |||||
| scope = q.result.includes(:project_category, :project_language,:owner, :repository, :has_pinned_users, :project_topics) | |||||
| sort = Project.column_names.include?(params[:sort_by]) ? params[:sort_by] : "updated_on" | sort = Project.column_names.include?(params[:sort_by]) ? params[:sort_by] : "updated_on" | ||||
| sort_direction = %w(desc asc).include?(params[:sort_direction]) ? params[:sort_direction] : "desc" | sort_direction = %w(desc asc).include?(params[:sort_direction]) ? params[:sort_direction] : "desc" | ||||
| @@ -3,7 +3,7 @@ class Projects::ListQuery < ApplicationQuery | |||||
| attr_reader :params, :current_user_id | 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) | def initialize(params, current_user_id=nil) | ||||
| @params = params | @params = params | ||||
| @@ -32,6 +32,7 @@ class Projects::ListQuery < ApplicationQuery | |||||
| collection = by_project_type(collection) | collection = by_project_type(collection) | ||||
| collection = by_project_category(collection) | collection = by_project_category(collection) | ||||
| collection = by_project_language(collection) | collection = by_project_language(collection) | ||||
| collection = by_project_topic(collection) | |||||
| collection | collection | ||||
| end | end | ||||
| @@ -74,6 +75,10 @@ class Projects::ListQuery < ApplicationQuery | |||||
| (params[:pinned].present? && params[:category_id].present?) ? items.pinned : items | (params[:pinned].present? && params[:category_id].present?) ? items.pinned : items | ||||
| end | end | ||||
| def by_project_topic(items) | |||||
| items.with_project_topic(params[:topic_id]) | |||||
| end | |||||
| # 优化排序 | # 优化排序 | ||||
| def optimize_sorting(relations, sort_by) | def optimize_sorting(relations, sort_by) | ||||
| if sort_by == "updated_on" | if sort_by == "updated_on" | ||||
| @@ -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 | |||||
| @@ -50,3 +50,6 @@ json.language do | |||||
| json.name project.project_language.name | json.name project.project_language.name | ||||
| end | end | ||||
| end | end | ||||
| json.topics project.project_topics.each do |topic| | |||||
| json.(topic, :id, :name) | |||||
| end | |||||
| @@ -48,4 +48,7 @@ json.projects @projects do |project| | |||||
| json.name project.project_language.name | json.name project.project_language.name | ||||
| end | end | ||||
| end | end | ||||
| json.topics project.project_topics.each do |topic| | |||||
| json.(topic, :id, :name) | |||||
| end | |||||
| end | end | ||||
| @@ -6,4 +6,7 @@ json.project_category_id @project.project_category_id | |||||
| json.project_language_id @project.project_language_id | json.project_language_id @project.project_language_id | ||||
| json.is_public @project.is_public | json.is_public @project.is_public | ||||
| json.website @project.website | json.website @project.website | ||||
| json.lesson_url @project.lesson_url | |||||
| json.lesson_url @project.lesson_url | |||||
| json.topics @project.project_topics.each do |topic| | |||||
| json.(topic, :id, :name) | |||||
| end | |||||
| @@ -21,6 +21,9 @@ json.mirror_url @project&.repository.remote_mirror_url | |||||
| json.mirror @project&.repository.mirror_url.present? | json.mirror @project&.repository.mirror_url.present? | ||||
| json.type @project.numerical_for_project_type | json.type @project.numerical_for_project_type | ||||
| json.open_devops @project.open_devops? | json.open_devops @project.open_devops? | ||||
| json.topics @project.project_topics.each do |topic| | |||||
| json.(topic, :id, :name) | |||||
| end | |||||
| unless @project.common? | unless @project.common? | ||||
| json.mirror_status @repository.mirror_status | json.mirror_status @repository.mirror_status | ||||
| @@ -2,7 +2,7 @@ defaults format: :json do | |||||
| namespace :api do | namespace :api do | ||||
| namespace :v1 do | namespace :v1 do | ||||
| scope ':owner' do | scope ':owner' do | ||||
| resource :users, path: '/', only: [:show, :update, :edit, :destroy] do | |||||
| resource :users, path: '/', only: [:update, :edit, :destroy] do | |||||
| collection do | collection do | ||||
| get :send_email_vefify_code | get :send_email_vefify_code | ||||
| post :check_password | post :check_password | ||||
| @@ -20,7 +20,7 @@ defaults format: :json do | |||||
| scope ':repo', constraints: { repo: /[^\/]+/ } do | scope ':repo', constraints: { repo: /[^\/]+/ } do | ||||
| # projects | # projects | ||||
| resource :projects, path: '/', only: [:show, :update, :edit, :destroy] do | |||||
| resource :projects, path: '/', only: [:show, :update, :edit] do | |||||
| collection do | collection do | ||||
| get :compare | get :compare | ||||
| get :blame | get :blame | ||||
| @@ -97,6 +97,7 @@ defaults format: :json do | |||||
| end | end | ||||
| resources :projects, only: [:index] | resources :projects, only: [:index] | ||||
| resources :project_topics, only: [:index, :create, :destroy] | |||||
| end | end | ||||
| @@ -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 | |||||