FEATURE: Can edit category/host relationships for embedding#1
FEATURE: Can edit category/host relationships for embedding#1akshayutture-augment wants to merge 1 commit into
Conversation
|
@claude review this PR |
1 similar comment
|
@claude review this PR |
|
Claude finished @akshayutture-augment's task —— View job Code Review CompleteI've completed a thorough review of this PR that introduces a new feature for managing embeddable host-to-category relationships. Here's my detailed feedback: Critical Issues 🔴1. Wrong File Content in embeddable_host_fabricator.rbFile: The new file contains Category fabricators instead of EmbeddableHost fabricators. Based on the diff, this appears to be a copy-paste error from Expected content: Fabricator(:embeddable_host) do
host "eviltrout.com"
category
endActual content: Contains Category fabricators ( This will cause test failures as the tests expect an 2. SQL Injection Vulnerability in MigrationFile: execute "INSERT INTO embeddable_hosts (host, category_id, created_at, updated_at) VALUES ('#{h}', #{category_id}, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP)"Direct string interpolation of user data ( Fix: Use parameterized queries or properly escape the values: execute sanitize_sql_array(["INSERT INTO embeddable_hosts (host, category_id, created_at, updated_at) VALUES (?, ?, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP)", h, category_id])Or use ActiveRecord: EmbeddableHost.create!(host: h, category_id: category_id)High Priority Issues 🟡3. Missing Authorization Check in destroyFile: def destroy
host = EmbeddableHost.where(id: params[:id]).first
host.destroy
render json: success_json
endNo check for Fix: def destroy
host = EmbeddableHost.find_by(id: params[:id])
return render_json_error("Host not found", status: 404) unless host
host.destroy
render json: success_json
end4. Redundant Code in SiteSetting ModelFile: The removed method !!embeddable_hosts.split("\n").detect {|h| h.sub(/^https?\:\/\//, '') == host }
hosts = embeddable_hosts.split("\n").map {|h| (URI(h).host rescue nil) || h } # Unreachable!
!!hosts.detect {|h| h == host} # Unreachable!Good that this was removed in favor of the cleaner 5. Regex Vulnerability in Host ValidationFile: validates_format_of :host, :with => /\A[a-z0-9]+([\-\.]{1}[a-z0-9]+)*\.[a-z]{2,5}(:[0-9]{1,5})?(\/.*)?\Z/iIssues:
Suggestion: validates_format_of :host, :with => /\A[a-z0-9]+([\-\.]{1}[a-z0-9]+)*\.[a-z]{2,}(:[0-9]{1,5})?\Z/i6. Missing Error Handling in ModelFile: self.host.sub!(/^https?:\/\//, '')This will raise an error if Fix: self.host = self.host.to_s.sub(/^https?:\/\//, '').sub(/\/.*$/, '')Medium Priority Issues 🟢7. Inconsistent Method NamingFile: def self.host_allowed?(host)
record_for_host(host).present?
endThis mirrors the old
8. Migration Query Could FailFile: category_id = execute("SELECT c.id FROM categories AS c
INNER JOIN site_settings AS s ON s.value = c.name
WHERE s.name = 'embed_category'")[0]['id'].to_iIf the join returns no results, Fix: result = execute("SELECT c.id FROM categories AS c
INNER JOIN site_settings AS s ON s.value = c.name
WHERE s.name = 'embed_category'").to_a
category_id = result.first&.fetch('id', 0).to_i9. Overly Verbose SerializerFile: All methods just return the object attribute directly, which is the default behavior. Can be simplified to: class EmbeddableHostSerializer < ApplicationSerializer
attributes :id, :host, :category_id
end10. Missing ValidationFile: Missing validation for validates :category_id, presence: true
validates :category, presence: true11. Test Coverage GapsFile: Only tests inheritance, not the actual CRUD operations. Should add tests for:
File: Same issue - only tests inheritance. 12. Frontend: Potential Race ConditionFile: host.save(props).then(() => {
host.set('category', Discourse.Category.findById(this.get('categoryId')));
this.set('editToggled', false);
}).catch(popupAjaxError);After saving, it manually sets the category by looking it up. The server should return the full object with the relationship already loaded. This could cause issues if Minor Issues / Suggestions 💡13. Magic NumberFile: host.category_id = SiteSetting.uncategorized_category_id if host.category_id.blank?Consider if this default should be explicit in the model or documented why uncategorized is chosen as the default. 14. Unused Route ParameterFile: put "customize/embedding" => "embedding#update", constraints: AdminConstraint.newThe 15. JavaScript Store EnhancementFile: The regex change Positive Aspects ✅
SummaryThis is a solid refactoring that moves embeddable host management from site settings to a proper database model with admin UI. The main concerns are:
Recommendation: Fix the critical issues before merging, particularly the fabricator file and SQL injection vulnerability. |
Test 10
Replicated from ai-code-review-evaluation/discourse-greptile#10