mirror of
https://github.com/discourse/discourse.git
synced 2024-11-23 02:19:27 +08:00
FEATURE: manage Permalinks
This commit is contained in:
parent
7f43653cad
commit
dc90c396f2
|
@ -0,0 +1,56 @@
|
|||
export default Ember.Component.extend({
|
||||
classNames: ['permalink-form'],
|
||||
formSubmitted: false,
|
||||
permalinkType: 'topic_id',
|
||||
|
||||
permalinkTypes: function() {
|
||||
return [
|
||||
{id: 'topic_id', name: I18n.t('admin.permalink.topic_id')},
|
||||
{id: 'post_id', name: I18n.t('admin.permalink.post_id')},
|
||||
{id: 'category_id', name: I18n.t('admin.permalink.category_id')},
|
||||
{id: 'external_url', name: I18n.t('admin.permalink.external_url')}
|
||||
];
|
||||
}.property(),
|
||||
|
||||
permalinkTypePlaceholder: function() {
|
||||
return 'admin.permalink.' + this.get('permalinkType');
|
||||
}.property('permalinkType'),
|
||||
|
||||
actions: {
|
||||
submit: function() {
|
||||
if (!this.get('formSubmitted')) {
|
||||
const self = this;
|
||||
self.set('formSubmitted', true);
|
||||
const permalink = Discourse.Permalink.create({url: self.get('url'), permalink_type: self.get('permalinkType'), permalink_type_value: self.get('permalink_type_value')});
|
||||
permalink.save().then(function(result) {
|
||||
self.set('url', '');
|
||||
self.set('permalink_type_value', '');
|
||||
self.set('formSubmitted', false);
|
||||
self.sendAction('action', Discourse.Permalink.create(result.permalink));
|
||||
Em.run.schedule('afterRender', function() { self.$('.permalink-url').focus(); });
|
||||
}, function(e) {
|
||||
self.set('formSubmitted', false);
|
||||
let error;
|
||||
if (e.responseJSON && e.responseJSON.errors) {
|
||||
error = I18n.t("generic_error_with_reason", {error: e.responseJSON.errors.join('. ')});
|
||||
} else {
|
||||
error = I18n.t("generic_error");
|
||||
}
|
||||
bootbox.alert(error, function() { self.$('.permalink-url').focus(); });
|
||||
});
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
didInsertElement: function() {
|
||||
var self = this;
|
||||
self._super();
|
||||
Em.run.schedule('afterRender', function() {
|
||||
self.$('.external-url').keydown(function(e) {
|
||||
if (e.keyCode === 13) { // enter key
|
||||
self.send('submit');
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
|
@ -0,0 +1,36 @@
|
|||
export default Ember.ArrayController.extend({
|
||||
loading: false,
|
||||
filter: null,
|
||||
|
||||
show: Discourse.debounce(function() {
|
||||
var self = this;
|
||||
self.set('loading', true);
|
||||
Discourse.Permalink.findAll(self.get("filter")).then(function(result) {
|
||||
self.set('model', result);
|
||||
self.set('loading', false);
|
||||
});
|
||||
}, 250).observes("filter"),
|
||||
|
||||
actions: {
|
||||
recordAdded(arg) {
|
||||
this.get("model").unshiftObject(arg);
|
||||
},
|
||||
|
||||
destroy: function(record) {
|
||||
const self = this;
|
||||
return bootbox.confirm(I18n.t("admin.permalink.delete_confirm"), I18n.t("no_value"), I18n.t("yes_value"), function(result) {
|
||||
if (result) {
|
||||
record.destroy().then(function(deleted) {
|
||||
if (deleted) {
|
||||
self.removeObject(record);
|
||||
} else {
|
||||
bootbox.alert(I18n.t("generic_error"));
|
||||
}
|
||||
}, function(){
|
||||
bootbox.alert(I18n.t("generic_error"));
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
22
app/assets/javascripts/admin/models/permalink.js.es6
Normal file
22
app/assets/javascripts/admin/models/permalink.js.es6
Normal file
|
@ -0,0 +1,22 @@
|
|||
const Permalink = Discourse.Model.extend({
|
||||
save: function() {
|
||||
return Discourse.ajax("/admin/permalinks.json", {
|
||||
type: 'POST',
|
||||
data: {url: this.get('url'), permalink_type: this.get('permalink_type'), permalink_type_value: this.get('permalink_type_value')}
|
||||
});
|
||||
},
|
||||
|
||||
destroy: function() {
|
||||
return Discourse.ajax("/admin/permalinks/" + this.get('id') + ".json", {type: 'DELETE'});
|
||||
}
|
||||
});
|
||||
|
||||
Permalink.reopenClass({
|
||||
findAll: function(filter) {
|
||||
return Discourse.ajax("/admin/permalinks.json", { data: { filter: filter } }).then(function(permalinks) {
|
||||
return permalinks.map(p => Discourse.Permalink.create(p));
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
export default Permalink;
|
|
@ -0,0 +1,9 @@
|
|||
export default Discourse.Route.extend({
|
||||
model() {
|
||||
return Discourse.Permalink.findAll();
|
||||
},
|
||||
|
||||
setupController(controller, model) {
|
||||
controller.set('model', model);
|
||||
}
|
||||
});
|
|
@ -22,6 +22,7 @@ export default {
|
|||
});
|
||||
this.resource('adminUserFields', { path: '/user_fields' });
|
||||
this.resource('adminEmojis', { path: '/emojis' });
|
||||
this.resource('adminPermalinks', { path: '/permalinks' });
|
||||
});
|
||||
this.route('api');
|
||||
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
<b>{{i18n 'admin.permalink.form.label'}}</b>
|
||||
{{text-field value=url disabled=formSubmitted class="permalink-url" placeholderKey="admin.permalink.url" autocorrect="off" autocapitalize="off"}}
|
||||
{{combo-box content=permalinkTypes value=permalinkType}}
|
||||
{{text-field value=permalink_type_value disabled=formSubmitted class="external-url" placeholderKey=permalinkTypePlaceholder autocorrect="off" autocapitalize="off"}}
|
||||
<button class="btn" {{action "submit" target="view"}} {{bind-attr disabled="formSubmitted"}}>{{i18n 'admin.permalink.form.add'}}</button>
|
|
@ -4,6 +4,7 @@
|
|||
{{nav-item route='adminSiteText' label='admin.site_text.title'}}
|
||||
{{nav-item route='adminUserFields' label='admin.user_fields.title'}}
|
||||
{{nav-item route='adminEmojis' label='admin.emoji.title'}}
|
||||
{{nav-item route='adminPermalinks' label='admin.permalink.title'}}
|
||||
{{/admin-nav}}
|
||||
|
||||
<div class="admin-container">
|
||||
|
|
25
app/assets/javascripts/admin/templates/permalinks.hbs
Normal file
25
app/assets/javascripts/admin/templates/permalinks.hbs
Normal file
|
@ -0,0 +1,25 @@
|
|||
<div class="permalink-title"><h2>{{i18n 'admin.permalink.title'}}</h2></div>
|
||||
<div class="pull-right">
|
||||
{{text-field value=filter class="url-input" placeholderKey="admin.permalink.form.filter" autocorrect="off" autocapitalize="off"}}
|
||||
</div>
|
||||
{{permalink-form action="recordAdded"}}
|
||||
<br/>
|
||||
|
||||
{{#conditional-loading-spinner condition=loading}}
|
||||
{{#if model.length}}
|
||||
<div class='table admin-logs-table permalinks'>
|
||||
<div class="heading-container">
|
||||
<div class="col heading first url">{{i18n 'admin.permalink.url'}}</div>
|
||||
<div class="col heading topic_id">{{i18n 'admin.permalink.topic_id'}}</div>
|
||||
<div class="col heading post_id">{{i18n 'admin.permalink.post_id'}}</div>
|
||||
<div class="col heading category_id">{{i18n 'admin.permalink.category_id'}}</div>
|
||||
<div class="col heading external_url">{{i18n 'admin.permalink.external_url'}}</div>
|
||||
<div class="col heading actions"></div>
|
||||
<div class="clearfix"></div>
|
||||
</div>
|
||||
{{view 'permalinks-list' content=controller}}
|
||||
</div>
|
||||
{{else}}
|
||||
{{i18n 'search.no_results'}}
|
||||
{{/if}}
|
||||
{{/conditional-loading-spinner}}
|
|
@ -0,0 +1,7 @@
|
|||
<div class="col first url">{{url}}</div>
|
||||
<div class="col topic_id">{{topic_id}}</div>
|
||||
<div class="col post_id">{{post_id}}</div>
|
||||
<div class="col category_id">{{category_id}}</div>
|
||||
<div class="col external_url">{{external_url}}</div>
|
||||
<div class="col action"><button class="btn btn-danger" {{action "destroy" this}}><i class="fa fa-trash-o"></i></button></div>
|
||||
<div class="clearfix"></div>
|
|
@ -0,0 +1,8 @@
|
|||
import ListView from 'ember-addons/list-view';
|
||||
import ListItemView from 'ember-addons/list-item-view';
|
||||
|
||||
export default ListView.extend({
|
||||
height: 700,
|
||||
rowHeight: 32,
|
||||
itemViewClass: ListItemView.extend({templateName: "admin/templates/permalinks_list_item"})
|
||||
});
|
|
@ -1199,7 +1199,7 @@ table.api-keys {
|
|||
position: absolute;
|
||||
}
|
||||
|
||||
.staff-actions, .screened-emails, .screened-urls, .screened-ip-addresses {
|
||||
.staff-actions, .screened-emails, .screened-urls, .screened-ip-addresses, .permalinks {
|
||||
|
||||
border-bottom: dotted 1px scale-color($primary, $lightness: 75%);
|
||||
|
||||
|
@ -1469,3 +1469,19 @@ table#user-badges {
|
|||
width: 90%;
|
||||
}
|
||||
}
|
||||
|
||||
// Permalinks
|
||||
|
||||
.permalinks {
|
||||
.url, .external_url {
|
||||
width: 300px;
|
||||
}
|
||||
.action, .topic_id, .post_id, .category_id {
|
||||
text-align: center;
|
||||
width: 9.9099%;
|
||||
}
|
||||
}
|
||||
|
||||
.permalink-title {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
|
39
app/controllers/admin/permalinks_controller.rb
Normal file
39
app/controllers/admin/permalinks_controller.rb
Normal file
|
@ -0,0 +1,39 @@
|
|||
class Admin::PermalinksController < Admin::AdminController
|
||||
|
||||
before_filter :fetch_permalink, only: [:destroy]
|
||||
|
||||
def index
|
||||
filter = params[:filter]
|
||||
|
||||
permalinks = Permalink
|
||||
permalinks = permalinks.where('url ILIKE :filter OR external_url ILIKE :filter', filter: "%#{params[:filter]}%") if filter.present?
|
||||
permalinks = permalinks.limit(100).order('created_at desc').to_a
|
||||
|
||||
render_serialized(permalinks, PermalinkSerializer)
|
||||
end
|
||||
|
||||
def create
|
||||
params.require(:url)
|
||||
params.require(:permalink_type)
|
||||
params.require(:permalink_type_value)
|
||||
|
||||
permalink = Permalink.new(:url => params[:url], params[:permalink_type] => params[:permalink_type_value])
|
||||
if permalink.save
|
||||
render_serialized(permalink, PermalinkSerializer)
|
||||
else
|
||||
render_json_error(permalink)
|
||||
end
|
||||
end
|
||||
|
||||
def destroy
|
||||
@permalink.destroy
|
||||
render json: success_json
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def fetch_permalink
|
||||
@permalink = Permalink.find(params[:id])
|
||||
end
|
||||
|
||||
end
|
3
app/serializers/permalink_serializer.rb
Normal file
3
app/serializers/permalink_serializer.rb
Normal file
|
@ -0,0 +1,3 @@
|
|||
class PermalinkSerializer < ApplicationSerializer
|
||||
attributes :id, :url, :topic_id, :post_id, :category_id, :external_url
|
||||
end
|
|
@ -2443,6 +2443,19 @@ en:
|
|||
image: "Image"
|
||||
delete_confirm: "Are you sure you want to delete the :%{name}: emoji?"
|
||||
|
||||
permalink:
|
||||
title: "Permalinks"
|
||||
url: "URL"
|
||||
topic_id: "Topic ID"
|
||||
post_id: "Post ID"
|
||||
category_id: "Category ID"
|
||||
external_url: "External URL"
|
||||
delete_confirm: Are you sure you want to delete this permalink?
|
||||
form:
|
||||
label: "New:"
|
||||
add: "Add"
|
||||
filter: "Search (URL or External URL)"
|
||||
|
||||
lightbox:
|
||||
download: "download"
|
||||
|
||||
|
|
|
@ -133,6 +133,7 @@ Discourse::Application.routes.draw do
|
|||
get "customize" => "color_schemes#index", constraints: AdminConstraint.new
|
||||
get "customize/css_html" => "site_customizations#index", constraints: AdminConstraint.new
|
||||
get "customize/colors" => "color_schemes#index", constraints: AdminConstraint.new
|
||||
get "customize/permalinks" => "permalinks#index", constraints: AdminConstraint.new
|
||||
get "flags" => "flags#index"
|
||||
get "flags/:filter" => "flags#index"
|
||||
post "flags/agree/:id" => "flags#agree"
|
||||
|
@ -148,6 +149,8 @@ Discourse::Application.routes.draw do
|
|||
|
||||
resources :color_schemes, constraints: AdminConstraint.new
|
||||
|
||||
resources :permalinks, constraints: AdminConstraint.new
|
||||
|
||||
get "version_check" => "versions#show"
|
||||
|
||||
resources :dashboard, only: [:index] do
|
||||
|
|
51
spec/controllers/admin/permalinks_controller_spec.rb
Normal file
51
spec/controllers/admin/permalinks_controller_spec.rb
Normal file
|
@ -0,0 +1,51 @@
|
|||
require 'spec_helper'
|
||||
|
||||
describe Admin::PermalinksController do
|
||||
|
||||
it "is a subclass of AdminController" do
|
||||
expect(Admin::PermalinksController < Admin::AdminController).to eq(true)
|
||||
end
|
||||
|
||||
let!(:user) { log_in(:admin) }
|
||||
|
||||
describe 'index' do
|
||||
it 'filters url' do
|
||||
Fabricate(:permalink, url: "/forum/23")
|
||||
Fabricate(:permalink, url: "/forum/98")
|
||||
Fabricate(:permalink, url: "/discuss/topic/45")
|
||||
Fabricate(:permalink, url: "/discuss/topic/76")
|
||||
|
||||
xhr :get, :index, filter: "topic"
|
||||
|
||||
expect(response).to be_success
|
||||
result = JSON.parse(response.body)
|
||||
expect(result.length).to eq(2)
|
||||
end
|
||||
|
||||
it 'filters external url' do
|
||||
Fabricate(:permalink, external_url: "http://google.com")
|
||||
Fabricate(:permalink, external_url: "http://wikipedia.org")
|
||||
Fabricate(:permalink, external_url: "http://www.discourse.org")
|
||||
Fabricate(:permalink, external_url: "http://try.discourse.org")
|
||||
|
||||
xhr :get, :index, filter: "discourse"
|
||||
|
||||
expect(response).to be_success
|
||||
result = JSON.parse(response.body)
|
||||
expect(result.length).to eq(2)
|
||||
end
|
||||
|
||||
it 'filters url and external url both' do
|
||||
Fabricate(:permalink, url: "/forum/23", external_url: "http://google.com")
|
||||
Fabricate(:permalink, url: "/discourse/98", external_url: "http://wikipedia.org")
|
||||
Fabricate(:permalink, url: "/discuss/topic/45", external_url: "http://discourse.org")
|
||||
Fabricate(:permalink, url: "/discuss/topic/76", external_url: "http://try.discourse.org")
|
||||
|
||||
xhr :get, :index, filter: "discourse"
|
||||
|
||||
expect(response).to be_success
|
||||
result = JSON.parse(response.body)
|
||||
expect(result.length).to eq(3)
|
||||
end
|
||||
end
|
||||
end
|
Loading…
Reference in New Issue
Block a user