diff --git a/Bowerfile b/Bowerfile index 19bf4d4b..24e82d3c 100644 --- a/Bowerfile +++ b/Bowerfile @@ -1,36 +1,36 @@ assets_path 'assets/javascript' -asset 'underscore' -asset 'backbone' -asset 'backbone-notifier', :github => 'ewebdev/backbone.notifier#v0.2.4' +asset 'underscore', '1.9.1' +asset 'backbone', '1.4.0' +asset 'backbone-notifier', 'https://github.com/ewebdev/backbone.notifier.git#v0.2.4' -asset 'wysihtml5', :github => 'xing/wysihtml5' -asset 'leaflet' +asset 'wysihtml5', 'https://github.com/xing/wysihtml5.git' +asset 'leaflet', '1.0.0' # jQuery -asset 'data-tables', :github => 'DataTables/DataTables' -asset 'flot', :github => 'flot/flot' -asset 'knob', :github => 'aterrien/jQuery-Knob' -asset 'uniform', :github => 'AudithSoftworks/Uniform' -asset 'jquery-ui', :github => 'jquery/jquery-ui#1.11.4' -asset 'jquery-filthypillow', :github => 'Rademade/jquery.filthypillow#master' -asset 'magnific-popup', :github => 'dimsemenov/Magnific-Popup' -asset 'touch-punch', :github => 'furf/jquery-ui-touch-punch' +asset 'data-tables', 'https://github.com/DataTables/DataTables.git#1.10.19' +asset 'flot', '0.8.3' +asset 'knob', 'https://github.com/aterrien/jQuery-Knob.git#1.2.13' +asset 'uniform', 'https://github.com/AudithSoftworks/Uniform.git' +asset 'jquery-ui', 'https://github.com/jquery/jquery-ui.git#1.11.4' +asset 'jquery-filthypillow', 'https://github.com/Rademade/jquery.filthypillow.git#master' +asset 'magnific-popup', 'https://github.com/dimsemenov/Magnific-Popup.git' +asset 'touch-punch', 'https://github.com/furf/jquery-ui-touch-punch.git' asset 'jquery-ujs' # Images -asset 'jcrop', :github => 'tapmodo/Jcrop#v0.9.12' -asset 'jquery-fileupload', :github => 'blueimp/jQuery-File-Upload' +asset 'jcrop', 'https://github.com/tapmodo/Jcrop.git#v0.9.12' +asset 'jquery-fileupload', 'https://github.com/blueimp/jQuery-File-Upload.git#v9.12.6' # List -asset 'TableDnD' +asset 'TableDnD', '0.9.2' # Form -asset 'moment' -asset 'jquery-form', :github => 'malsup/form' -asset 'jquery-serialize', :github => 'macek/jquery-serialize-object' -asset 'jquery-formrestrict', :github => 'treyhunner/jquery-formrestrict' -asset 'jquery-validation', :github => 'jzaefferer/jquery-validation#v1.13.1' +asset 'moment', '2.24.0' +asset 'jquery-form', 'https://github.com/malsup/form.git#v4.0.0' +asset 'jquery-serialize', 'https://github.com/macek/jquery-serialize-object.git' +asset 'jquery-formrestrict', 'https://github.com/treyhunner/jquery-formrestrict.git' +asset 'jquery-validation', 'https://github.com/jzaefferer/jquery-validation.git#v1.13.1' #Thead -asset 'floatThead', :github => 'mkoryak/floatThead' +asset 'floatThead', 'https://github.com/mkoryak/floatThead.git' diff --git a/Gemfile b/Gemfile index 06832a3d..5989f42a 100644 --- a/Gemfile +++ b/Gemfile @@ -10,6 +10,7 @@ end group :test do gem 'coveralls', :require => false + gem 'ckeditor', '~> 4.0' # Uploaders gem 'carrierwave' diff --git a/app/assets/javascripts/app/common/helpers.coffee b/app/assets/javascripts/app/common/helpers.coffee new file mode 100644 index 00000000..03e6470d --- /dev/null +++ b/app/assets/javascripts/app/common/helpers.coffee @@ -0,0 +1,12 @@ +window.RademadeAdmin = { + helpers: { + stripScripts: (string) -> + div = document.createElement('div') + div.innerHTML = string + scripts = div.getElementsByTagName('script') + i = scripts.length + while i-- + scripts[i].parentNode.removeChild scripts[i] + div.innerHTML + } +} diff --git a/app/assets/javascripts/app/common/turboform.coffee b/app/assets/javascripts/app/common/turboform.coffee deleted file mode 100644 index 813e61f7..00000000 --- a/app/assets/javascripts/app/common/turboform.coffee +++ /dev/null @@ -1,8 +0,0 @@ -initTurboform = () -> - $('form[data-turboform]').on 'submit', () -> - separator = if @action.indexOf('?') is -1 then '?' else '&' - Turbolinks.visit @action + separator + $(this).serialize() - return false - -$ -> - $(document).on 'ready page:load init-plugins', initTurboform diff --git a/app/assets/javascripts/app/common/uploader.coffee b/app/assets/javascripts/app/common/uploader.coffee index 198cbc85..cc4c5c91 100644 --- a/app/assets/javascripts/app/common/uploader.coffee +++ b/app/assets/javascripts/app/common/uploader.coffee @@ -19,11 +19,15 @@ class @Uploader extends Backbone.View @showLoader() $form.submit().done @updateUploader always : @hideLoader + fail : (event, data) -> + errorMessage = data?._response?.jqXHR?.responseJSON?.error + window.notifier.notify(errorMessage) if errorMessage updateUploader : (result) => @$el.find('[data-preview-item]').replaceWith(result.html) @$el.find('.upload-holder.hide').removeClass('hide') @$hidden.val(result.file.url) + @$hidden.change() ImagePreview.initPlugin() showLoader : () -> @@ -38,6 +42,7 @@ class @Uploader extends Backbone.View @$el.find('.upload-holder:has([data-preview-item])').fadeOut 300, () -> $(this).addClass('hide').show() @$hidden.val('') + @$hidden.change() _getUploaderData : () -> uploaderData = _.pick @$uploader.data(), 'id', 'model', 'column', 'uploader' @@ -63,4 +68,4 @@ class @Uploader extends Backbone.View @initAll() $ -> - $(document).on 'page:load ready init-plugins', Uploader.initPlugin \ No newline at end of file + $(document).on 'page:load ready init-plugins', Uploader.initPlugin diff --git a/app/assets/javascripts/app/common/url-visitor.coffee b/app/assets/javascripts/app/common/url-visitor.coffee index 7c3fab7d..11f3d9da 100644 --- a/app/assets/javascripts/app/common/url-visitor.coffee +++ b/app/assets/javascripts/app/common/url-visitor.coffee @@ -1,6 +1,6 @@ initUrlVisit = () -> $('[data-link-url]').click () -> - Turbolinks.visit $(this).data('linkUrl') + window.location.href = $(this).data('linkUrl') $ -> - $(document).on 'ready page:load init-plugins', initUrlVisit \ No newline at end of file + $(document).on 'ready page:load init-plugins', initUrlVisit diff --git a/app/assets/javascripts/app/compatibility/turbolinks.coffee b/app/assets/javascripts/app/compatibility/turbolinks.coffee deleted file mode 100644 index e26fbbfa..00000000 --- a/app/assets/javascripts/app/compatibility/turbolinks.coffee +++ /dev/null @@ -1,30 +0,0 @@ -{defer, dispatch} = Turbolinks - -handleEvent = (eventName, handler) -> - document.addEventListener(eventName, handler, false) - -translateEvent = ({from, to}) -> - handler = (event) -> - event = dispatch(to, target: event.target, cancelable: event.cancelable, data: event.data) - event.preventDefault() if event.defaultPrevented - handleEvent(from, handler) - -translateEvent from: "turbolinks:click", to: "page:before-change" -translateEvent from: "turbolinks:request-start", to: "page:fetch" -translateEvent from: "turbolinks:request-end", to: "page:receive" -translateEvent from: "turbolinks:before-cache", to: "page:before-unload" -translateEvent from: "turbolinks:render", to: "page:update" -translateEvent from: "turbolinks:load", to: "page:change" -translateEvent from: "turbolinks:load", to: "page:update" - -loaded = false -handleEvent "DOMContentLoaded", -> - defer -> - loaded = true -handleEvent "turbolinks:load", -> - if loaded - dispatch("page:load") - -jQuery?(document).on "ajaxSuccess", (event, xhr, settings) -> - if jQuery.trim(xhr.responseText).length > 0 - dispatch("page:update") diff --git a/app/assets/javascripts/app/content/view.coffee b/app/assets/javascripts/app/content/view.coffee index cf984339..ecbce147 100644 --- a/app/assets/javascripts/app/content/view.coffee +++ b/app/assets/javascripts/app/content/view.coffee @@ -1,31 +1,42 @@ class @Content extends Backbone.View - renderItemFromUrl : (url, cb) -> + isLoadingContentItem = false + + renderItemFromUrl : (url, cb, urlData = {}) -> + return if isLoadingContentItem + return if url == '' $(document).trigger 'before-content-render' @_updateHistory(url) - $.get url, layout : false, (html) => + $('#loader').removeClass('hide') + isLoadingContentItem = true + $.get url, _.extend(urlData, layout : false), (html) => $contentItem = $(html) $('[data-content]').append $contentItem $(window).scrollTop(0) $(document).trigger 'init-plugins' @bindClick $contentItem cb($contentItem) if cb + isLoadingContentItem = false + $('#loader').addClass('hide') - renderModel : (model) -> + renderModel : (model, urlData = {}) -> @renderItemFromUrl model.get('editurl'), ($contentItem) => $contentItem.find('form').on 'ajax-submit-done', (e, response) => model.update response.data $contentItem.remove() + , urlData moveToPreviousContentItem : () -> @moveToContentItem $('[data-content-item]:nth-last-child(2)') moveToContentItem : ($contentItem) -> - return if $contentItem.is(':last-child') - $contentItem.nextAll('[data-content-item]').remove() - if $contentItem.is(':first-child') - @renderItemFromUrl $contentItem.data('contentItem'), () -> - $contentItem.remove() + if $contentItem.length is 0 + window.history.back() if window.history.length > 2 + else + $contentItem.nextAll('[data-content-item]').remove() + if $contentItem.is(':first-child') || !$contentItem.has('.content-data').length + @renderItemFromUrl $contentItem.data('contentItem'), () -> + $contentItem.remove() bindClick : ($el) -> $el.find('[data-content-header]').bind 'click', (e) => @@ -34,27 +45,35 @@ class @Content extends Backbone.View @renderItemFromUrl $(e.currentTarget).data('contentUrl') false $el.find('[data-content-close]').bind 'click', (e) => - @moveToContentItem $(e.currentTarget).closest('[data-content-item]').prev() + $contentItem = $(e.currentTarget).closest('[data-content-item]') + $prevContentItem = $contentItem.prev() + if $prevContentItem.length is 0 + @moveToContentItem $contentItem + else + @moveToContentItem $prevContentItem + + bindDocumentClick : () => + @bindClick($(document)) bindHistoryBack : () -> $(window).bind 'popstate', (e) -> - state = e.originalEvent.state - window.location.href = state.url if state.url + window.location.reload() _updateHistory : (url) -> if history.pushState isnt undefined and $('[data-content-header]').length < 2 history.pushState url : url, document.title, url @init : () -> - content = new Content() + content = new this() content.bindHistoryBack() + content.bindDocumentClick() content + @initInstance : () => + window.ContentInstance = @init() + @getInstance : () -> - instance = null - do () -> - instance ||= Content.init() + window.ContentInstance -$ -> - $(document).on 'page:load ready', () -> - Content.getInstance().bindClick $(document) + $ -> + $(document).on 'page:load ready', Content.initInstance diff --git a/app/assets/javascripts/app/forms/forgot-password-form.coffee b/app/assets/javascripts/app/forms/forgot-password-form.coffee new file mode 100644 index 00000000..f72e48b2 --- /dev/null +++ b/app/assets/javascripts/app/forms/forgot-password-form.coffee @@ -0,0 +1,5 @@ +$(document).on 'ready page:load', -> + + $('#forgot-password-form').on + 'ajax-submit-done': (e, data) -> + $(e.currentTarget).html(data.template) \ No newline at end of file diff --git a/app/assets/javascripts/app/forms/login.coffee b/app/assets/javascripts/app/forms/login.coffee index 53120f3a..91ea9a3b 100644 --- a/app/assets/javascripts/app/forms/login.coffee +++ b/app/assets/javascripts/app/forms/login.coffee @@ -1,4 +1,8 @@ $(document).on 'ready page:load', -> $('#login-form').on - 'ajax-submit-done': -> window.location.reload() \ No newline at end of file + 'ajax-submit-done': (event, data) -> + if data.redirect_url && typeof data.redirect_url is 'string' + window.location.href = data.redirect_url + else + window.location.reload() diff --git a/app/assets/javascripts/app/forms/reset-password-form.coffee b/app/assets/javascripts/app/forms/reset-password-form.coffee new file mode 100644 index 00000000..e1aeb0a3 --- /dev/null +++ b/app/assets/javascripts/app/forms/reset-password-form.coffee @@ -0,0 +1,5 @@ +$(document).on 'ready page:load init-plugins', -> + + $('#reset-password-form').on + 'ajax-submit-done': (e) -> + window.location.reload() diff --git a/app/assets/javascripts/app/gallery/image/collection-view.coffee b/app/assets/javascripts/app/gallery/image/collection-view.coffee index a014a0f7..80016dd2 100644 --- a/app/assets/javascripts/app/gallery/image/collection-view.coffee +++ b/app/assets/javascripts/app/gallery/image/collection-view.coffee @@ -7,12 +7,7 @@ class @GalleryImageCollectionView extends Backbone.View @_initImage $(image) initSort : () -> - sortUrl = @$el.data('sortableUrl') - if sortUrl - @images.setSortUrl sortUrl - @$el.sortable - stop : () => - @images.sort @_getSortedImages() + @$el.sortable() if @$el.data('sortable') && @$el.sortable addImage : ($image) -> @_initImage $image @@ -32,4 +27,4 @@ class @GalleryImageCollectionView extends Backbone.View el : $el collectionView.initImages className collectionView.initSort() - collectionView \ No newline at end of file + collectionView diff --git a/app/assets/javascripts/app/gallery/image/collection.coffee b/app/assets/javascripts/app/gallery/image/collection.coffee index f80f3a55..1c114d4d 100644 --- a/app/assets/javascripts/app/gallery/image/collection.coffee +++ b/app/assets/javascripts/app/gallery/image/collection.coffee @@ -5,15 +5,3 @@ class @GalleryImageCollection extends Backbone.Collection getClassName : () -> @className - - setSortUrl : (sortUrl) -> - @sortUrl = sortUrl - - sort : (images) -> - $.ajax - type : 'patch' - url : @sortUrl - data : - class_name : @className - images : images - dataType : 'json' \ No newline at end of file diff --git a/app/assets/javascripts/app/gallery/image/model.coffee b/app/assets/javascripts/app/gallery/image/model.coffee index fd15abbb..e64378b7 100644 --- a/app/assets/javascripts/app/gallery/image/model.coffee +++ b/app/assets/javascripts/app/gallery/image/model.coffee @@ -1,19 +1,10 @@ class @GalleryImageModel extends ImageModel remove : () -> - $.ajax - type : 'delete' - url : @get 'removeUrl' - data : - class_name : @collection.getClassName() - dataType : 'json' - success : () => - @collection.remove this - @trigger 'image-removed' - error : (data) => - window.notifier.notify data.error + @collection.remove this + @trigger 'image-removed' _getData : () -> data = super data.class_name = @collection.getClassName() - data \ No newline at end of file + data diff --git a/app/assets/javascripts/app/gallery/image/view.coffee b/app/assets/javascripts/app/gallery/image/view.coffee index ae5d5e08..e2386407 100644 --- a/app/assets/javascripts/app/gallery/image/view.coffee +++ b/app/assets/javascripts/app/gallery/image/view.coffee @@ -2,14 +2,14 @@ class @GalleryImageView extends Backbone.View events : 'click' : 'showPopup' - 'click [data-remove-url]' : 'remove' + 'click [data-remove]' : 'remove' initialize : () -> @model.on 'image-removed', @_onImageRemove @model.on 'change:resizedUrl', @_updateImageUrl remove : () -> - @model.remove() if confirm I18n.t('rademade_admin.remove_confirm.image') + @model.remove() false showPopup : () -> @@ -27,8 +27,7 @@ class @GalleryImageView extends Backbone.View @init : ($el) -> model = new GalleryImageModel $el.data() - model.set 'removeUrl', $el.find('[data-remove-url]').data('removeUrl') new GalleryImageView model : model el : $el - model \ No newline at end of file + model diff --git a/app/assets/javascripts/app/gallery/view.coffee b/app/assets/javascripts/app/gallery/view.coffee index ff12eaf9..950cb290 100644 --- a/app/assets/javascripts/app/gallery/view.coffee +++ b/app/assets/javascripts/app/gallery/view.coffee @@ -2,25 +2,39 @@ class @Gallery extends Backbone.View initUploadButton : () -> @$uploadButton = @$el.find('[type="file"]') - @galleryId = @$el.find('[type="hidden"]').val() @galleryClassName = @$uploadButton.data('class-name') @$loaderHolder = @$el.find('.upload-item.add') initCollectionView : () -> - @collectionView = GalleryImageCollectionView.init @$el.find('[data-sortable-url]'), @galleryClassName + @collectionView = GalleryImageCollectionView.init @$el.find('.upload-box'), @galleryClassName + # todo refactor bindUpload : () -> @$uploadButton.fileupload dataType : 'json' dropZone : @$el - url : @$uploadButton.data('url') - formData : - gallery_id : @galleryId - class_name : @galleryClassName - add : (e, $form) => + add : (e, data) => @showLoader() - $form.submit().done @_appendUploadResult + filesLeft = data.files.length + $.each data.files, (index, file) => + reader = new FileReader() + reader.readAsDataURL(file) + reader.onload = () => + # todo move template to view render + image = reader.result + imageHtml = "
+
+ + +
+
" + @collectionView.addImage $(imageHtml) + filesLeft-- + @hideLoader() if filesLeft <= 0 stop : @hideLoader + error : (data) => + if data.responseJSON?.error + window.notifier.notify data.responseJSON.error showLoader : () -> @$loaderHolder.addClass('is-loading') @@ -28,10 +42,6 @@ class @Gallery extends Backbone.View hideLoader : () => @$loaderHolder.removeClass('is-loading') - _appendUploadResult : (result) => - $.each result.gallery_images_html, (index, image_html) => - @collectionView.addImage $(image_html) - @init : ($el) -> gallery = new this el : $el @@ -50,4 +60,4 @@ class @Gallery extends Backbone.View @initAll() $ -> - $(document).on 'page:load ready init-plugins', Gallery.initPlugin \ No newline at end of file + $(document).on 'page:load ready init-plugins', Gallery.initPlugin diff --git a/app/assets/javascripts/app/notifier/initialize.js b/app/assets/javascripts/app/notifier/initialize.js index 6ae092e4..e6f428e0 100644 --- a/app/assets/javascripts/app/notifier/initialize.js +++ b/app/assets/javascripts/app/notifier/initialize.js @@ -1,31 +1,38 @@ -$(document).on('ready page:load', function(){ - window.notifier = new Backbone.Notifier({ // defaults - el: 'body', // container for notification (default: 'body') - baseCls: 'notifier',// css classes prefix, should match css file. Change to solve conflicts. - theme: 'clean',// default theme for notifications (available: 'plastic'/'clean'). - types: ['warning', 'error', 'info', 'success'],// available notification styles - type: null, // default notification type (null/'warning'/'error'/'info'/'success') - dialog: false, // whether display the notification with a title bar and a dialog style. - // - sets 'hideOnClick' to false, unless defined otherwise - // - sets 'position' to 'center', unless defined otherwise - // - sets 'ms' to null, unless defined otherwise - modal: false, // whether to dark and block the UI behind the notification (default: false) - message: '', // default message content - title: undefined,// default notification title, if defined, causes the notification to be - // 'dialog' (unless dialog is 'false') - closeBtn: false, // whether to display an enabled close button on notification - ms: 5000, // milliseconds before hiding (null || false => no timeout) (default: 10000) - 'class': null, // additional css class - hideOnClick: true,// whether to hide the notifications on mouse click (default: true) - loader: false, // whether to display loader animation in notifications (default: false) - destroy: false,// notification or selector of notifications to hide on show (default: false) - opacity: 1, // notification's opacity (default: 1) - offsetY: 0, // distance between the notifications and the top/bottom edge (default: 0) - fadeInMs: 500, // duration (milliseconds) of notification's fade-in effect (default: 500) - fadeOutMs: 500, // duration (milliseconds) of notification's fade-out effect (default: 500) - position: 'top',// default notifications position ('top' / 'center' / 'bottom') - zIndex: 10000, // minimal z-index for notifications - screenOpacity: 0.5,// opacity of dark screen background that goes behind for modals (0 to 1) - width: undefined// notification's width ('auto' if not set) - }); -}); \ No newline at end of file +$(document).on('ready page:load', function () { + window.notifier = new Backbone.Notifier({ // defaults + el: 'body', // container for notification (default: 'body') + baseCls: 'notifier',// css classes prefix, should match css file. Change to solve conflicts. + theme: 'clean',// default theme for notifications (available: 'plastic'/'clean'). + types: ['warning', 'error', 'info', 'success'],// available notification styles + type: null, // default notification type (null/'warning'/'error'/'info'/'success') + dialog: false, // whether display the notification with a title bar and a dialog style. + // - sets 'hideOnClick' to false, unless defined otherwise + // - sets 'position' to 'center', unless defined otherwise + // - sets 'ms' to null, unless defined otherwise + modal: false, // whether to dark and block the UI behind the notification (default: false) + message: '', // default message content + title: undefined,// default notification title, if defined, causes the notification to be + // 'dialog' (unless dialog is 'false') + closeBtn: false, // whether to display an enabled close button on notification + ms: 5000, // milliseconds before hiding (null || false => no timeout) (default: 10000) + 'class': null, // additional css class + hideOnClick: true,// whether to hide the notifications on mouse click (default: true) + loader: false, // whether to display loader animation in notifications (default: false) + destroy: false,// notification or selector of notifications to hide on show (default: false) + opacity: 1, // notification's opacity (default: 1) + offsetY: 0, // distance between the notifications and the top/bottom edge (default: 0) + fadeInMs: 500, // duration (milliseconds) of notification's fade-in effect (default: 500) + fadeOutMs: 500, // duration (milliseconds) of notification's fade-out effect (default: 500) + position: 'top',// default notifications position ('top' / 'center' / 'bottom') + zIndex: 10000, // minimal z-index for notifications + screenOpacity: 0.5,// opacity of dark screen background that goes behind for modals (0 to 1) + width: undefined // notification's width ('auto' if not set) + }); + + const originalGetSettings = window.notifier.getSettings.bind(window.notifier); + window.notifier.getSettings = function (options) { + let settings = originalGetSettings(options); + settings.message = RademadeAdmin.helpers.stripScripts(settings.message); + return settings; + } +}); diff --git a/app/assets/javascripts/app/select2/related/collection-view.coffee b/app/assets/javascripts/app/select2/related/collection-view.coffee index c7181e3e..08a960ed 100644 --- a/app/assets/javascripts/app/select2/related/collection-view.coffee +++ b/app/assets/javascripts/app/select2/related/collection-view.coffee @@ -25,6 +25,7 @@ class @Select2Input.RelatedCollectionView extends Backbone.View collection = new Select2Input.RelatedCollection collection.setSortable $list.data('sortable') collection.setDeletable $list.data('deletable') + collection.setDuplicatable $list.data('duplicatable') $list.find('li').each () -> relatedView = Select2Input.RelatedView.init $(this) @@ -35,4 +36,6 @@ class @Select2Input.RelatedCollectionView extends Backbone.View el : $list views : views collectionView.initSort() + collection.on 'duplicate', (modelId, additionalUrlOptions) -> + collectionView.trigger 'duplicate', modelId, additionalUrlOptions collectionView \ No newline at end of file diff --git a/app/assets/javascripts/app/select2/related/collection.coffee b/app/assets/javascripts/app/select2/related/collection.coffee index b55ab798..c2d10ca5 100644 --- a/app/assets/javascripts/app/select2/related/collection.coffee +++ b/app/assets/javascripts/app/select2/related/collection.coffee @@ -19,12 +19,21 @@ class @Select2Input.RelatedCollection extends Backbone.Collection setDeletable : (deletable) -> @deletable = deletable + setDuplicatable : (duplicatable) -> + @duplicatable = duplicatable + + setNewUrl : (newUrl) -> + @newUrl = newUrl + isSortable : () -> @sortable isDeletable : () -> @deletable + isDuplicatable : () -> + @duplicatable + resort : () -> @sort() @_triggerChange() diff --git a/app/assets/javascripts/app/select2/related/view.coffee b/app/assets/javascripts/app/select2/related/view.coffee index e5bf434f..286c55a3 100644 --- a/app/assets/javascripts/app/select2/related/view.coffee +++ b/app/assets/javascripts/app/select2/related/view.coffee @@ -7,6 +7,7 @@ class @Select2Input.RelatedView extends Backbone.View events : 'click [data-edit]' : 'editRelation' 'click [data-remove]' : 'removeRelation' + 'click [data-duplicate]' : 'duplicateRelation' initialize : () -> @model.on 'relation-remove', @remove, this @@ -14,16 +15,22 @@ class @Select2Input.RelatedView extends Backbone.View editRelation : (e) -> e.preventDefault() - Content.getInstance().renderModel @model + Content.getInstance().renderModel @model, @$el.data('additional-url-options') removeRelation : (e) -> e.preventDefault() @model.relationRemove() if confirm I18n.t('rademade_admin.remove_confirm.model') false + duplicateRelation : (e) -> + e.preventDefault() + @model.trigger 'duplicate', @model.id, @$el.data('additional-url-options') + render : () -> @$el.html @_getHtml(@model.toJSON()) @$el.addClass('is-draggable') if @isSortable() + _.each @model.attributes, (value, name) => + @$el.attr("data-#{name}", value) return this isSortable : () -> @@ -32,16 +39,23 @@ class @Select2Input.RelatedView extends Backbone.View else false - isDeletable: () -> + isDeletable : () -> if @model.collection @model.collection.isDeletable() else false + isDuplicatable : () -> + if @model.collection + @model.collection.isDuplicatable() + else + false + _getHtml : (data) -> JST['app/templates/related-item'] _.extend isSortable : @isSortable() isDeletable : @isDeletable() + isDuplicatable : @isDuplicatable() , data @init : ($el) -> diff --git a/app/assets/javascripts/app/select2/view.coffee b/app/assets/javascripts/app/select2/view.coffee index 10c701fc..afd4981d 100644 --- a/app/assets/javascripts/app/select2/view.coffee +++ b/app/assets/javascripts/app/select2/view.coffee @@ -1,6 +1,6 @@ class @Select2Input.View extends Backbone.View - resultLimit = 10 + resultLimit = 20 initItem : () -> @$item = @$el.find('[data-rel-multiple]') @@ -13,10 +13,16 @@ class @Select2Input.View extends Backbone.View searchUrl : @$item.data('searchUrl') newUrl : @$item.data('newUrl') multiple : @$item.data('relMultiple') + editable : @$item.data('editable') + disabled : @$item.data('disabled') + destroyable : @$item.data('destroyable') initRelated : () -> if @model.isMultiple() collectionView = Select2Input.RelatedCollectionView.init @$el.find('.select2-items-list') + collectionView.on 'duplicate', (modelId, additionalUrlOptions) => + options = _.extend({ duplicate_from: modelId }, additionalUrlOptions || {}) + Content.getInstance().renderModel @_createRelatedModel(@model.get('newUrl')), options @model.set 'related', collectionView.collection else relatedData = @$el.children('input[type="hidden"]').data() @@ -26,12 +32,12 @@ class @Select2Input.View extends Backbone.View @$item.select2( multiple : @model.isMultiple() placeholder : I18n.t('rademade_admin.relation.search') - allowClear : true + allowClear : @model.get('destroyable') formatNoMatches : () -> I18n.t('select2.no_results') formatSelection : (data, $container) => @_appendEditButton($container) - data.text + RademadeAdmin.helpers.stripScripts(data.text) ajax : url : @_getUrl() dataType : 'json' @@ -47,7 +53,7 @@ class @Select2Input.View extends Backbone.View Content.getInstance().renderModel @model.get('related') _appendEditButton : ($container) -> - unless @model.isMultiple() or @initalized + if !(@model.isMultiple() or @initalized) and @model.get('editable') @initalized = yes @$edit = $ @_editButton() @$edit.on 'mousedown', () => @@ -56,10 +62,11 @@ class @Select2Input.View extends Backbone.View $container.after @$edit _appendAddButton : () -> + return unless @model.get('newUrl') $addPlaceholder = $ @_placeholderForAdd() $addPlaceholder.click () => @$item.select2('close') - Content.getInstance().renderModel @_createRelatedModel(@model.get('newUrl')) + Content.getInstance().renderModel @_createRelatedModel(@model.get('newUrl')), $addPlaceholder.data('additionalUrlOptions') @$item.select2('container').find('.select2-drop').append $addPlaceholder _getUrl : () -> @@ -87,15 +94,18 @@ class @Select2Input.View extends Backbone.View @$item.val('') @model.get('related').clear() @$edit.hide() if @$edit + @$item.trigger 'select2:select' _createRelatedModel : (url) -> relatedModel = @_relatedModel url relatedModel.on 'data-change', () => @model.get('related').add(relatedModel) if @model.isMultiple() @_updateData() + @$item.trigger 'select2:select' relatedModel _updateData : () => + $(document).trigger 'view-update' relatedData = @model.getRelatedData() if @model.isMultiple() or relatedData.id @$item.select2('data', relatedData) diff --git a/app/assets/javascripts/app/templates/related-item.jst.ejs b/app/assets/javascripts/app/templates/related-item.jst.ejs index 12226c65..55bd1e76 100644 --- a/app/assets/javascripts/app/templates/related-item.jst.ejs +++ b/app/assets/javascripts/app/templates/related-item.jst.ejs @@ -2,9 +2,13 @@ if (isSortable) { %><% } -%> -<% +%>
<%= text %>
<% if (isDeletable) { - %><% + %>
<%= I18n.t('rademade_admin.relation.destroy') %>
<% +} +if (isDuplicatable) { + %>
+ +
<% } %> \ No newline at end of file diff --git a/app/assets/javascripts/ckeditor/config.js b/app/assets/javascripts/ckeditor/config.js index b1f6a89b..8695b592 100644 --- a/app/assets/javascripts/ckeditor/config.js +++ b/app/assets/javascripts/ckeditor/config.js @@ -94,5 +94,11 @@ if (CKEDITOR && CKEDITOR.config) { { name: 'styles', items: [ 'Styles', 'Format', 'Font', 'FontSize' ] }, { name: 'maximize', items: ['Maximize'] } ]; + + config.toolbar_mini = [ + { name: 'basicstyles', groups: [ 'basicstyles', 'cleanup' ], items: [ 'Bold', 'Italic', 'Underline', 'Strike', 'Subscript', 'Superscript', '-', 'RemoveFormat' ] }, + { name: 'paragraph', groups: [ 'list', 'indent', 'blocks', 'align', 'bidi' ], items: [ 'NumberedList', 'BulletedList', '-', 'Outdent', 'Indent', '-', 'Blockquote', '-', 'JustifyLeft', 'JustifyCenter', 'JustifyRight', 'JustifyBlock' ] }, + { name: 'styles', items: [ 'Font', 'FontSize' ] }, + ]; }; } diff --git a/app/assets/javascripts/form/form-ajax.coffee b/app/assets/javascripts/form/form-ajax.coffee index 98824083..59e6ffa6 100644 --- a/app/assets/javascripts/form/form-ajax.coffee +++ b/app/assets/javascripts/form/form-ajax.coffee @@ -4,7 +4,7 @@ class @FormAjax extends Backbone.View @_prepareForAjax() $.ajax( url : @$el.attr('action') - type : @$el.attr('method') + type : @$el.data('method') || @$el.attr('method') data : @_getData() dataType : 'json' ).done(@_onDone).fail(@_onFail).always(@_onAlways) @@ -16,6 +16,7 @@ class @FormAjax extends Backbone.View _onDone : (data) => @trigger 'ajax-done', data + window.notifier.notify(data.message) if data.message @$el.find('.error-message').remove() _onFail : (response) => @@ -24,7 +25,6 @@ class @FormAjax extends Backbone.View _onAlways : (response) => data = if (response.responseJSON) then response.responseJSON else response - window.notifier.notify(data.message) if data.message @trigger 'ajax-finish', data _getData : () -> @@ -34,6 +34,16 @@ class @FormAjax extends Backbone.View array = items.data[memb] items.data[memb] = @_cleanArray(array) if $.isArray(array) + $('[data-gallery]').each () -> + $gallery = $(this) + galleryImages = [] + $gallery.find('[data-full-url]').each () -> + $galleryImage = $(this) + galleryImages.push + image_id: $galleryImage.data('imageId') + full_url: $galleryImage.data('fullUrl') + items.data["#{$gallery.data('gallery')}_images"] = if _.isEmpty(galleryImages) then [''] else galleryImages + inputMethod = @$el.find('input[name="_method"]') items['_method'] = inputMethod.val() if inputMethod instanceof jQuery @@ -42,7 +52,7 @@ class @FormAjax extends Backbone.View _cleanArray : (array) -> newArray = [] for val in array - cleanVal = val.replace(/\s+/g, '') + cleanVal = val.trim() if cleanVal.length > 0 newArray = $.merge(newArray, cleanVal.split(',')) if newArray.length is 0 then [''] else newArray diff --git a/app/assets/javascripts/form/form-validation.coffee b/app/assets/javascripts/form/form-validation.coffee index c267373c..325ceecf 100644 --- a/app/assets/javascripts/form/form-validation.coffee +++ b/app/assets/javascripts/form/form-validation.coffee @@ -6,9 +6,12 @@ class @FormValidation extends Backbone.View @validationObject = options.validationObject displayFieldErrors : (errors) -> - [messages, globalMessages] = @_collectErrorMessages(errors) - @_showErrorMessages(messages) - @_showGlobalErrorMessages(globalMessages) + if _.isArray(errors) || _.isObject(errors) + [messages, globalMessages] = @_collectErrorMessages(errors) + @_showErrorMessages(messages) + @_showGlobalErrorMessages(globalMessages) + else + window.notifier.notify errors false clearFieldErrors : () -> @@ -30,6 +33,8 @@ class @FormValidation extends Backbone.View name = "data[#{field}]" if $("[name='#{name}']").length > 0 messages[name] = message + else if $("[name='#{name}[]']").length > 0 + messages["#{name}[]"] = message else $("[name*='#{name}']").each (index) -> messages[@name] = '' @@ -51,10 +56,25 @@ class @FormValidation extends Backbone.View @initDefaults : () -> $.validator.setDefaults showErrors : (errorMap, errorList) => + wasScrolledToError = false _.each errorList, (error) => - $error = $(error.element) - $error.parent().addClass 'in-error' - $error.after @_getErrorNotifier(error) + $element = $(error.element) + $holder = $element.closest('.input-holder') + $holder.find('.error-message').remove() + $holder.addClass 'in-error' + $holder.append @_getErrorNotifier(error) + $element.on 'input change select2:select', () -> + $holder.removeClass('in-error') + $holder.find('.error-message').remove() + if error.element.type == 'hidden' + $holder.on 'click', () -> + $holder.removeClass('in-error') + $holder.find('.error-message').remove() + unless wasScrolledToError + wasScrolledToError = true + $('html, body').animate({ + scrollTop : $holder.offset().top - 50 + }, 500) @_getErrorNotifier : (message) -> $([ @@ -68,4 +88,4 @@ class @FormValidation extends Backbone.View if $.isArray(error.message) error.message.join('
') else - error.message \ No newline at end of file + error.message diff --git a/app/assets/javascripts/form/form.coffee b/app/assets/javascripts/form/form.coffee index de91e662..7c216793 100644 --- a/app/assets/javascripts/form/form.coffee +++ b/app/assets/javascripts/form/form.coffee @@ -34,6 +34,7 @@ class @Form extends Backbone.View @$el.triggerHandler.apply(@$el, arguments) _onAjaxStart : () => + $('#loader').removeClass('hide') @formValidation.clearFieldErrors() @sending = true @@ -48,6 +49,7 @@ class @Form extends Backbone.View @formValidation.displayFieldErrors(data.errors) _onAjaxFinish : (data) => + $('#loader').addClass('hide') @trigger 'ajax-submit-always', [data] @sending = false @@ -57,4 +59,4 @@ Form.init = ($el) -> el : $el form.initValidationObject() form.initFormAjax() - form \ No newline at end of file + form diff --git a/app/assets/javascripts/rademade_admin.coffee b/app/assets/javascripts/rademade_admin.coffee index 8042da40..4afd72b8 100644 --- a/app/assets/javascripts/rademade_admin.coffee +++ b/app/assets/javascripts/rademade_admin.coffee @@ -18,7 +18,6 @@ #= require TableDnD/js/jquery.tablednd #= require leaflet/dist/leaflet-src #= require moment/moment -#= require turbolinks #= require select2 #= require ckeditor/init #= require flot/jquery.flot diff --git a/app/assets/stylesheets/blocks/content/_import.sass b/app/assets/stylesheets/blocks/content/_import.sass index 0b04e348..d37f6ae7 100644 --- a/app/assets/stylesheets/blocks/content/_import.sass +++ b/app/assets/stylesheets/blocks/content/_import.sass @@ -6,4 +6,5 @@ @import "actions" @import "tooltip" @import "draggable" -@import "status" \ No newline at end of file +@import "status" +@import "loader" \ No newline at end of file diff --git a/app/assets/stylesheets/blocks/content/_loader.sass b/app/assets/stylesheets/blocks/content/_loader.sass new file mode 100644 index 00000000..431975e4 --- /dev/null +++ b/app/assets/stylesheets/blocks/content/_loader.sass @@ -0,0 +1,41 @@ +.loader-wrapper + position: fixed + z-index: 999 + top: 0 + left: 0 + right: 0 + bottom: 0 + background-color: rgba(0,0,0,.5) + +.lds-hourglass + position: absolute + top: 50% + left: 50% + display: inline-block + width: 64px + height: 64px + transform: translate(-50%, -50%) + +.lds-hourglass:after + content: " " + display: block + border-radius: 50% + width: 0 + height: 0 + margin: 6px + box-sizing: border-box + border: 26px solid #fff + border-color: #fff transparent #fff transparent + animation: lds-hourglass 1.2s infinite + +@keyframes lds-hourglass + 0% + transform: rotate(0) + animation-timing-function: cubic-bezier(0.55, 0.055, 0.675, 0.19) + + 50% + transform: rotate(900deg) + animation-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1) + + 100% + transform: rotate(1800deg) diff --git a/app/assets/stylesheets/blocks/content/_table.sass b/app/assets/stylesheets/blocks/content/_table.sass index fe211ec3..8a3604c7 100644 --- a/app/assets/stylesheets/blocks/content/_table.sass +++ b/app/assets/stylesheets/blocks/content/_table.sass @@ -113,6 +113,14 @@ opacity: .7 transform: translateY(-50%) +sprite(discard_red) + + & ~ .text + display: block + overflow: hidden + width: calc(100% - 25px) + white-space: nowrap + text-overflow: ellipsis + &:hover opacity: 1 .tooltip-holder diff --git a/app/assets/stylesheets/blocks/form/file/_main.sass b/app/assets/stylesheets/blocks/form/file/_main.sass index f577ba88..ce92dae7 100644 --- a/app/assets/stylesheets/blocks/form/file/_main.sass +++ b/app/assets/stylesheets/blocks/form/file/_main.sass @@ -4,4 +4,18 @@ +clear .upload-box - display: inline \ No newline at end of file + display: flex + + .upload-item.upload-item--file + height: 100% + padding: 5px + display: flex + justify-content: center + align-items: center + background-color: #F9FBFE + + a + color: rgb(102, 102, 102) + font-weight: bold + word-break: break-all + font-size: 14px diff --git a/app/controllers/rademade_admin/abstract_controller.rb b/app/controllers/rademade_admin/abstract_controller.rb index 6e5939ed..dd0f7665 100644 --- a/app/controllers/rademade_admin/abstract_controller.rb +++ b/app/controllers/rademade_admin/abstract_controller.rb @@ -1,13 +1,15 @@ # -*- encoding : utf-8 -*- module RademadeAdmin - class AbstractController < ApplicationController + class AbstractController < ActionController::Base include ::RademadeAdmin::UriHelper layout 'rademade_admin' - before_action :init_user, :init_template_service, :require_login - + protect_from_forgery prepend: true + + before_action :init_data, :require_login + attr_reader :current_user rescue_from ::CanCan::AccessDenied do |exception| @@ -17,11 +19,27 @@ class AbstractController < ApplicationController protected def require_login - redirect_to login_url unless admin_logged_in? + unless admin_logged_in? + session[:redirect_after] = request.url + redirect_to rademade_admin_route(:login_url) + end + end + + def init_data + init_model_graph + init_user + init_template_service + end + + def init_model_graph + RademadeAdmin::Model::Graph.instance.init_pairs end def init_user - @current_user = RademadeAdmin.configuration.admin_class.find(session[:user_id]) if session[:user_id].present? + if session[:user_id].present? + related_info = RademadeAdmin::Model::Graph.instance.model_info(RademadeAdmin.configuration.admin_class) + @current_user = related_info.query_adapter.find(session[:user_id]) + end end def init_template_service @@ -36,12 +54,16 @@ def render_errors(errors) end def admin_logged_in? - @current_user.is_a? RademadeAdmin.configuration.admin_class and @current_user.admin? + @current_user && @current_user.admin? end def current_ability @current_ability ||= RademadeAdmin.configuration.ability_class.new(@current_user) end + def default_url_options + RademadeAdmin::Engine.routes.default_url_options + end + end -end \ No newline at end of file +end diff --git a/app/controllers/rademade_admin/application_controller.rb b/app/controllers/rademade_admin/application_controller.rb index 32236354..194ee7ee 100644 --- a/app/controllers/rademade_admin/application_controller.rb +++ b/app/controllers/rademade_admin/application_controller.rb @@ -1,6 +1,7 @@ # -*- encoding : utf-8 -*- +# intermediate class for logic rewrite module RademadeAdmin - class ApplicationController < ActionController::Base + class ApplicationController < ::RademadeAdmin::AbstractController end end diff --git a/app/controllers/rademade_admin/dashboard_controller.rb b/app/controllers/rademade_admin/dashboard_controller.rb index 0743b001..233561c5 100644 --- a/app/controllers/rademade_admin/dashboard_controller.rb +++ b/app/controllers/rademade_admin/dashboard_controller.rb @@ -1,6 +1,6 @@ # -*- encoding : utf-8 -*- module RademadeAdmin - class DashboardController < RademadeAdmin::AbstractController + class DashboardController < ::RademadeAdmin::ApplicationController helper RademadeAdmin::FormHelper helper RademadeAdmin::MenuHelper diff --git a/app/controllers/rademade_admin/file_controller.rb b/app/controllers/rademade_admin/file_controller.rb index 08f5339a..82b34f68 100644 --- a/app/controllers/rademade_admin/file_controller.rb +++ b/app/controllers/rademade_admin/file_controller.rb @@ -1,12 +1,15 @@ # -*- encoding : utf-8 -*- -class RademadeAdmin::FileController < RademadeAdmin::AbstractController +class RademadeAdmin::FileController < RademadeAdmin::ApplicationController def upload param_key = params[:column].to_sym uploader.store!(params[param_key]) - render :json => { - :html => RademadeAdmin::Upload::Preview::File.new(uploader).preview_html, - :file => JSON.parse(uploader.to_json).merge(url: uploader.url) + render json: { + html: RademadeAdmin::Upload::Preview::FilePreview.new(uploader).preview_html( + editable: can?(:update, uploader.model), + destroyable: can?(:destroy, uploader.model) + ), + file: JSON.parse(uploader.to_json).merge(url: uploader.url) } rescue CarrierWave::UploadError => e show_error(e) @@ -20,10 +23,10 @@ def download def crop image = uploader.crop_image(params[:crop], params[:path]) uploader.store!(image) - preview_service = RademadeAdmin::Upload::Preview::File.new(uploader) - render :json => { - :image_data => preview_service.image_data(uploader), - :resized_url => preview_service.image_preview + preview_service = RademadeAdmin::Upload::Preview::FilePreview.new(uploader) + render json: { + image_data: preview_service.image_data(uploader), + resized_url: preview_service.image_preview } rescue CarrierWave::UploadError => e show_error(e) @@ -32,7 +35,7 @@ def crop private def show_error(error) - render :json => { :error => error.to_s }, :status => :unprocessable_entity + render json: { error: error.to_s }, status: :unprocessable_entity end def uploader @@ -48,4 +51,4 @@ def model model_object || model_info.persistence_adapter.new_record end -end \ No newline at end of file +end diff --git a/app/controllers/rademade_admin/forgot_passwords_controller.rb b/app/controllers/rademade_admin/forgot_passwords_controller.rb new file mode 100644 index 00000000..df05634f --- /dev/null +++ b/app/controllers/rademade_admin/forgot_passwords_controller.rb @@ -0,0 +1,31 @@ +# -*- encoding : utf-8 -*- +module RademadeAdmin + class ForgotPasswordsController < RademadeAdmin::ApplicationController + + layout 'login' + + skip_before_action :require_login + + def show + if admin_logged_in? + redirect_to root_path + end + end + + def create + @user = RademadeAdmin.configuration.admin_class.get_by_email(params[:data][:email]) + + if @user.nil? + render json: { errors: { email: I18n.t('rademade_admin.forgot_password.validation.email') } }, status: :precondition_failed + else + token = UserPasswordToken.encode(@user, { exp: 30.minutes.from_now.to_i }) + UserMailer.reset_password(@user, token).deliver_now + + html_template = render_to_string('rademade_admin/forgot_passwords/success', layout: false) + render json: { template: html_template } + end + + end + + end +end diff --git a/app/controllers/rademade_admin/gallery_controller.rb b/app/controllers/rademade_admin/gallery_controller.rb deleted file mode 100644 index 07786fac..00000000 --- a/app/controllers/rademade_admin/gallery_controller.rb +++ /dev/null @@ -1,47 +0,0 @@ -# -*- encoding : utf-8 -*- -class RademadeAdmin::GalleryController < RademadeAdmin::AbstractController - - def upload - render :json => { - :gallery_images_html => gallery_service.upload_images(params[:gallery_id], params[:files]) - } - rescue Exception => e - show_error(e) - end - - def crop - uploader = gallery_service.crop_image(params[:id], params[:crop]) - preview_service = RademadeAdmin::Upload::Preview::Gallery.new - render :json => { - :image_data => preview_service.image_data(uploader), - :resized_url => preview_service.gallery_image_preview(uploader) - } - rescue Exception => e - show_error(e) - end - - def remove - gallery_service.remove_image(params[:id]) - render :json => { } - rescue Exception => e - show_error(e) - end - - def sort - gallery_service.sort_images(params[:images]) - render :json => { } - rescue Exception => e - show_error(e) - end - - private - - def show_error(error) - render :json => { :error => error.to_s }, :status => :unprocessable_entity - end - - def gallery_service - @gallery_service ||= RademadeAdmin::Gallery::Manager.new(params[:class_name]) - end - -end \ No newline at end of file diff --git a/app/controllers/rademade_admin/model_controller.rb b/app/controllers/rademade_admin/model_controller.rb index 0596a86b..b4c02e20 100644 --- a/app/controllers/rademade_admin/model_controller.rb +++ b/app/controllers/rademade_admin/model_controller.rb @@ -1,14 +1,14 @@ # -*- encoding : utf-8 -*- # todo extract more modules module RademadeAdmin - class ModelController < RademadeAdmin::AbstractController + class ModelController < RademadeAdmin::ApplicationController - extend RademadeAdmin::ModelOptions + extend RademadeAdmin::ModelControllerModules::ModelOptions + + include RademadeAdmin::ModelControllerModules::InstanceOptions + include RademadeAdmin::ModelControllerModules::Templates + include RademadeAdmin::ModelControllerModules::Notifier - include RademadeAdmin::InstanceOptions - include RademadeAdmin::Templates - include RademadeAdmin::Notifier - helper RademadeAdmin::FieldHelper helper RademadeAdmin::FieldTypeHelper helper RademadeAdmin::FormHelper @@ -58,14 +58,8 @@ def autocomplete def index authorize! :read, model_class - respond_to do |format| - format.html { - @items = index_items - render_template - } - format.json { render :json => index_items(false) } - format.csv { render_csv(index_items(false)) } - end + @is_sortable_list = true + render_index end def new @@ -105,8 +99,19 @@ def sort protected # TODO move to search module + def render_index + respond_to do |format| + format.html { + @items = index_items + render_template + } + format.json { render :json => index_items(false) } + format.csv { render_csv(index_items(false)) } + end + end + def index_items(with_pagination = true) - conditions = Search::Conditions::List.new(params, model_info.data_items) + conditions = Search::Conditions::ListConditions.new(params, model_info.data_items) conditions.paginate = nil unless with_pagination if params[:rel_class] && params[:rel_id] && params[:rel_getter] related_info = RademadeAdmin::Model::Graph.instance.model_info(params[:rel_class]) @@ -117,7 +122,7 @@ def index_items(with_pagination = true) end def autocomplete_items - conditions = Search::Conditions::Autocomplete.new(params, model_info.data_items) + conditions = Search::Conditions::AutocompleteConditions.new(params, model_info.data_items) Search::Searcher.new(model_info).search(conditions) end @@ -172,4 +177,4 @@ def autocomplete_serializer end end -end \ No newline at end of file +end diff --git a/app/controllers/rademade_admin/reset_passwords_controller.rb b/app/controllers/rademade_admin/reset_passwords_controller.rb new file mode 100644 index 00000000..bc2c95a0 --- /dev/null +++ b/app/controllers/rademade_admin/reset_passwords_controller.rb @@ -0,0 +1,29 @@ +# -*- encoding : utf-8 -*- +module RademadeAdmin + class ResetPasswordsController < RademadeAdmin::ApplicationController + + layout 'login' + + skip_before_action :require_login + + def show + # params[:id] is JWT token + @user = UserPasswordToken.decode(params[:id]) + rescue + redirect_to root_path + end + + def update + user = UserPasswordToken.decode(params[:id]) + data = params.require(:data).permit(:password, :password_repeat).merge(user: user).to_hash.symbolize_keys + + RademadeAdmin::ResetPassword.call(data) + + render json: { redirect_to: login_url } + rescue RademadeAdmin::FieldError => e + render json: { errors: e.error_hash }, status: :precondition_failed + rescue JWT::DecodeError + render json: { message: 'Error', with_return: true }, status: 404 + end + end +end diff --git a/app/controllers/rademade_admin/sessions_controller.rb b/app/controllers/rademade_admin/sessions_controller.rb index d3ab0cbf..a43c32d9 100644 --- a/app/controllers/rademade_admin/sessions_controller.rb +++ b/app/controllers/rademade_admin/sessions_controller.rb @@ -1,15 +1,21 @@ # -*- encoding : utf-8 -*- module RademadeAdmin - class SessionsController < RademadeAdmin::AbstractController + class SessionsController < RademadeAdmin::ApplicationController skip_before_action :require_login def login user = RademadeAdmin::Login.admin(params) session[:user_id] = user.id.to_s + if session[:redirect_after].present? + redirect_url = session[:redirect_after] + session[:redirect_after] = nil + else + redirect_url = { :controller => 'dashboard', :action => 'index' } + end respond_to do |format| - format.html { redirect_to :controller => 'dashboard', :action => 'index' } - format.json { render :json => user } + format.html { redirect_to redirect_url } + format.json { render :json => { redirect_url: redirect_url } } end rescue RademadeAdmin::Login::Error => e render :json => { :errors => e.field_messages }, :status => :precondition_failed diff --git a/app/controllers/rademade_admin/status_controller.rb b/app/controllers/rademade_admin/status_controller.rb index 972dec26..e969ff0b 100644 --- a/app/controllers/rademade_admin/status_controller.rb +++ b/app/controllers/rademade_admin/status_controller.rb @@ -1,8 +1,8 @@ # -*- encoding : utf-8 -*- module RademadeAdmin - class StatusController < RademadeAdmin::AbstractController + class StatusController < RademadeAdmin::ApplicationController - include RademadeAdmin::Notifier + include RademadeAdmin::ModelControllerModules::Notifier def toggle authorize! :update, params[:model] @@ -13,4 +13,4 @@ def toggle end end -end \ No newline at end of file +end diff --git a/app/helpers/rademade_admin/field_helper.rb b/app/helpers/rademade_admin/field_helper.rb index 0e979edd..c3477f8f 100644 --- a/app/helpers/rademade_admin/field_helper.rb +++ b/app/helpers/rademade_admin/field_helper.rb @@ -19,7 +19,7 @@ def display_item_value(item, data_item) value = data_item.list_preview_handler.call(item) end return display_boolean_item(value) if !!value == value - value.to_s.html_safe + sanitize value.to_s end def display_boolean_item(value) @@ -39,7 +39,7 @@ def display_related_item(data_item, item, value) end def display_upload_item(value) - RademadeAdmin::Upload::Preview::File.new(value).uploaded_file_html + RademadeAdmin::Upload::Preview::FilePreview.new(value).uploaded_file_html end def input_attr(attrs = {}) @@ -49,4 +49,4 @@ def input_attr(attrs = {}) ) end -end \ No newline at end of file +end diff --git a/app/helpers/rademade_admin/form_helper.rb b/app/helpers/rademade_admin/form_helper.rb index 18408abb..6c1f6632 100644 --- a/app/helpers/rademade_admin/form_helper.rb +++ b/app/helpers/rademade_admin/form_helper.rb @@ -11,12 +11,17 @@ def login_form(&block) end def admin_field(form, data_item, model_info) - if can_read_relation data_item + if can_read? data_item name = data_item.name attrs = admin_default_params(name, model_info) .merge(field_params(data_item)) - .merge(input_params(name)) - concat form.input(name, input_attr(attrs)) + .deep_merge(input_params(name)) + concat form.input(name, { + addable: can?(:create, @item) && (!data_item.has_relation? || can?(:create, data_item.relation.to)), + editable: can?(:update, @item) && (!data_item.has_relation? || can?(:update, data_item.relation.to)), + destroyable: can?(:destroy, @item) || (data_item.has_relation? && can?(:destroy, data_item.relation.to)), + disabled: !can?(:update, @item) + }.merge(input_attr(attrs))) end end @@ -35,17 +40,27 @@ def admin_form_options(record, model_info) url = admin_create_uri(model_info) form_class = 'insert-item-form' method = :post + save_type = :create + id = nil else url = admin_update_uri(record) form_class = 'update-item-form' method = :patch + save_type = :update + id = record.id end { :wrapper => :rademade, :url => url, :method => method, :as => :data, - :html => admin_form_html_attributes(form_class) + :html => admin_form_html_attributes(form_class), + :data => { + :method => method, + :model => record.model.to_s, + :save_type => save_type, + :id => id + } } end @@ -83,7 +98,7 @@ def field_params(data_item) def input_params(name) { :input_html => { - :id => "#{name}_#{@item.id}" + :id => "#{name}_#{@item.id || unique_pseudo_id}" } } end @@ -91,7 +106,7 @@ def input_params(name) def localized_field_params(data_item, locale) { :input_html => { - :id => "#{data_item.getter}_#{locale}_#{@item.id}", + :id => "#{data_item.getter}_#{locale}_#{@item.id || unique_pseudo_id}", :value => localized_value(data_item.getter, locale) } } @@ -99,6 +114,11 @@ def localized_field_params(data_item, locale) private + # generate pseudo id for records without id (not created yet) + def unique_pseudo_id + DateTime.now.strftime('%Q') + rand.to_s + end + def localized_value(getter, locale) current_locale = I18n.locale I18n.locale = locale @@ -107,8 +127,8 @@ def localized_value(getter, locale) item_value end - def can_read_relation(data_item) - !data_item.has_relation? || can?(:read, data_item.relation.to) + def can_read?(data_item) + can?(:access_field, @item, data_item.name) && (!data_item.has_relation? || can?(:read, data_item.relation.to)) end -end \ No newline at end of file +end diff --git a/app/helpers/rademade_admin/menu_helper.rb b/app/helpers/rademade_admin/menu_helper.rb index d7002f17..1e80db5f 100644 --- a/app/helpers/rademade_admin/menu_helper.rb +++ b/app/helpers/rademade_admin/menu_helper.rb @@ -48,7 +48,11 @@ def collect_children(menu_key) menu_key = menu_key.to_s unless @menu_data[menu_key].nil? @menu_data[menu_key].each do |model_info| - uri = current_ability.can?(:read, model_info.model) ? admin_list_uri(model_info) : nil + if current_ability.can?(:read, model_info.model) && current_ability.can?(:read_menu, model_info.model) + uri = admin_list_uri(model_info, model_info.menu_default_link_params) + else + uri = nil + end menu << { :uri => uri, :name => model_info.item_name, @@ -76,4 +80,4 @@ def current_menu?(uri, model_info) model_info == @model_info or (not uri.nil? and current_page?(uri)) end -end \ No newline at end of file +end diff --git a/app/helpers/rademade_admin/uri_helper.rb b/app/helpers/rademade_admin/uri_helper.rb index 93cea555..88ad5f5e 100644 --- a/app/helpers/rademade_admin/uri_helper.rb +++ b/app/helpers/rademade_admin/uri_helper.rb @@ -6,7 +6,6 @@ def root_uri end def rademade_admin_route(route_url, opts = {}) - opts[:only_path] = true RademadeAdmin::Engine.routes.url_helpers.send(route_url, opts) end @@ -65,7 +64,6 @@ def admin_model_url_for(model, opts = {}) end def admin_url_for(opts) - opts[:only_path] = true Rails.application.routes.url_helpers.url_for(opts) rescue RademadeAdmin::Engine.routes.url_helpers.url_for(opts) rescue nil diff --git a/app/inputs/rademade_admin/file_input.rb b/app/inputs/rademade_admin/file_input.rb index 15ea241a..c1a01125 100644 --- a/app/inputs/rademade_admin/file_input.rb +++ b/app/inputs/rademade_admin/file_input.rb @@ -35,10 +35,13 @@ def holder_html(inner_html, hidden = false) end def file_preview_html - template.content_tag(:div, upload_preview_service.preview_html, :class => 'upload-item') + class_name = 'upload-item' + class_name += ' upload-item--file' if !photo_uploader? && !video_uploader? + template.content_tag(:div, upload_preview_service.preview_html(options.slice(:editable, :destroyable)), :class => class_name) end - + def upload_button_html + return unless options[:editable] template.content_tag( :div, RademadeAdmin::HtmlBuffer.new([ @@ -70,7 +73,7 @@ def input_hidden_html end def upload_preview_service - @upload_preview_service ||= RademadeAdmin::Upload::Preview::File.new(uploader) + @upload_preview_service ||= RademadeAdmin::Upload::Preview::FilePreview.new(uploader) end def uploader @@ -106,4 +109,4 @@ def uploader_params end end -end \ No newline at end of file +end diff --git a/app/inputs/rademade_admin/gallery_input.rb b/app/inputs/rademade_admin/gallery_input.rb index 7889d96a..7fb0fbc2 100644 --- a/app/inputs/rademade_admin/gallery_input.rb +++ b/app/inputs/rademade_admin/gallery_input.rb @@ -8,68 +8,69 @@ def input(wrapper_options = {}) template.content_tag( :div, HtmlBuffer.new([gallery_block_html, upload_block_html, gallery_hidden_html]), - :class => 'upload-list', - :data => { :gallery => '' } + class: 'upload-list', + data: { gallery: gallery_info.getter } ) end - + protected - + def gallery_block_html is_sortable = gallery_image_info.sortable_relation? template.content_tag(:div, images_html, - :class => 'upload-box', - :data => { - :sortable_url => is_sortable ? rademade_admin_route(:gallery_sort_url) : '' + class: 'upload-box', + data: { + sortable: is_sortable ? 'sortable' : nil # todo check sortable } ) end def images_html html = [] - preview_service = RademadeAdmin::Upload::Preview::Gallery.new + preview_service = RademadeAdmin::Upload::Preview::GalleryPreview.new gallery.images.each do |gallery_image| - html << preview_service.preview_html(gallery_image.image) - end + html << preview_service.preview_html( + gallery_image.image, + options.slice(:editable, :destroyable) + ) + end if gallery HtmlBuffer.new(html) end def upload_block_html - template.content_tag(:div, upload_button_html, :class => 'upload-holder') + if options[:editable] + template.content_tag(:div, upload_button_html, class: 'upload-holder') + end end def upload_button_html template.content_tag(:div, HtmlBuffer.new([ input_file_html, - template.content_tag(:span, t('rademade_admin.uploader.add.gallery'), :class => 'upload-text') - ]), :class => 'upload-item add') + template.content_tag(:span, t('rademade_admin.uploader.add.gallery'), class: 'upload-text') + ]), class: 'upload-item add') end def input_file_html template.content_tag(:input, '', - :type => 'file', - :multiple => true, - :data => { - :url => rademade_admin_route(:gallery_upload_url), - :class_name => gallery_class.to_s - } + type: 'file', + multiple: true ) end def gallery_hidden_html template.content_tag(:input, '', { - :type => 'hidden', - :name => "data[#{gallery_info.getter}]", - :value => gallery.id.to_s + type: 'hidden', + name: "data[#{gallery_info.getter}]", + value: gallery ? gallery.id.to_s : '' }) end def gallery - @gallery ||= object.send(attribute_name) || gallery_class.create + @gallery ||= object.send(attribute_name) end def gallery_info - @gallery_relation ||= model_info(object.class.to_s, attribute_name) + @gallery_relation ||= model_info(object.class, attribute_name) end def gallery_image_info @@ -85,4 +86,4 @@ def model_info(class_name, data_item_name) end end -end \ No newline at end of file +end diff --git a/app/inputs/rademade_admin/related_select_input.rb b/app/inputs/rademade_admin/related_select_input.rb index 3527b47d..adfa4efb 100644 --- a/app/inputs/rademade_admin/related_select_input.rb +++ b/app/inputs/rademade_admin/related_select_input.rb @@ -1,13 +1,10 @@ # -*- encoding : utf-8 -*- -require 'rademade_admin/input/related_select_input/model_data' -require 'rademade_admin/input/related_select_input/related_list' - module RademadeAdmin class RelatedSelectInput < SimpleForm::Inputs::CollectionSelectInput include ::RademadeAdmin::UriHelper - include ::RademadeAdmin::Input::RelatedSelectInput::ModelData - include ::RademadeAdmin::Input::RelatedSelectInput::RelatedList + include ::RademadeAdmin::RelatedSelectInput::ModelData + include ::RademadeAdmin::RelatedSelectInput::RelatedList def input(wrapper_options = {}) RademadeAdmin::HtmlBuffer.new([select_ui_html, related_html]) @@ -43,13 +40,22 @@ def html_attributes def reflection_data search_url = admin_autocomplete_uri(related_to, :format => :json) + + # add custom query params to autocomplete + params = related_data_item.form_params[:search_params] + search_url = params ? "#{search_url}?#{params.to_query}" : search_url + new_url = admin_new_form_uri(related_to) data = { :'rel-multiple' => multiple?, - :'rel-class' => related_to.to_s + :'rel-class' => related_to.to_s, + :addable => options[:addable], + :editable => options[:editable], + :destroyable => options[:destroyable], + :disabled => options[:disabled] } - data[:'search-url'] = search_url unless search_url.nil? - data[:'new-url'] = new_url unless new_url.nil? + data[:'search-url'] = search_url + data[:'new-url'] = new_url if options[:addable] && new_url data end diff --git a/app/inputs/rademade_admin/related_select_input/model_data.rb b/app/inputs/rademade_admin/related_select_input/model_data.rb new file mode 100644 index 00000000..d527c19c --- /dev/null +++ b/app/inputs/rademade_admin/related_select_input/model_data.rb @@ -0,0 +1,38 @@ +# -*- encoding : utf-8 -*- +module RademadeAdmin + class RelatedSelectInput + module ModelData + + protected + + def model + @model ||= @builder.object + end + + def related_data_item + unless @related_data_item + model_info = Model::Graph.instance.model_info(model.class) + @related_data_item = model_info.data_items.data_item(attribute_name) + end + @related_data_item + end + + def related_to + related_data_item.relation.to || related_value.class + end + + def relation_getter + related_data_item.getter + end + + def multiple? + related_data_item.relation.has_many? + end + + def related_value + @related_value ||= model.send(relation_getter) + end + + end + end +end diff --git a/app/inputs/rademade_admin/related_select_input/related_list.rb b/app/inputs/rademade_admin/related_select_input/related_list.rb new file mode 100644 index 00000000..abdb755e --- /dev/null +++ b/app/inputs/rademade_admin/related_select_input/related_list.rb @@ -0,0 +1,74 @@ +# -*- encoding : utf-8 -*- +module RademadeAdmin + class RelatedSelectInput + module RelatedList + + protected + + def related_list_html + template.content_tag(:ul, related_list_items_html, { + :class => 'select2-items-list', + :data => { + :sortable => sortable_relation?, + :deletable => destroyable_relation?, + :duplicatable => options[:editable] && options[:duplicatable] + } + }) + end + + def related_list_items_html + serialized_values = serializer.new(related_value).as_json + html = serialized_values.map do |serialized_value| + template.content_tag(:li, related_list_item_html(serialized_value), { + :class => related_item_class, + :data => serialized_value + }) + end + RademadeAdmin::HtmlBuffer.new(html) + end + + def related_list_item_html(serialized_value) + RademadeAdmin::HtmlBuffer.new([ + draggable_button_html, + related_list_item_title_html(serialized_value), + related_list_item_remove_html + ]) + end + + def draggable_button_html + template.content_tag(:i, '', { + :class => 'draggable-btn' + }) if sortable_relation? + end + + def related_list_item_title_html(serialized_value) + template.content_tag(:button, serialized_value[:text], { + :'data-edit' => options[:editable] ? serialized_value[:editurl] : '', + :class => 'select2-item-edit' + }) + end + + def related_list_item_remove_html + template.content_tag(:button, I18n.t('rademade_admin.relation.destroy'), { + :'data-remove' => '', + :class => 'select2-item-remove' + }) if destroyable_relation? + end + + def related_item_class + class_name = 'select2-item' + class_name += ' is-draggable' if sortable_relation? + class_name + end + + def sortable_relation? + options[:editable] && related_data_item.relation.sortable? + end + + def destroyable_relation? + options[:destroyable] && related_data_item.relation.destroyable? + end + + end + end +end diff --git a/app/mailers/rademade_admin/application_mailer.rb b/app/mailers/rademade_admin/application_mailer.rb new file mode 100644 index 00000000..7072204b --- /dev/null +++ b/app/mailers/rademade_admin/application_mailer.rb @@ -0,0 +1,7 @@ +module RademadeAdmin + class ApplicationMailer < ActionMailer::Base + + layout 'mailer' + + end +end diff --git a/app/mailers/rademade_admin/user_mailer.rb b/app/mailers/rademade_admin/user_mailer.rb new file mode 100644 index 00000000..f433b47f --- /dev/null +++ b/app/mailers/rademade_admin/user_mailer.rb @@ -0,0 +1,14 @@ +module RademadeAdmin + + class UserMailer < RademadeAdmin::ApplicationMailer + + def reset_password(user, token) + @token = token + @user = user + + mail(to: user.email) + end + + end + +end diff --git a/app/models/rademade_admin/ability.rb b/app/models/rademade_admin/ability.rb index 4cad4930..bd725092 100644 --- a/app/models/rademade_admin/ability.rb +++ b/app/models/rademade_admin/ability.rb @@ -7,32 +7,6 @@ def initialize(user) if user.try(:admin?) can :manage, :all end - # Define abilities for the passed in user here. For example: - # - # user ||= User.new # guest user (not logged in) - # if user.admin? - # can :manage, :all - # else - # can :read, :all - # end - # - # The first argument to `can` is the action you are giving the user - # permission to do. - # If you pass :manage it will apply to every action. Other common actions - # here are :read, :create, :update and :destroy. - # - # The second argument is the resource the user can perform the action on. - # If you pass :all it will apply to every resource. Otherwise pass a Ruby - # class of the resource. - # - # The third argument is an optional hash of conditions to further filter the - # objects. - # For example, here the user can only update published articles. - # - # can :update, Article, :published => true - # - # See the wiki for details: - # https://github.com/ryanb/cancan/wiki/Defining-Abilities end end diff --git a/app/services/gallery/manager.rb b/app/services/gallery/manager.rb deleted file mode 100644 index cdf867e6..00000000 --- a/app/services/gallery/manager.rb +++ /dev/null @@ -1,89 +0,0 @@ -module RademadeAdmin - module Gallery - class Manager - - def initialize(class_name) - @class_name = class_name - end - - def upload_images(gallery_id, files) - gallery = gallery_info.query_adapter.find(gallery_id) - image_presenter = upload_gallery_images(files) - save_gallery_images(gallery, image_presenter.gallery_images) - image_presenter.gallery_images_html - end - - def crop_image(image_id, crop_data) - gallery_image = gallery_image_info.query_adapter.find(image_id) - uploader = gallery_image.image - image = uploader.crop_image(crop_data) - uploader.store!(image) - gallery_image_info.persistence_adapter.save(gallery_image) - uploader - end - - def remove_image(image_id) - gallery_image = gallery_image_info.query_adapter.find(image_id) - gallery_image_info.persistence_adapter.destroy(gallery_image) - end - - def sort_images(images) - sort_gallery_images images - end - - protected - - def gallery_info - @gallery_info ||= RademadeAdmin::Model::Graph.instance.model_info(@class_name) - end - - def gallery_image_data_item - @gallery_image_data_item ||= gallery_info.data_items.data_item(:images) - end - - def gallery_image_relation - @gallery_image_relation ||= gallery_image_data_item.relation - end - - def gallery_image_info - @gallery_image_info ||= RademadeAdmin::Model::Graph.instance.model_info(gallery_image_relation.to) - end - - def upload_gallery_images(images) - image_presenter = RademadeAdmin::Upload::ImagePresenter.new(gallery_image_info.persistence_adapter) - image_presenter.upload_gallery_images(images) - image_presenter - end - - def save_gallery_images(gallery, gallery_images) - gallery_image_data_item.set_data(gallery, gallery.images + gallery_images) - gallery_images.each do |gallery_image| - update_gallery_image_position(gallery, gallery_image) - gallery_image_info.persistence_adapter.save(gallery_image) - end - gallery_info.persistence_adapter.save(gallery) - end - - def sort_gallery_images(images) - images.each_with_index do |image_id, index| - gallery_image = gallery_image_info.query_adapter.find(image_id) - set_gallery_image_position(gallery_image, index) - gallery_image_info.persistence_adapter.save(gallery_image) - end - end - - def update_gallery_image_position(gallery, gallery_image) - if gallery_image_relation.sortable? - last_image = gallery.images.last - previous_position = last_image.nil? ? 0 : last_image.send(gallery_image_relation.sortable_field.to_sym) - set_gallery_image_position(gallery_image, previous_position + 1) - end - end - - def set_gallery_image_position(gallery_image, position) - gallery_image.send(:"#{gallery_image_relation.sortable_field}=", position) - end - - end - end -end \ No newline at end of file diff --git a/app/services/model_controller/instance_options.rb b/app/services/model_controller/instance_options.rb deleted file mode 100644 index e1e43af4..00000000 --- a/app/services/model_controller/instance_options.rb +++ /dev/null @@ -1,46 +0,0 @@ -# -*- encoding : utf-8 -*- -module RademadeAdmin - module InstanceOptions - - attr_reader :model_info, - :model_class, - :model_name, - :item_name, - :list_fields, - # TODO form_fields refactor - :form_fields_without_locale, - :form_fields_with_locale - - def load_model_options - @model_info = self.class.model_info - @model_name = self.class.model_name - @model_class = self.class.model_class - @item_name = self.class.item_name - end - - def load_field_options - @list_fields = @model_info.data_items.list_fields - @form_fields_without_locale = @model_info.data_items.form_fields_without_locale - @form_fields_with_locale = @model_info.data_items.form_fields_with_locale - end - - def origin_fields - @model_info.data_items.origin_fields - end - - def filter_fields - @model_info.data_items.filter_fields - end - - def load_template_options - @form_template_path ||= form_template_path - end - - def load_options - load_model_options - load_field_options - load_template_options - end - - end -end diff --git a/app/services/model_controller/model_options.rb b/app/services/model_controller/model_options.rb deleted file mode 100644 index 485dad22..00000000 --- a/app/services/model_controller/model_options.rb +++ /dev/null @@ -1,49 +0,0 @@ -# -*- encoding : utf-8 -*- -module RademadeAdmin - module ModelOptions - - # Configure admin part of model - # Support options - # - model - # - name - # - parent_menu (todo extract to menu method) - # - fixed_thead - # - menu_count - # - list - # - form - # - labels - # - def options(&options_block) - configuration.instance_eval &options_block - end - - def model_name - configuration.model_name - end - - def item_name - configuration.item_name - end - - def parent_menu_item - configuration.parent_menu_item - end - - def fixed_thead_value - configuration.fixed_thead_value - end - - def model_class - configuration.model_class - end - - def model_info - @model_info ||= Model::Graph.instance.model_info(model_class) - end - - def configuration - @configuration ||= Model::Configuration.new(self) - end - - end -end diff --git a/app/services/model_controller/notifier.rb b/app/services/model_controller/notifier.rb deleted file mode 100644 index 90a63770..00000000 --- a/app/services/model_controller/notifier.rb +++ /dev/null @@ -1,61 +0,0 @@ -# -*- encoding : utf-8 -*- -module RademadeAdmin - module Notifier - - # TODO use responder (respond with) - - def success_action - render :json => { - :message => I18n.t('rademade_admin.success_message.simple') - } - end - - def success_insert(item) - respond_to do |format| - format.html { redirect_to admin_edit_uri(item) } - format.json { success_message(item, I18n.t('rademade_admin.success_message.insert'), success_data(item)) } - end - end - - def success_update(item) - respond_to do |format| - format.html { redirect_to admin_edit_uri(item) } - format.json { success_message(item, I18n.t('rademade_admin.success_message.update'), success_data(item)) } - end - end - - def success_delete(item) - respond_to do |format| - format.html { redirect_to admin_list_uri(item) } - format.json { success_message(item, I18n.t('rademade_admin.success_message.delete')) } - end - end - - def success_status_change(item) - respond_to do |format| - format.html { redirect_to admin_list_uri(item) } - format.json { success_message(item, t('rademade_admin.success_message.status_update')) } - end - end - - def success_message(item, message, additional_data = {}) - render :json => { - :data => notifier_serializer.new([item]).as_json.first, - :message => message - }.merge(additional_data) - end - - def success_data(item) - if params.has_key?(:save_and_return) - { :with_return => true } - else - { :form_action => admin_update_uri(item) } # TODO check JS. Rename for update - end - end - - def notifier_serializer - Autocomplete::BaseSerializer - end - - end -end \ No newline at end of file diff --git a/app/services/model_controller/templates.rb b/app/services/model_controller/templates.rb deleted file mode 100644 index 3c15bce3..00000000 --- a/app/services/model_controller/templates.rb +++ /dev/null @@ -1,27 +0,0 @@ -# -*- encoding : utf-8 -*- -module RademadeAdmin - module Templates - - def native_template_folder - # 15 = "RademadeAdmin::".length - # 11 = "Controller".length - # e.g. RademadeAdmin::QuestionAnswer::UsersController to "question_answer/users" - @native_template_folder ||= self.class.to_s[15..-11].underscore - end - - def form_template_path(real = false) - abstract_template((real ? '_' : '') + 'form') - end - - def abstract_template(template) - # TODO make with rails native controller extending - if template_exists?(template, @template_service.template_path(native_template_folder)) - folder = native_template_folder - else - folder = 'abstract' - end - @template_service.template_path(folder, template) - end - - end -end diff --git a/app/services/rademade_admin/base64_service.rb b/app/services/rademade_admin/base64_service.rb new file mode 100644 index 00000000..b5eb0b91 --- /dev/null +++ b/app/services/rademade_admin/base64_service.rb @@ -0,0 +1,38 @@ +# frozen_string_literal: true + +# https://gist.github.com/shrikanthkr/10097999 +module RademadeAdmin + class Base64Service + + def base64_to_file(image) + if image + image_parts = image.split(',') + matches = /\/(.+);/.match(image_parts[0]) + extension = 'jpg' + if matches && matches[1] != 'jpeg' # optimization hack + extension = matches[1] + end + image = file_decode(image_parts[1], "photo.#{extension}") + end + rescue + image + end + + def file_decode(base, filename) + file = Tempfile.new([file_base_name(filename), file_extension(filename)]) + file.binmode + file.write(Base64.decode64(base)) + file.close + file + end + + def file_base_name(file_name) + File.basename(file_name, file_extension(file_name)) + end + + def file_extension(file_name) + File.extname(file_name) + end + + end +end diff --git a/app/services/csv_service.rb b/app/services/rademade_admin/csv_service.rb similarity index 100% rename from app/services/csv_service.rb rename to app/services/rademade_admin/csv_service.rb diff --git a/app/services/error_service.rb b/app/services/rademade_admin/error_service.rb similarity index 90% rename from app/services/error_service.rb rename to app/services/rademade_admin/error_service.rb index 9021e05d..13e67fd1 100644 --- a/app/services/error_service.rb +++ b/app/services/rademade_admin/error_service.rb @@ -7,6 +7,8 @@ def error_messages_for(error) error.record.errors elsif sequel_error?(error) error.errors + elsif error.is_a?(RademadeAdmin::FieldError) + error.error_hash else error.message end diff --git a/app/services/rademade_admin/field_error.rb b/app/services/rademade_admin/field_error.rb new file mode 100644 index 00000000..ad08f09f --- /dev/null +++ b/app/services/rademade_admin/field_error.rb @@ -0,0 +1,14 @@ +module RademadeAdmin + class FieldError < Exception + + def initialize(field, message) + super(message) + @field = field + end + + def error_hash + { @field => message } + end + + end +end \ No newline at end of file diff --git a/lib/rademade_admin/gallery.rb b/app/services/rademade_admin/gallery.rb similarity index 100% rename from lib/rademade_admin/gallery.rb rename to app/services/rademade_admin/gallery.rb diff --git a/lib/rademade_admin/hideable.rb b/app/services/rademade_admin/hideable.rb similarity index 100% rename from lib/rademade_admin/hideable.rb rename to app/services/rademade_admin/hideable.rb diff --git a/lib/rademade_admin/html_buffer.rb b/app/services/rademade_admin/html_buffer.rb similarity index 100% rename from lib/rademade_admin/html_buffer.rb rename to app/services/rademade_admin/html_buffer.rb diff --git a/app/services/loader_service.rb b/app/services/rademade_admin/loader_service.rb similarity index 100% rename from app/services/loader_service.rb rename to app/services/rademade_admin/loader_service.rb diff --git a/app/services/login.rb b/app/services/rademade_admin/login.rb similarity index 89% rename from app/services/login.rb rename to app/services/rademade_admin/login.rb index bae29744..ba7f8845 100644 --- a/app/services/login.rb +++ b/app/services/rademade_admin/login.rb @@ -1,4 +1,5 @@ # -*- encoding : utf-8 -*- +# todo remove module RademadeAdmin class Login @@ -6,7 +7,7 @@ def self.admin(params) params.require(:data).permit([:email, :password]) user = RademadeAdmin.configuration.admin_class.get_by_email(params[:data][:email]) - error(I18n.t('rademade_admin.login.validation.email_not_found'), :email) unless user.is_a? RademadeAdmin.configuration.admin_class + error(I18n.t('rademade_admin.login.validation.email_not_found'), :email) if user.nil? error(I18n.t('rademade_admin.login.validation.incorrect_password'), :password) unless user.valid_password? params[:data][:password] error(I18n.t('rademade_admin.login.validation.access_denied'), :email) unless user.admin? diff --git a/app/services/login/error.rb b/app/services/rademade_admin/login/error.rb similarity index 100% rename from app/services/login/error.rb rename to app/services/rademade_admin/login/error.rb diff --git a/lib/rademade_admin/model/adapter/data.rb b/app/services/rademade_admin/model/adapter/data.rb similarity index 97% rename from lib/rademade_admin/model/adapter/data.rb rename to app/services/rademade_admin/model/adapter/data.rb index 1127198e..27277804 100644 --- a/lib/rademade_admin/model/adapter/data.rb +++ b/app/services/rademade_admin/model/adapter/data.rb @@ -123,7 +123,7 @@ def _model_fields def _relation_class_name(to_class) if !to_class.nil? && to_class.ancestors.include?(RademadeAdmin::Gallery) - ::RademadeAdmin::Model::Info::Relation::Gallery + ::RademadeAdmin::Model::Info::Relation::GalleryRelation else ::RademadeAdmin::Model::Info::Relation end diff --git a/lib/rademade_admin/model/adapter/data/active_record.rb b/app/services/rademade_admin/model/adapter/data/active_record_data.rb similarity index 98% rename from lib/rademade_admin/model/adapter/data/active_record.rb rename to app/services/rademade_admin/model/adapter/data/active_record_data.rb index 0be0749e..523a7017 100644 --- a/lib/rademade_admin/model/adapter/data/active_record.rb +++ b/app/services/rademade_admin/model/adapter/data/active_record_data.rb @@ -3,7 +3,7 @@ module RademadeAdmin module Model module Adapter class Data - class ActiveRecord < RademadeAdmin::Model::Adapter::Data + class ActiveRecordData < RademadeAdmin::Model::Adapter::Data protected @@ -145,4 +145,4 @@ def datetime_type?(field_data) end end end -end \ No newline at end of file +end diff --git a/lib/rademade_admin/model/adapter/data/mongoid.rb b/app/services/rademade_admin/model/adapter/data/mongoid_data.rb similarity index 97% rename from lib/rademade_admin/model/adapter/data/mongoid.rb rename to app/services/rademade_admin/model/adapter/data/mongoid_data.rb index de36c6e6..a8f237fa 100644 --- a/lib/rademade_admin/model/adapter/data/mongoid.rb +++ b/app/services/rademade_admin/model/adapter/data/mongoid_data.rb @@ -3,7 +3,7 @@ module RademadeAdmin module Model module Adapter class Data - class Mongoid < RademadeAdmin::Model::Adapter::Data + class MongoidData < RademadeAdmin::Model::Adapter::Data protected @@ -65,7 +65,7 @@ def _relation_destroyable? def _model_fields @model.fields.keys.map(&:to_sym) end - + private def field_type(type) @@ -85,4 +85,4 @@ def field_type(type) end end end -end \ No newline at end of file +end diff --git a/lib/rademade_admin/model/adapter/data/sequel.rb b/app/services/rademade_admin/model/adapter/data/sequel_data.rb similarity index 69% rename from lib/rademade_admin/model/adapter/data/sequel.rb rename to app/services/rademade_admin/model/adapter/data/sequel_data.rb index 657ab74f..3292aece 100644 --- a/lib/rademade_admin/model/adapter/data/sequel.rb +++ b/app/services/rademade_admin/model/adapter/data/sequel_data.rb @@ -3,7 +3,7 @@ module RademadeAdmin module Model module Adapter class Data - class Sequel < RademadeAdmin::Model::Adapter::Data + class SequelData < RademadeAdmin::Model::Adapter::Data protected @@ -37,6 +37,7 @@ def _map_relations to_class = RademadeAdmin::LoaderService.const_get(relation_info[:class_name]) rescue nil has_many = has_many_relations.include?(relation_info[:type]) getter = name + is_sortable = to_class ? to_class.columns.include?(:position) && relation_info[:type] != :many_to_many : false relations[name] = _relation_class_name(to_class).new({ :name => name, :from => @model, @@ -48,7 +49,8 @@ def _map_relations :many => relation_info[:type] == :one_to_many, :has_many => has_many, :destroyable => _relation_destroyable?, - :sortable => false, + :sortable => is_sortable, + :sortable_field => is_sortable ? :position : nil, :foreign_key => relation_info[:key] }) end @@ -61,12 +63,25 @@ def _relation_destroyable? def _to_many_setter(relation_info, getter) Proc.new do |new_items| + model_info = RademadeAdmin::Model::Graph.instance.model_info(self.class) + if model_info.data_items.data_item(relation_info[:name]).relation.sortable? + new_items.each_with_index do |item, position| + item.position = position + item.save_changes + end + end old_items = self.send(getter) - (old_items - new_items).each do |related_item| - self.instance_exec(related_item, &relation_info[:remover]) + new_items_ids = new_items.map &:id + old_items_ids = old_items.map &:id + old_items.each do |related_item| + unless new_items_ids.include?(related_item.id) + self.instance_exec(related_item, &relation_info[:remover]) + end end - (new_items - old_items).each do |related_item| - self.instance_exec(related_item, &relation_info[:adder]) + new_items.each do |related_item| + unless old_items_ids.include?(related_item.id) + self.instance_exec(related_item, &relation_info[:adder]) + end end end end @@ -90,4 +105,4 @@ def field_type(type) end end end -end \ No newline at end of file +end diff --git a/lib/rademade_admin/model/adapter/persistence.rb b/app/services/rademade_admin/model/adapter/persistence.rb similarity index 90% rename from lib/rademade_admin/model/adapter/persistence.rb rename to app/services/rademade_admin/model/adapter/persistence.rb index 335c8130..243790ec 100644 --- a/lib/rademade_admin/model/adapter/persistence.rb +++ b/app/services/rademade_admin/model/adapter/persistence.rb @@ -16,7 +16,7 @@ def new?(record) nil end - def save(record) + def save(record, options = {}) nil end @@ -27,4 +27,4 @@ def destroy(record) end end end -end \ No newline at end of file +end diff --git a/lib/rademade_admin/model/adapter/persistence/mongoid.rb b/app/services/rademade_admin/model/adapter/persistence/active_record_persistence.rb similarity index 66% rename from lib/rademade_admin/model/adapter/persistence/mongoid.rb rename to app/services/rademade_admin/model/adapter/persistence/active_record_persistence.rb index 8d71ccd7..9a70cc25 100644 --- a/lib/rademade_admin/model/adapter/persistence/mongoid.rb +++ b/app/services/rademade_admin/model/adapter/persistence/active_record_persistence.rb @@ -3,13 +3,13 @@ module RademadeAdmin module Model module Adapter class Persistence - class Mongoid < RademadeAdmin::Model::Adapter::Persistence + class ActiveRecordPersistence < RademadeAdmin::Model::Adapter::Persistence def new?(record) record.new_record? end - def save(record) + def save(record, options = {}) record.save! end @@ -17,4 +17,4 @@ def save(record) end end end -end \ No newline at end of file +end diff --git a/lib/rademade_admin/model/adapter/persistence/active_record.rb b/app/services/rademade_admin/model/adapter/persistence/mongoid_persistence.rb similarity index 67% rename from lib/rademade_admin/model/adapter/persistence/active_record.rb rename to app/services/rademade_admin/model/adapter/persistence/mongoid_persistence.rb index 92684db9..8c9ef944 100644 --- a/lib/rademade_admin/model/adapter/persistence/active_record.rb +++ b/app/services/rademade_admin/model/adapter/persistence/mongoid_persistence.rb @@ -3,13 +3,13 @@ module RademadeAdmin module Model module Adapter class Persistence - class ActiveRecord < RademadeAdmin::Model::Adapter::Persistence + class MongoidPersistence < RademadeAdmin::Model::Adapter::Persistence def new?(record) record.new_record? end - def save(record) + def save(record, options = {}) record.save! end @@ -17,4 +17,4 @@ def save(record) end end end -end \ No newline at end of file +end diff --git a/app/services/rademade_admin/model/adapter/persistence/sequel_persistence.rb b/app/services/rademade_admin/model/adapter/persistence/sequel_persistence.rb new file mode 100644 index 00000000..5f726d77 --- /dev/null +++ b/app/services/rademade_admin/model/adapter/persistence/sequel_persistence.rb @@ -0,0 +1,32 @@ +# -*- encoding : utf-8 -*- +module RademadeAdmin + module Model + module Adapter + class Persistence + class SequelPersistence < RademadeAdmin::Model::Adapter::Persistence + + def initialize(model) + @model = model + end + + def new_record + @model.new + end + + def new?(record) + record.new? + end + + def destroy(record) + record.destroy + end + + def save(record, options = {}) + record.save(options) + end + + end + end + end + end +end diff --git a/lib/rademade_admin/model/adapter/query.rb b/app/services/rademade_admin/model/adapter/query.rb similarity index 100% rename from lib/rademade_admin/model/adapter/query.rb rename to app/services/rademade_admin/model/adapter/query.rb diff --git a/lib/rademade_admin/model/adapter/query/active_record.rb b/app/services/rademade_admin/model/adapter/query/active_record_query.rb similarity index 86% rename from lib/rademade_admin/model/adapter/query/active_record.rb rename to app/services/rademade_admin/model/adapter/query/active_record_query.rb index aebc8591..2faae233 100644 --- a/lib/rademade_admin/model/adapter/query/active_record.rb +++ b/app/services/rademade_admin/model/adapter/query/active_record_query.rb @@ -1,11 +1,9 @@ # -*- encoding : utf-8 -*- -require 'rademade_admin/model/adapter/query/sql' - module RademadeAdmin module Model module Adapter class Query - class ActiveRecord < RademadeAdmin::Model::Adapter::Query::Sql + class ActiveRecordQuery < RademadeAdmin::Model::Adapter::Query::SqlQuery def find(ids) @model.find(ids) @@ -36,4 +34,4 @@ def paginate(page_condition, per_page_condition) end end end -end \ No newline at end of file +end diff --git a/lib/rademade_admin/model/adapter/query/mongoid.rb b/app/services/rademade_admin/model/adapter/query/mongoid_query.rb similarity index 96% rename from lib/rademade_admin/model/adapter/query/mongoid.rb rename to app/services/rademade_admin/model/adapter/query/mongoid_query.rb index 945987e0..5677fa09 100644 --- a/lib/rademade_admin/model/adapter/query/mongoid.rb +++ b/app/services/rademade_admin/model/adapter/query/mongoid_query.rb @@ -3,7 +3,7 @@ module RademadeAdmin module Model module Adapter class Query - class Mongoid < RademadeAdmin::Model::Adapter::Query + class MongoidQuery < RademadeAdmin::Model::Adapter::Query def find(ids) @model.find(ids) diff --git a/lib/rademade_admin/model/adapter/query/mysql.rb b/app/services/rademade_admin/model/adapter/query/mysql_query.rb similarity index 50% rename from lib/rademade_admin/model/adapter/query/mysql.rb rename to app/services/rademade_admin/model/adapter/query/mysql_query.rb index 2c6e1e3a..832e2d64 100644 --- a/lib/rademade_admin/model/adapter/query/mysql.rb +++ b/app/services/rademade_admin/model/adapter/query/mysql_query.rb @@ -1,14 +1,12 @@ # -*- encoding : utf-8 -*- -require 'rademade_admin/model/adapter/query/active_record' - module RademadeAdmin module Model module Adapter class Query - class Mysql < RademadeAdmin::Model::Adapter::Query::ActiveRecord + class MysqlQuery < RademadeAdmin::Model::Adapter::Query::ActiveRecordQuery end end end end -end \ No newline at end of file +end diff --git a/lib/rademade_admin/model/adapter/query/postgresql.rb b/app/services/rademade_admin/model/adapter/query/postgresql_query.rb similarity index 78% rename from lib/rademade_admin/model/adapter/query/postgresql.rb rename to app/services/rademade_admin/model/adapter/query/postgresql_query.rb index dfc7fe79..f8bb88aa 100644 --- a/lib/rademade_admin/model/adapter/query/postgresql.rb +++ b/app/services/rademade_admin/model/adapter/query/postgresql_query.rb @@ -1,11 +1,9 @@ # -*- encoding : utf-8 -*- -require 'rademade_admin/model/adapter/query/active_record' - module RademadeAdmin module Model module Adapter class Query - class Postgresql < RademadeAdmin::Model::Adapter::Query::ActiveRecord + class PostgresqlQuery < RademadeAdmin::Model::Adapter::Query::ActiveRecordQuery protected diff --git a/lib/rademade_admin/model/adapter/query/sequel.rb b/app/services/rademade_admin/model/adapter/query/sequel_query.rb similarity index 64% rename from lib/rademade_admin/model/adapter/query/sequel.rb rename to app/services/rademade_admin/model/adapter/query/sequel_query.rb index f1139364..a4176156 100644 --- a/lib/rademade_admin/model/adapter/query/sequel.rb +++ b/app/services/rademade_admin/model/adapter/query/sequel_query.rb @@ -1,11 +1,9 @@ # -*- encoding : utf-8 -*- -require 'rademade_admin/model/adapter/query/sql' - module RademadeAdmin module Model module Adapter class Query - class Sequel < RademadeAdmin::Model::Adapter::Query::Sql + class SequelQuery < RademadeAdmin::Model::Adapter::Query::SqlQuery def find(ids) @model[ids] @@ -17,6 +15,17 @@ def initial protected + def build_where_condition(field: nil, value: nil) + field = table_field(field) + if value.is_a? Regexp + ["LOWER(#{field}) ~* ?", [value.source]] + elsif value.is_a? Array + ["#{field} IN (?)", [value]] + else + ["#{field} = ?", [value]] + end + end + def order(order_conditions) order_conditions.parts.each do |part| if part.is_a? RademadeAdmin::Search::Part::Order @@ -36,4 +45,4 @@ def paginate(page_condition, per_page_condition) end end end -end \ No newline at end of file +end diff --git a/lib/rademade_admin/model/adapter/query/sql.rb b/app/services/rademade_admin/model/adapter/query/sql_query.rb similarity index 95% rename from lib/rademade_admin/model/adapter/query/sql.rb rename to app/services/rademade_admin/model/adapter/query/sql_query.rb index f76e9319..b0c63701 100644 --- a/lib/rademade_admin/model/adapter/query/sql.rb +++ b/app/services/rademade_admin/model/adapter/query/sql_query.rb @@ -3,7 +3,7 @@ module RademadeAdmin module Model module Adapter class Query - class Sql < RademadeAdmin::Model::Adapter::Query + class SqlQuery < RademadeAdmin::Model::Adapter::Query protected @@ -47,4 +47,4 @@ def table_field(field) end end end -end \ No newline at end of file +end diff --git a/lib/rademade_admin/model/configuration.rb b/app/services/rademade_admin/model/configuration.rb similarity index 84% rename from lib/rademade_admin/model/configuration.rb rename to app/services/rademade_admin/model/configuration.rb index 5b46cac6..ba0cee3c 100644 --- a/lib/rademade_admin/model/configuration.rb +++ b/app/services/rademade_admin/model/configuration.rb @@ -3,7 +3,8 @@ module RademadeAdmin module Model class Configuration - attr_reader :controller, :parent_menu_item, :fixed_thead_value, :model_name, :menu_count_block, :preview_url_block + attr_reader :controller, :parent_menu_item, :menu_default_link_params, :fixed_thead_value, :model_name, + :menu_count_block, :preview_url_block, :title_field, :title_block def initialize(controller) @controller = controller @@ -73,6 +74,14 @@ def preview_url(&block) @preview_url_block = block end + def title(value = nil, &block) + if block_given? + @title_block = block + else + @title_field = value + end + end + private def name(item_name) @@ -83,6 +92,10 @@ def parent_menu(parent_menu_item) @parent_menu_item = parent_menu_item end + def menu_link_params(menu_link_params) + @menu_default_link_params = menu_link_params + end + def fixed_thead(value) @fixed_thead_value = value ? true : false end @@ -105,4 +118,4 @@ def form(*field_options, &block) end end -end \ No newline at end of file +end diff --git a/lib/rademade_admin/model/configuration/csv_fields.rb b/app/services/rademade_admin/model/configuration/csv_fields.rb similarity index 72% rename from lib/rademade_admin/model/configuration/csv_fields.rb rename to app/services/rademade_admin/model/configuration/csv_fields.rb index 977f17b6..0c8e71c8 100644 --- a/lib/rademade_admin/model/configuration/csv_fields.rb +++ b/app/services/rademade_admin/model/configuration/csv_fields.rb @@ -1,6 +1,4 @@ # -*- encoding : utf-8 -*- -require 'rademade_admin/model/configuration/list_fields' - module RademadeAdmin module Model class Configuration diff --git a/lib/rademade_admin/model/configuration/field_label.rb b/app/services/rademade_admin/model/configuration/field_label.rb similarity index 100% rename from lib/rademade_admin/model/configuration/field_label.rb rename to app/services/rademade_admin/model/configuration/field_label.rb diff --git a/lib/rademade_admin/model/configuration/fields.rb b/app/services/rademade_admin/model/configuration/fields.rb similarity index 100% rename from lib/rademade_admin/model/configuration/fields.rb rename to app/services/rademade_admin/model/configuration/fields.rb diff --git a/lib/rademade_admin/model/configuration/fields_labels.rb b/app/services/rademade_admin/model/configuration/fields_labels.rb similarity index 91% rename from lib/rademade_admin/model/configuration/fields_labels.rb rename to app/services/rademade_admin/model/configuration/fields_labels.rb index 5142abc5..476c0230 100644 --- a/lib/rademade_admin/model/configuration/fields_labels.rb +++ b/app/services/rademade_admin/model/configuration/fields_labels.rb @@ -1,6 +1,4 @@ # -*- encoding : utf-8 -*- -require 'rademade_admin/model/configuration/fields' - module RademadeAdmin module Model class Configuration diff --git a/lib/rademade_admin/model/configuration/form_field.rb b/app/services/rademade_admin/model/configuration/form_field.rb similarity index 100% rename from lib/rademade_admin/model/configuration/form_field.rb rename to app/services/rademade_admin/model/configuration/form_field.rb diff --git a/lib/rademade_admin/model/configuration/form_fields.rb b/app/services/rademade_admin/model/configuration/form_fields.rb similarity index 83% rename from lib/rademade_admin/model/configuration/form_fields.rb rename to app/services/rademade_admin/model/configuration/form_fields.rb index 80a30f7d..1194e4c6 100644 --- a/lib/rademade_admin/model/configuration/form_fields.rb +++ b/app/services/rademade_admin/model/configuration/form_fields.rb @@ -1,6 +1,4 @@ # -*- encoding : utf-8 -*- -require 'rademade_admin/model/configuration/fields' - module RademadeAdmin module Model class Configuration diff --git a/lib/rademade_admin/model/configuration/list_field.rb b/app/services/rademade_admin/model/configuration/list_field.rb similarity index 100% rename from lib/rademade_admin/model/configuration/list_field.rb rename to app/services/rademade_admin/model/configuration/list_field.rb diff --git a/lib/rademade_admin/model/configuration/list_fields.rb b/app/services/rademade_admin/model/configuration/list_fields.rb similarity index 83% rename from lib/rademade_admin/model/configuration/list_fields.rb rename to app/services/rademade_admin/model/configuration/list_fields.rb index 27ceb5f3..500fa53a 100644 --- a/lib/rademade_admin/model/configuration/list_fields.rb +++ b/app/services/rademade_admin/model/configuration/list_fields.rb @@ -1,6 +1,4 @@ # -*- encoding : utf-8 -*- -require 'rademade_admin/model/configuration/fields' - module RademadeAdmin module Model class Configuration diff --git a/lib/rademade_admin/model/graph.rb b/app/services/rademade_admin/model/graph.rb similarity index 85% rename from lib/rademade_admin/model/graph.rb rename to app/services/rademade_admin/model/graph.rb index 4fc3974b..fd801cd9 100644 --- a/lib/rademade_admin/model/graph.rb +++ b/app/services/rademade_admin/model/graph.rb @@ -21,10 +21,20 @@ def add_pair(module_name, controller_name) }) end + def add_pair_lazy(module_name, controller_name) + @pairs << { module_name: module_name, controller_name: controller_name } + end + + def init_pairs + while pair = @pairs.shift + add_pair(pair[:module_name], pair[:controller_name]) + end + end + def model_info(model) model_name = model.to_s @model_infos[model_name] ||= init_model_info({ - :model => model, + :model => model.is_a?(String) ? LoaderService.const_get(model) : model, :controller => default_controller(model_name) }) end @@ -33,6 +43,7 @@ def model_info(model) def initialize @model_infos = {} + @pairs = [] end def init_model_info(model: nil, controller_name: nil, module_name: nil, controller: nil) diff --git a/lib/rademade_admin/model/info.rb b/app/services/rademade_admin/model/info.rb similarity index 87% rename from lib/rademade_admin/model/info.rb rename to app/services/rademade_admin/model/info.rb index b3054b7d..62951290 100644 --- a/lib/rademade_admin/model/info.rb +++ b/app/services/rademade_admin/model/info.rb @@ -48,6 +48,10 @@ def parent_menu @model_configuration.parent_menu_item end + def menu_default_link_params + @model_configuration.menu_default_link_params || {} + end + def fixed_thead @model_configuration.fixed_thead_value end @@ -100,6 +104,16 @@ def label_for(name) @model_configuration.field_labels.label_for(name) end + def title_of(item) + if @model_configuration.title_field + item.public_send(@model_configuration.title_field) + elsif @model_configuration.title_block + @model_configuration.title_block.call(item) + else + item.to_s + end + end + protected def _data_adapter @@ -120,4 +134,4 @@ def uploaders end end -end \ No newline at end of file +end diff --git a/lib/rademade_admin/model/info/data_item.rb b/app/services/rademade_admin/model/info/data_item.rb similarity index 99% rename from lib/rademade_admin/model/info/data_item.rb rename to app/services/rademade_admin/model/info/data_item.rb index 1fafbc5e..49ca0bdc 100644 --- a/lib/rademade_admin/model/info/data_item.rb +++ b/app/services/rademade_admin/model/info/data_item.rb @@ -47,7 +47,7 @@ def sortable_relation? end def gallery_relation? - @relation.is_a? RademadeAdmin::Model::Info::Relation::Gallery + @relation.is_a? RademadeAdmin::Model::Info::Relation::GalleryRelation end def localizable?(localizable = true) @@ -142,4 +142,4 @@ def _getter end end end -end \ No newline at end of file +end diff --git a/lib/rademade_admin/model/info/data_item/initializer.rb b/app/services/rademade_admin/model/info/data_item/initializer.rb similarity index 100% rename from lib/rademade_admin/model/info/data_item/initializer.rb rename to app/services/rademade_admin/model/info/data_item/initializer.rb diff --git a/lib/rademade_admin/model/info/data_items.rb b/app/services/rademade_admin/model/info/data_items.rb similarity index 99% rename from lib/rademade_admin/model/info/data_items.rb rename to app/services/rademade_admin/model/info/data_items.rb index 74b364d8..f22cc14b 100644 --- a/lib/rademade_admin/model/info/data_items.rb +++ b/app/services/rademade_admin/model/info/data_items.rb @@ -133,4 +133,4 @@ def collect_field_names end end end -end \ No newline at end of file +end diff --git a/lib/rademade_admin/model/info/field.rb b/app/services/rademade_admin/model/info/field.rb similarity index 100% rename from lib/rademade_admin/model/info/field.rb rename to app/services/rademade_admin/model/info/field.rb diff --git a/lib/rademade_admin/model/info/field/type.rb b/app/services/rademade_admin/model/info/field/type.rb similarity index 100% rename from lib/rademade_admin/model/info/field/type.rb rename to app/services/rademade_admin/model/info/field/type.rb diff --git a/lib/rademade_admin/model/info/fields.rb b/app/services/rademade_admin/model/info/fields.rb similarity index 100% rename from lib/rademade_admin/model/info/fields.rb rename to app/services/rademade_admin/model/info/fields.rb diff --git a/lib/rademade_admin/model/info/relation.rb b/app/services/rademade_admin/model/info/relation.rb similarity index 100% rename from lib/rademade_admin/model/info/relation.rb rename to app/services/rademade_admin/model/info/relation.rb diff --git a/lib/rademade_admin/model/info/relation/gallery.rb b/app/services/rademade_admin/model/info/relation/gallery_relation.rb similarity index 77% rename from lib/rademade_admin/model/info/relation/gallery.rb rename to app/services/rademade_admin/model/info/relation/gallery_relation.rb index 300fcc46..dac8b81c 100644 --- a/lib/rademade_admin/model/info/relation/gallery.rb +++ b/app/services/rademade_admin/model/info/relation/gallery_relation.rb @@ -3,7 +3,7 @@ module RademadeAdmin module Model class Info class Relation - class Gallery < Relation + class GalleryRelation < Relation end end diff --git a/lib/rademade_admin/model/info/relations.rb b/app/services/rademade_admin/model/info/relations.rb similarity index 100% rename from lib/rademade_admin/model/info/relations.rb rename to app/services/rademade_admin/model/info/relations.rb diff --git a/lib/rademade_admin/model/info/uploader.rb b/app/services/rademade_admin/model/info/uploader.rb similarity index 72% rename from lib/rademade_admin/model/info/uploader.rb rename to app/services/rademade_admin/model/info/uploader.rb index 3604b38f..d89f7bdb 100644 --- a/lib/rademade_admin/model/info/uploader.rb +++ b/app/services/rademade_admin/model/info/uploader.rb @@ -17,6 +17,13 @@ def remove_proc end end + def remote_url_setter_proc(remote_url) + method_name = :"remote_#{name}_url=" + Proc.new do + self.send(method_name, remote_url) + end + end + def full_path_for(image_path) "#{CarrierWave.root}#{image_path}" end @@ -24,4 +31,4 @@ def full_path_for(image_path) end end end -end \ No newline at end of file +end diff --git a/lib/rademade_admin/model/info/uploaders.rb b/app/services/rademade_admin/model/info/uploaders.rb similarity index 100% rename from lib/rademade_admin/model/info/uploaders.rb rename to app/services/rademade_admin/model/info/uploaders.rb diff --git a/lib/rademade_admin/model/reflection.rb b/app/services/rademade_admin/model/reflection.rb similarity index 92% rename from lib/rademade_admin/model/reflection.rb rename to app/services/rademade_admin/model/reflection.rb index 128de8df..a6c996ae 100644 --- a/lib/rademade_admin/model/reflection.rb +++ b/app/services/rademade_admin/model/reflection.rb @@ -19,18 +19,18 @@ def initialize(model, controller, module_name) # # @return [RademadeAdmin::Model::Adapter::Data] def data_adapter - @data_adapter ||= "RademadeAdmin::Model::Adapter::Data::#{orm_type}".constantize.new(@model) + @data_adapter ||= "RademadeAdmin::Model::Adapter::Data::#{orm_type}Data".constantize.new(@model) end # Load query adapter for current model # # @return [RademadeAdmin::Model::Adapter::Query] def query_adapter - @query_adapter ||= "RademadeAdmin::Model::Adapter::Query::#{query_adapter_type}".constantize.new(@model) + @query_adapter ||= "RademadeAdmin::Model::Adapter::Query::#{query_adapter_type}Query".constantize.new(@model) end def persistence_adapter - @persistence_adapter ||= "RademadeAdmin::Model::Adapter::Persistence::#{orm_type}".constantize.new(@model) + @persistence_adapter ||= "RademadeAdmin::Model::Adapter::Persistence::#{orm_type}Persistence".constantize.new(@model) end def hideable? @@ -68,4 +68,4 @@ def query_adapter_type end end end -end \ No newline at end of file +end diff --git a/app/services/rademade_admin/model_controller_modules/instance_options.rb b/app/services/rademade_admin/model_controller_modules/instance_options.rb new file mode 100644 index 00000000..2da94afe --- /dev/null +++ b/app/services/rademade_admin/model_controller_modules/instance_options.rb @@ -0,0 +1,48 @@ +# -*- encoding : utf-8 -*- +module RademadeAdmin + module ModelControllerModules + module InstanceOptions + + attr_reader :model_info, + :model_class, + :model_name, + :item_name, + :list_fields, + # TODO form_fields refactor + :form_fields_without_locale, + :form_fields_with_locale + + def load_model_options + @model_info = self.class.model_info + @model_name = self.class.model_name + @model_class = self.class.model_class + @item_name = self.class.item_name + end + + def load_field_options + @list_fields = @model_info.data_items.list_fields + @form_fields_without_locale = @model_info.data_items.form_fields_without_locale + @form_fields_with_locale = @model_info.data_items.form_fields_with_locale + end + + def origin_fields + @model_info.data_items.origin_fields + end + + def filter_fields + @model_info.data_items.filter_fields + end + + def load_template_options + @form_template_path ||= form_template_path + end + + def load_options + load_model_options + load_field_options + load_template_options + end + + end + end +end diff --git a/app/services/rademade_admin/model_controller_modules/model_options.rb b/app/services/rademade_admin/model_controller_modules/model_options.rb new file mode 100644 index 00000000..513c040c --- /dev/null +++ b/app/services/rademade_admin/model_controller_modules/model_options.rb @@ -0,0 +1,51 @@ +# -*- encoding : utf-8 -*- +module RademadeAdmin + module ModelControllerModules + module ModelOptions + + # Configure admin part of model + # Support options + # - model + # - name + # - parent_menu (todo extract to menu method) + # - fixed_thead + # - menu_count + # - list + # - form + # - labels + # + def options(&options_block) + configuration.instance_eval &options_block + end + + def model_name + configuration.model_name + end + + def item_name + configuration.item_name + end + + def parent_menu_item + configuration.parent_menu_item + end + + def fixed_thead_value + configuration.fixed_thead_value + end + + def model_class + configuration.model_class + end + + def model_info + @model_info ||= ::RademadeAdmin::Model::Graph.instance.model_info(model_class) + end + + def configuration + @configuration ||= ::RademadeAdmin::Model::Configuration.new(self) + end + + end + end +end diff --git a/app/services/rademade_admin/model_controller_modules/notifier.rb b/app/services/rademade_admin/model_controller_modules/notifier.rb new file mode 100644 index 00000000..3af6c843 --- /dev/null +++ b/app/services/rademade_admin/model_controller_modules/notifier.rb @@ -0,0 +1,63 @@ +# -*- encoding : utf-8 -*- +module RademadeAdmin + module ModelControllerModules + module Notifier + + # TODO use responder (respond with) + + def success_action + render :json => { + :message => I18n.t('rademade_admin.success_message.simple') + } + end + + def success_insert(item) + respond_to do |format| + format.html { redirect_to admin_edit_uri(item) } + format.json { success_message(item, I18n.t('rademade_admin.success_message.insert'), success_data(item)) } + end + end + + def success_update(item) + respond_to do |format| + format.html { redirect_to admin_edit_uri(item) } + format.json { success_message(item, I18n.t('rademade_admin.success_message.update'), success_data(item)) } + end + end + + def success_delete(item) + respond_to do |format| + format.html { redirect_to admin_list_uri(item) } + format.json { success_message(item, I18n.t('rademade_admin.success_message.delete')) } + end + end + + def success_status_change(item) + respond_to do |format| + format.html { redirect_to admin_list_uri(item) } + format.json { success_message(item, t('rademade_admin.success_message.status_update')) } + end + end + + def success_message(item, message, additional_data = {}) + render :json => { + :data => notifier_serializer.new([item]).as_json.first, + :message => message + }.merge(additional_data) + end + + def success_data(item) + if params.has_key?(:save_and_return) + { :with_return => true } + else + { :form_action => admin_update_uri(item) } # TODO check JS. Rename for update + end + end + + def notifier_serializer + Autocomplete::BaseSerializer + end + + end + end +end diff --git a/app/services/rademade_admin/model_controller_modules/templates.rb b/app/services/rademade_admin/model_controller_modules/templates.rb new file mode 100644 index 00000000..7f13cb45 --- /dev/null +++ b/app/services/rademade_admin/model_controller_modules/templates.rb @@ -0,0 +1,26 @@ +# -*- encoding : utf-8 -*- +module RademadeAdmin + module ModelControllerModules + module Templates + + def native_template_folder + # e.g. RademadeAdmin::QuestionAnswer::UsersController to "rademade_admin/question_answer/users" + @native_template_folder ||= self.class.to_s.gsub('Controller', '').underscore + end + + def form_template_path(real = false) + abstract_template((real ? '_' : '') + 'form') + end + + def abstract_template(template) + # TODO make with rails native controller extending + if template_exists?(template, native_template_folder) + "#{native_template_folder}/#{template}" + else + @template_service.template_path('abstract', template) + end + end + + end + end +end diff --git a/app/services/rademade_admin/reset_password.rb b/app/services/rademade_admin/reset_password.rb new file mode 100644 index 00000000..0761a0c9 --- /dev/null +++ b/app/services/rademade_admin/reset_password.rb @@ -0,0 +1,20 @@ +# -*- encoding : utf-8 -*- +module RademadeAdmin + class ResetPassword + + MIN_PASSWORD_LENGTH = 6 + + def self.call(password:, password_repeat:, user:) + error(I18n.t('rademade_admin.login.validation.password_length', length: MIN_PASSWORD_LENGTH), :password) if password.length < MIN_PASSWORD_LENGTH + error(I18n.t('rademade_admin.login.validation.password_not_match'), :password_repeat) if password != password_repeat + error(I18n.t('rademade_admin.login.validation.access_denied'), :password) unless user.admin? + user.password = password + user.save + end + + def self.error(message, field) + raise FieldError.new(field, message) + end + + end +end diff --git a/app/services/rademade_admin/saver.rb b/app/services/rademade_admin/saver.rb new file mode 100644 index 00000000..26f5c1e4 --- /dev/null +++ b/app/services/rademade_admin/saver.rb @@ -0,0 +1,164 @@ +# -*- encoding : utf-8 -*- +module RademadeAdmin + class Saver + + attr_accessor :item + + # Initialization of model saver class + # + # @param model_info [RademadeAdmin::Model::Info] + # @param params [Hash] + # + def initialize(model_info, params) + @model_info, @params = model_info, params + end + + def create_model + @item = @model_info.persistence_adapter.new_record + end + + def find_model + @item = @model_info.query_adapter.find(@params[:id]) + end + + def set_data + save_galleries + save_simple_fields + save_localizable_fields + save_item(validate: false) if @model_info.persistence_adapter.new?(item) # to init id + save_model_uploads + save_model_relations + save_item + end + + def save_item(options = {}) + @model_info.persistence_adapter.save(item, options) + end + + private + + def save_simple_fields + simple_field_params.each do |field, value| + item.send(:"#{field}=", value) + end + end + + def save_localizable_fields + current_locale = I18n.locale + @model_info.data_items.localizable_fields.each do |_, data_item| + values = @params[:data].try(:[], data_item.name) + values.each do |locale, value| + I18n.locale = locale + if data_item.has_uploader? + save_model_upload(data_item, value) + else + data_item.set_data(item, value) + end + end if values + end + I18n.locale = current_locale + end + + def save_model_relations + data = @params[:data] + @model_info.data_items.related_fields.each do |_, data_item| + if !data_item.gallery_relation? && data.has_key?(data_item.name) + data_item.set_data(item, find_entities(data_item, data[data_item.name])) + end + end + end + + def save_model_uploads + data = @params[:data] + @model_info.data_items.uploader_fields.each do |_, data_item| + name = data_item.name + save_model_upload(data_item, data[name]) if data.has_key?(name) + end + end + + def save_galleries + data = @params[:data] + @model_info.data_items.items.each do |_, data_item| + if data_item.gallery_relation? + name = data_item.name + if data.has_key? name + gallery_info = RademadeAdmin::Model::Graph.instance.model_info(data_item.relation.to) + gallery = gallery_info.query_adapter.find(data[name].to_i) + unless gallery + gallery = gallery_info.persistence_adapter.new_record + gallery_info.persistence_adapter.save(gallery) + @item.send(:"#{name}_id=", gallery.id) + end + save_gallery_images(gallery_info, gallery, data["#{name}_images"]) + end + end + end + end + + def save_gallery_images(gallery_info, gallery, images_data) + return unless images_data + gallery_image_data_item = gallery_info.data_items.data_item(:images) + gallery_image_relation = gallery_image_data_item.relation + gallery_image_info = RademadeAdmin::Model::Graph.instance.model_info(gallery_image_relation.to) + saved_gallery_images = [] + images_data.each do |index, image_data| + next unless image_data + position = index.to_i + 1 + if image_data.has_key? :image_id + gallery_image = gallery_image_info.query_adapter.find(image_data[:image_id]) + gallery_image.update(gallery_image_relation.sortable_field => position) if gallery_image_relation.sortable? + else + gallery_image = gallery_image_info.persistence_adapter.new_record + gallery_image_info.persistence_adapter.save(gallery_image) + if gallery_image_relation.sortable? + gallery_image.public_send("#{gallery_image_relation.sortable_field}=", position) + end + gallery_image.image = ::RademadeAdmin::Base64Service.new.base64_to_file(image_data[:full_url]) + raise I18n.t('rademade_admin.uploader.error.gallery') if gallery_image.image.blank? + gallery_image_info.persistence_adapter.save(gallery_image) + end + saved_gallery_images << gallery_image + end + gallery_image_data_item.set_data(gallery, saved_gallery_images) + end + + def save_model_upload(data_item, image_path) + if item.try(:translation).respond_to? data_item.setter + entity = item.translation + else + entity = item + end + if image_path.blank? + item.instance_exec(&data_item.uploader.remove_proc) + else + if image_path.match /^http/ # is full path already + item.instance_exec(&data_item.uploader.remote_url_setter_proc(image_path)) + else + full_image_path = data_item.uploader.full_path_for(image_path) + data_item.set_data(entity, File.open(full_image_path)) + item.public_send(data_item.getter)&.store! + end + end + rescue + # rm_todo clear image + end + + def find_entities(data_item, ids) + if ids.kind_of? Array + ids = ids.map { |sub_ids| sub_ids.split(',') }.flatten.reject { |id| id.empty? } + related_entities(data_item, ids) + else + ids.empty? ? nil : data_item.relation.related_entities(ids) + end + end + + def simple_field_params + @params.require(:data).slice(*@model_info.data_items.save_form_fields) + end + + def related_entities(data_item, ids) + ids.map { |id| data_item.relation.related_entities(id) } + end + + end +end diff --git a/app/services/search/conditions/abstract.rb b/app/services/rademade_admin/search/conditions/abstract_conditions.rb similarity index 94% rename from app/services/search/conditions/abstract.rb rename to app/services/rademade_admin/search/conditions/abstract_conditions.rb index 1574c577..c79f4ac1 100644 --- a/app/services/search/conditions/abstract.rb +++ b/app/services/rademade_admin/search/conditions/abstract_conditions.rb @@ -2,7 +2,7 @@ module RademadeAdmin module Search module Conditions - class Abstract + class AbstractConditions attr_reader :params attr_writer :base_items @@ -48,7 +48,7 @@ def paginate if page.nil? || per_page.nil? nil else - [page, per_page] + [page.to_i, per_page.to_i] end end diff --git a/app/services/search/conditions/autocomplete.rb b/app/services/rademade_admin/search/conditions/autocomplete_conditions.rb similarity index 90% rename from app/services/search/conditions/autocomplete.rb rename to app/services/rademade_admin/search/conditions/autocomplete_conditions.rb index d38ab689..9d620eb7 100644 --- a/app/services/search/conditions/autocomplete.rb +++ b/app/services/rademade_admin/search/conditions/autocomplete_conditions.rb @@ -1,11 +1,8 @@ # -*- encoding : utf-8 -*- -require 'search/conditions/abstract' -require 'search/where' - module RademadeAdmin module Search module Conditions - class Autocomplete < Abstract + class AutocompleteConditions < AbstractConditions include RademadeAdmin::Search::Where diff --git a/app/services/search/conditions/list.rb b/app/services/rademade_admin/search/conditions/list_conditions.rb similarity index 92% rename from app/services/search/conditions/list.rb rename to app/services/rademade_admin/search/conditions/list_conditions.rb index bdd1f560..e901969a 100644 --- a/app/services/search/conditions/list.rb +++ b/app/services/rademade_admin/search/conditions/list_conditions.rb @@ -1,11 +1,8 @@ # -*- encoding : utf-8 -*- -require 'search/conditions/abstract' -require 'search/where' - module RademadeAdmin module Search module Conditions - class List < Abstract + class ListConditions < AbstractConditions include RademadeAdmin::Search::Where @@ -52,4 +49,4 @@ def search_by_fields end end end -end \ No newline at end of file +end diff --git a/app/services/search/part/abstract.rb b/app/services/rademade_admin/search/part/abstract.rb similarity index 100% rename from app/services/search/part/abstract.rb rename to app/services/rademade_admin/search/part/abstract.rb diff --git a/app/services/search/part/order.rb b/app/services/rademade_admin/search/part/order.rb similarity index 88% rename from app/services/search/part/order.rb rename to app/services/rademade_admin/search/part/order.rb index 34fa97ff..72147e29 100644 --- a/app/services/search/part/order.rb +++ b/app/services/rademade_admin/search/part/order.rb @@ -1,6 +1,4 @@ # -*- encoding : utf-8 -*- -require 'search/part/abstract' - module RademadeAdmin module Search module Part @@ -16,4 +14,4 @@ def part_object(field, value) end end end -end \ No newline at end of file +end diff --git a/app/services/search/part/where.rb b/app/services/rademade_admin/search/part/where.rb similarity index 88% rename from app/services/search/part/where.rb rename to app/services/rademade_admin/search/part/where.rb index 57c26704..f66d8afe 100644 --- a/app/services/search/part/where.rb +++ b/app/services/rademade_admin/search/part/where.rb @@ -1,6 +1,4 @@ # -*- encoding : utf-8 -*- -require 'search/part/abstract' - module RademadeAdmin module Search module Part diff --git a/lib/rademade_admin/search/searcher.rb b/app/services/rademade_admin/search/searcher.rb similarity index 100% rename from lib/rademade_admin/search/searcher.rb rename to app/services/rademade_admin/search/searcher.rb diff --git a/app/services/search/where.rb b/app/services/rademade_admin/search/where.rb similarity index 86% rename from app/services/search/where.rb rename to app/services/rademade_admin/search/where.rb index 5d0bac51..9f095ded 100644 --- a/app/services/search/where.rb +++ b/app/services/rademade_admin/search/where.rb @@ -8,7 +8,7 @@ def regex_filter(where_conditions, search) if search.present? and not @data_items.filter_fields.empty? query_where = RademadeAdmin::Search::Part::Where.new(:or) @data_items.filter_fields.each do |field| - query_where.add(field, /#{search}/i) + query_where.add(field, /#{Regexp.escape(search)}/i) end where_conditions.sub_add(query_where) end @@ -17,4 +17,4 @@ def regex_filter(where_conditions, search) end end -end \ No newline at end of file +end diff --git a/lib/rademade_admin/sortable.rb b/app/services/rademade_admin/sortable.rb similarity index 100% rename from lib/rademade_admin/sortable.rb rename to app/services/rademade_admin/sortable.rb diff --git a/app/services/sortable_service.rb b/app/services/rademade_admin/sortable_service.rb similarity index 100% rename from app/services/sortable_service.rb rename to app/services/rademade_admin/sortable_service.rb diff --git a/app/services/status/toggler.rb b/app/services/rademade_admin/status/toggler.rb similarity index 100% rename from app/services/status/toggler.rb rename to app/services/rademade_admin/status/toggler.rb diff --git a/app/services/template_service.rb b/app/services/rademade_admin/template_service.rb similarity index 100% rename from app/services/template_service.rb rename to app/services/rademade_admin/template_service.rb diff --git a/app/services/rademade_admin/upload/preview.rb b/app/services/rademade_admin/upload/preview.rb new file mode 100644 index 00000000..d7c07998 --- /dev/null +++ b/app/services/rademade_admin/upload/preview.rb @@ -0,0 +1,20 @@ +# -*- encoding : utf-8 -*- +module RademadeAdmin + module Upload + class Preview + + include ActionView::Helpers::TagHelper + include ActionView::Context + include UriHelper + + def image_data(uploader) + { + image_id: uploader.model.id.to_s, + full_url: uploader.url || '', + name: uploader.file.try(:filename) + } + end + + end + end +end diff --git a/app/services/upload/preview/file.rb b/app/services/rademade_admin/upload/preview/file_preview.rb similarity index 67% rename from app/services/upload/preview/file.rb rename to app/services/rademade_admin/upload/preview/file_preview.rb index 2af3be2f..99b09b7c 100644 --- a/app/services/upload/preview/file.rb +++ b/app/services/rademade_admin/upload/preview/file_preview.rb @@ -2,7 +2,7 @@ module RademadeAdmin module Upload class Preview - class File < RademadeAdmin::Upload::Preview + class FilePreview < RademadeAdmin::Upload::Preview include ActionView::Helpers::NumberHelper @@ -10,15 +10,17 @@ def initialize(uploader) @uploader = uploader end - def preview_html - content_tag(:div, uploaded_file_html, :data => { :preview_item => '' }) + def preview_html(options = {}) + content_tag(:div, uploaded_file_html(options), :data => { :preview_item => '' }) end - def uploaded_file_html + def uploaded_file_html(options = {}) if @uploader.blank? || @uploader.size.zero? '' else - content_tag(:div, HtmlBuffer.new([uploaded_preview_html, remove_ico_html])) + html_elements = [uploaded_preview_html] + html_elements << remove_ico_html if options[:destroyable] + content_tag(:div, HtmlBuffer.new(html_elements)) end end @@ -35,13 +37,17 @@ def crop? end def image_preview - @uploader.resize_with_crop(300, 300) + if image? + @uploader.resize_with_crop(300, 300) + else + @uploader.url + end end protected def uploaded_preview_html - if image? + if image? || @uploader.file.content_type.match(/image\//) image_preview_html elsif video? video_preview_html @@ -65,8 +71,9 @@ def video_preview_html def file_preview_html file_path = @uploader.path - file_name = "#{::File.basename(file_path)}, #{number_to_human_size(::File.size(file_path))}" - content_tag(:a, file_name, download_params) + file_name_parts = [::File.basename(file_path)] + file_name_parts << number_to_human_size(::File.size(file_path)) rescue nil + content_tag(:a, file_name_parts.join(', '), download_params) end def crop_url @@ -87,4 +94,4 @@ def remove_ico_html end end end -end \ No newline at end of file +end diff --git a/app/services/rademade_admin/upload/preview/gallery_preview.rb b/app/services/rademade_admin/upload/preview/gallery_preview.rb new file mode 100644 index 00000000..c72a4719 --- /dev/null +++ b/app/services/rademade_admin/upload/preview/gallery_preview.rb @@ -0,0 +1,46 @@ +# -*- encoding : utf-8 -*- +module RademadeAdmin + module Upload + class Preview + class GalleryPreview < RademadeAdmin::Upload::Preview + + def preview_html(uploader, options = { editable: true, destroyable: true }) + content_tag(:div, image_item_html(uploader, options), + class: 'upload-holder', + data: image_data(uploader) + ) + end + + def gallery_image_preview(uploader) + uploader.resize_with_crop(300, 300) + end + + private + + def image_item_html(uploader, options) + html_parts = [image_html(uploader)] + html_parts << remove_ico_html if options[:destroyable] + content_tag( + :div, + HtmlBuffer.new(html_parts), + class: 'upload-item' + ) + end + + def image_html(uploader) + content_tag(:img, '', src: gallery_image_preview(uploader)) + end + + def remove_ico_html + content_tag(:i, '', + class: 'upload-delete', + data: { + remove: '' + } + ) + end + + end + end + end +end diff --git a/lib/rademade_admin/uploader/carrier_wave.rb b/app/services/rademade_admin/uploader/carrier_wave.rb similarity index 93% rename from lib/rademade_admin/uploader/carrier_wave.rb rename to app/services/rademade_admin/uploader/carrier_wave.rb index 3ec8b849..c5e53ba3 100644 --- a/lib/rademade_admin/uploader/carrier_wave.rb +++ b/app/services/rademade_admin/uploader/carrier_wave.rb @@ -1,6 +1,4 @@ # encoding: utf-8 -require 'rademade_admin/uploader/crop_photo' - module RademadeAdmin module Uploader class CarrierWave < CarrierWave::Uploader::Base diff --git a/lib/rademade_admin/uploader/crop_photo.rb b/app/services/rademade_admin/uploader/crop_photo.rb similarity index 95% rename from lib/rademade_admin/uploader/crop_photo.rb rename to app/services/rademade_admin/uploader/crop_photo.rb index 9c1c8070..701ce11b 100644 --- a/lib/rademade_admin/uploader/crop_photo.rb +++ b/app/services/rademade_admin/uploader/crop_photo.rb @@ -1,6 +1,4 @@ # -*- encoding : utf-8 -*- -require 'rademade_admin/uploader/photo' - module RademadeAdmin module Uploader module CropPhoto diff --git a/lib/rademade_admin/uploader/photo.rb b/app/services/rademade_admin/uploader/photo.rb similarity index 100% rename from lib/rademade_admin/uploader/photo.rb rename to app/services/rademade_admin/uploader/photo.rb diff --git a/lib/rademade_admin/uploader/video.rb b/app/services/rademade_admin/uploader/video.rb similarity index 100% rename from lib/rademade_admin/uploader/video.rb rename to app/services/rademade_admin/uploader/video.rb diff --git a/lib/rademade_admin/user.rb b/app/services/rademade_admin/user_module.rb similarity index 100% rename from lib/rademade_admin/user.rb rename to app/services/rademade_admin/user_module.rb diff --git a/app/services/rademade_admin/user_password_token.rb b/app/services/rademade_admin/user_password_token.rb new file mode 100644 index 00000000..5100b0e5 --- /dev/null +++ b/app/services/rademade_admin/user_password_token.rb @@ -0,0 +1,58 @@ +require 'jwt' +module RademadeAdmin + + class UserPasswordToken + + class << self + + def encode(user, meta = {}) + @meta = meta + JWT.encode(encode_payload(user), secret(user)) + end + + def decode(token) + payload = decoded_payload(token) + raise Error.new('Invalid payload') unless valid_payload?(payload) + user = RademadeAdmin.configuration.admin_class.get_by_email(payload['email']) + JWT.decode(token, secret(user)) + user + end + + private + + def encode_payload(user) + { + email: user.email + }.reverse_merge!(meta) + end + + def decoded_payload(token) + JWT::Decode.new(token, nil).decode_segments[1] + end + + def secret(user) + "#{user.encrypted_password}#{Rails.application.secrets.secret_key_base}" + end + + def valid_payload?(payload) + !expired?(payload) && payload['email'] + end + + def meta + { + exp: 30.minutes.from_now.to_i, + iss: 'Rademade admin user', + iat: Time.now, + aud: 'admin user' + }.merge(@meta) + end + + def expired?(payload) + Time.at(payload['exp']).past? + end + + end + end + +end + diff --git a/app/services/video_service.rb b/app/services/rademade_admin/video_service.rb similarity index 100% rename from app/services/video_service.rb rename to app/services/rademade_admin/video_service.rb diff --git a/app/services/saver.rb b/app/services/saver.rb deleted file mode 100644 index 21b1f917..00000000 --- a/app/services/saver.rb +++ /dev/null @@ -1,110 +0,0 @@ -# -*- encoding : utf-8 -*- -module RademadeAdmin - class Saver - - attr_reader :item - - # Initialization of model saver class - # - # @param model_info [RademadeAdmin::Model::Info] - # @param params [Hash] - # - def initialize(model_info, params) - @model_info, @params = model_info, params - end - - def create_model - @item = @model_info.persistence_adapter.new_record - end - - def find_model - @item = @model_info.query_adapter.find(@params[:id]) - end - - def set_data - save_simple_fields - save_localizable_fields - save_model_relations - save_model_uploads - end - - def save_item - @model_info.persistence_adapter.save(item) - end - - private - - def save_simple_fields - simple_field_params.each do |field, value| - item.send(:"#{field}=", value) - end - end - - def save_localizable_fields - current_locale = I18n.locale - @model_info.data_items.localizable_fields.each do |_, data_item| - values = @params[:data].try(:[], data_item.name) - values.each do |locale, value| - I18n.locale = locale - if data_item.has_uploader? - save_model_upload(data_item, value) - else - data_item.set_data(item, value) - end - end if values - end - I18n.locale = current_locale - end - - def save_model_relations - data = @params[:data] - @model_info.data_items.related_fields.each do |_, data_item| - if data.has_key? data_item.name - data_item.set_data(item, find_entities(data_item, data[data_item.name])) - end - end - end - - def save_model_uploads - data = @params[:data] - @model_info.data_items.uploader_fields.each do |_, data_item| - name = data_item.name - save_model_upload(data_item, data[name]) if data.has_key?(name) - end - end - - def save_model_upload(data_item, image_path) - if item.try(:translation).respond_to? data_item.setter - entity = item.translation - else - entity = item - end - if image_path.blank? - item.instance_exec(&data_item.uploader.remove_proc) - else - full_image_path = data_item.uploader.full_path_for(image_path) - data_item.set_data(entity, File.open(full_image_path)) - end - rescue - # rm_todo clear image - end - - def find_entities(data_item, ids) - if ids.kind_of? Array - ids.reject! { |id| id.empty? } - related_entities(data_item, ids) - else - ids.empty? ? nil : data_item.relation.related_entities(ids) - end - end - - def simple_field_params - @params.require(:data).symbolize_keys.slice(*@model_info.data_items.save_form_fields) - end - - def related_entities(data_item, ids) - ids.map { |id| data_item.relation.related_entities(id) } - end - - end -end \ No newline at end of file diff --git a/app/services/upload/image_presenter.rb b/app/services/upload/image_presenter.rb deleted file mode 100644 index e6377a7c..00000000 --- a/app/services/upload/image_presenter.rb +++ /dev/null @@ -1,38 +0,0 @@ -# -*- encoding : utf-8 -*- -module RademadeAdmin - module Upload - class ImagePresenter - - attr_reader :gallery_images, :gallery_images_html - - def initialize(gallery_image_persistence_adapter) - @gallery_image_persistence_adapter = gallery_image_persistence_adapter - end - - def upload_gallery_images(images) - @gallery_images = [] - @gallery_images_html = [] - images.each { |image| add_gallery_image upload_gallery_image(image) } - end - - protected - - def upload_gallery_image(image) - gallery_image = @gallery_image_persistence_adapter.new_record - @gallery_image_persistence_adapter.save(gallery_image) - gallery_image.image.store! image - gallery_image - end - - def add_gallery_image(gallery_image) - @gallery_images << gallery_image - @gallery_images_html << preview_service.preview_html(gallery_image.image) - end - - def preview_service - @preview_service ||= RademadeAdmin::Upload::Preview::Gallery.new - end - - end - end -end \ No newline at end of file diff --git a/app/services/upload/preview.rb b/app/services/upload/preview.rb deleted file mode 100644 index e12ad36d..00000000 --- a/app/services/upload/preview.rb +++ /dev/null @@ -1,35 +0,0 @@ -# -*- encoding : utf-8 -*- -module RademadeAdmin - module Upload - class Preview - - include ActionView::Helpers::TagHelper - include ActionView::Context - include UriHelper - - def image_data(uploader) - data = { - :image_id => uploader.model.id.to_s, - :full_url => uploader.url, - :name => uploader.file.try(:filename) - } - data[:crop] = crop_data(uploader) if uploader.class.ancestors.include? RademadeAdmin::Uploader::CropPhoto - data - end - - def crop_data(uploader) - { - :url => crop_url, - :original_dimensions => uploader.original_dimensions.join(',') - } - end - - protected - - def crop_url - nil - end - - end - end -end \ No newline at end of file diff --git a/app/services/upload/preview/gallery.rb b/app/services/upload/preview/gallery.rb deleted file mode 100644 index 789788be..00000000 --- a/app/services/upload/preview/gallery.rb +++ /dev/null @@ -1,55 +0,0 @@ -# -*- encoding : utf-8 -*- -module RademadeAdmin - module Upload - class Preview - class Gallery < RademadeAdmin::Upload::Preview - - def preview_html(uploader) - content_tag(:div, image_item_html(uploader), - :class => 'upload-holder', - :data => image_data(uploader) - ) - end - - def gallery_image_preview(uploader) - uploader.resize_with_crop(300, 300) - end - - protected - - def crop_url - rademade_admin_route(:gallery_crop_url) - end - - private - - def image_item_html(uploader) - content_tag( - :div, - HtmlBuffer.new([image_html(uploader), remove_ico_html(uploader)]), - :class => 'upload-item' - ) - end - - def image_html(uploader) - content_tag(:img, '', :src => gallery_image_preview(uploader)) - end - - def remove_ico_html(uploader) - content_tag(:i, '', - :class => 'upload-delete', - :data => { - #todo use route name and resources - :remove_url => admin_url_for({ - :controller => 'rademade_admin/gallery', - :action => 'remove', - :id => uploader.model.id.to_s - }) - } - ) - end - - end - end - end -end \ No newline at end of file diff --git a/app/views/layouts/rademade_admin/mailer.html.erb b/app/views/layouts/rademade_admin/mailer.html.erb new file mode 100644 index 00000000..cbd34d2e --- /dev/null +++ b/app/views/layouts/rademade_admin/mailer.html.erb @@ -0,0 +1,13 @@ + + + + + + + + + <%= yield %> + + diff --git a/app/views/rademade_admin/_blocks/_form.html.erb b/app/views/rademade_admin/_blocks/_form.html.erb index 10add560..e1667c45 100644 --- a/app/views/rademade_admin/_blocks/_form.html.erb +++ b/app/views/rademade_admin/_blocks/_form.html.erb @@ -1,8 +1,12 @@ <% -concat render :template => @template_service.content_item_layout, :locals => { - :content_header => @model_info.item_name, - :content_url => admin_list_uri(@model_info) -} if @with_layout %> +if @with_layout && !@without_index_tab + content_url = admin_list_uri(@model_info) + concat render :template => @template_service.content_item_layout, :locals => { + :content_header => @model_info.item_name, + :content_url => content_url + } if content_url +end +%> <% content_for :content do %><% buttons_template ||= @template_service.form_control_block @@ -16,7 +20,7 @@ concat render :template => @template_service.content_item_layout, :locals => { concat render @template_service.form_lang_panel_block, :f => form %> <% - if !defined?(show_buttons) || show_buttons + if (!defined?(show_buttons) || show_buttons) && !@without_buttons %>
<% concat render buttons_template, :f => form @@ -29,8 +33,11 @@ end if @model_info.persistence_adapter.new?(@item) content_header = t('rademade_admin.title.new_record', :model => @model_info.item_name) else - content_header = t('rademade_admin.title.edit_record', :model => @model_info.item_name, :record => @item) + content_header = t('rademade_admin.title.edit_record', { + :model => @model_info.item_name, + :record => @model_info.title_of(@item) + }) end concat render :template => @template_service.content_item_layout, :locals => { :content_header => content_header -} %> \ No newline at end of file +} %> diff --git a/app/views/rademade_admin/_blocks/_list.html.erb b/app/views/rademade_admin/_blocks/_list.html.erb index f897f715..c1313278 100644 --- a/app/views/rademade_admin/_blocks/_list.html.erb +++ b/app/views/rademade_admin/_blocks/_list.html.erb @@ -1,6 +1,6 @@ <% content_for :nav_buttons do %><% new_uri = admin_new_uri(@model_info) - if new_uri + if new_uri && can?(:create, @model_info.model) %><% concat t('rademade_admin.record.new') %><% @@ -30,4 +30,4 @@ end concat render :template => @template_service.content_item_layout, :locals => { :content_header => @model_info.item_name -} %> \ No newline at end of file +} %> diff --git a/app/views/rademade_admin/_blocks/_navigation.html.erb b/app/views/rademade_admin/_blocks/_navigation.html.erb index 8bc5295c..5a77bb3f 100644 --- a/app/views/rademade_admin/_blocks/_navigation.html.erb +++ b/app/views/rademade_admin/_blocks/_navigation.html.erb @@ -1,4 +1,6 @@ -