diff --git a/Gemfile b/Gemfile index ff991b5..8132d77 100644 --- a/Gemfile +++ b/Gemfile @@ -34,7 +34,7 @@ gem 'mongoid', github: "mongoid/mongoid" gem "mini_magick", "3.5.0" gem 'carrierwave' gem 'carrierwave-mongoid', :require => 'carrierwave/mongoid' - +gem 'zip-zip' gem 'kaminari' gem "impressionist" gem "chartkick" diff --git a/app/assets/images/license-denied.png b/app/assets/images/license-denied.png new file mode 100644 index 0000000..2641519 Binary files /dev/null and b/app/assets/images/license-denied.png differ diff --git a/app/assets/javascripts/frontend.js b/app/assets/javascripts/frontend.js index fa2e95a..c717991 100644 --- a/app/assets/javascripts/frontend.js +++ b/app/assets/javascripts/frontend.js @@ -1,8 +1,16 @@ (function($) { - $("document").ready(function(){ + $("document").ready(function(){ // Get link data-attribute and make the banner clickable - $('.w-ad-banner__slide').not('[data-link=""]').not(".youtube").addClass('cursor').on("click",function(){ - window.open($(this).data("link"),"_blank"); + $('.w-ad-banner__slide') + .not('[data-link=""]') + .not(".youtube") + .addClass('cursor') + .on("click",function(){ + if( $(this).data('target') === '_blank' ) { + window.open($(this).data("link"), "_blank"); + } else { + window.location.href = ($(this).data("link")); + } }) }) }(jQuery)); \ No newline at end of file diff --git a/app/assets/javascripts/validator.js b/app/assets/javascripts/validator.js index 847a6d4..435d4d7 100644 --- a/app/assets/javascripts/validator.js +++ b/app/assets/javascripts/validator.js @@ -25,6 +25,9 @@ var FormValidator = function(form){ nospace : function(value){ return (/\s/.test(value) ? false : true); }, + lowercase : function(value){ + return (value == value.toLowerCase() ? true : false); + }, email : function(value){ var re = /^(([^<>()[\]\\.,;:\s@\"]+(\.[^<>()[\]\\.,;:\s@\"]+)*)|(\".+\"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/; return re.test(value); @@ -40,35 +43,39 @@ var FormValidator = function(form){ var _attachSubmitHandler = function(){ fv.form.on("submit",function(){ - failed_elements = []; - $.each(elements_data,function(key,element){ - var validators = element.validators, - messages = element.messages, - el = fv.form.find("#" + key); - for(i = 0; i < validators.length; i++){ - var error_span = (fv.form.find("div[for=" + key + "]").length ? $("div[for=" + key + "]") : $("
")); - if(typeof fv.validate_functions[validators[i]] == "function"){ - if(!fv.validate_functions[validators[i]](el.val(),el)){ - error_span.text(messages[i]); - el.after(error_span); - failed_elements.push(el); - break; - }else{ - error_span.remove(); - } + return fv.isFormValidated(); + }) + } + + this.isFormValidated = function(){ + failed_elements = []; + $.each(elements_data,function(key,element){ + var validators = element.validators, + messages = element.messages, + el = fv.form.find("#" + key); + for(i = 0; i < validators.length; i++){ + var error_span = (fv.form.find("div[for=" + key + "]").length ? $("div[for=" + key + "]") : $("")); + if(typeof fv.validate_functions[validators[i]] == "function"){ + if(!fv.validate_functions[validators[i]](el.val(),el)){ + error_span.text(messages[i]); + el.after(error_span); + failed_elements.push(el); + break; }else{ - console.info("Not validating for " + validators[i] + ". Skipping."); + error_span.remove(); } + }else{ + console.info("Not validating for " + validators[i] + ". Skipping."); } - }) - if(failed_elements.length){ - var offset = failed_elements[0].offset().top - fv.form.offset().top + fv.form.scrollTop(); - fv.form.parent().animate({scrollTop:offset-50}, '300', 'swing'); - return false; - }else{ - return true; } }) + if(failed_elements.length){ + var offset = failed_elements[0].offset().top - fv.form.offset().top + fv.form.scrollTop(); + fv.form.parent().animate({scrollTop:offset-50}, '300', 'swing'); + return false; + }else{ + return true; + } } var _putFieldsValidatorAndMessage = function(){ diff --git a/app/assets/stylesheets/basic/global.css b/app/assets/stylesheets/basic/global.css index 3f05c30..c22a181 100644 --- a/app/assets/stylesheets/basic/global.css +++ b/app/assets/stylesheets/basic/global.css @@ -122,6 +122,20 @@ legend { text-align: center; list-style: none; } +#sidebar .sidebar-nav .license-denied { + cursor: not-allowed; +} +#sidebar .sidebar-nav .license-denied > span { + position: relative; + width: 60px; +} +#sidebar .sidebar-nav .license-denied > span:before { + position: absolute; + top: 10px; + left: 12px; + font-size: 3.1em; + color: rgba(205, 10, 10, 0.46); +} #sidebar > h2.position { margin: 0; width: 61px; @@ -188,6 +202,7 @@ legend { } #sidebar .sidebar-nav > li a { display: block; + text-decoration: none; } #sidebar .sidebar-nav > li i { font-size: 1.6em; diff --git a/app/assets/stylesheets/lib/orbit_bar/orbit-bar.scss.erb b/app/assets/stylesheets/lib/orbit_bar/orbit-bar.scss.erb index 8b60f83..4d74081 100644 --- a/app/assets/stylesheets/lib/orbit_bar/orbit-bar.scss.erb +++ b/app/assets/stylesheets/lib/orbit_bar/orbit-bar.scss.erb @@ -318,7 +318,7 @@ $orbit-bar-bgc-lighter: lighten($orbit-bar-bgc, 20%) !default; display: none; top: 0; margin: 0 2em; - padding: 0.3em 0; + padding: 0; color: #FFF; font-size: 1.4em; text-align: center; @@ -328,6 +328,9 @@ $orbit-bar-bgc-lighter: lighten($orbit-bar-bgc, 20%) !default; a { color: #FFF; } + .page-main & { + padding: 0.3em 0; + } } .orbit-bar-search-sign-language { float: right; @@ -339,6 +342,7 @@ $orbit-bar-bgc-lighter: lighten($orbit-bar-bgc, 20%) !default; input[type="search"] { color: $orbit-bar-bgc-lighter; border: none; + margin-bottom: 0; border-radius: 1.7em; line-height: 1.3em; padding: 0.2em 0.8em; diff --git a/app/controllers/admin/module_store_controller.rb b/app/controllers/admin/module_store_controller.rb index c6ac85f..7385bbd 100644 --- a/app/controllers/admin/module_store_controller.rb +++ b/app/controllers/admin/module_store_controller.rb @@ -3,7 +3,7 @@ class Admin::ModuleStoreController < OrbitAdminController def index @extensions = [] - @downloaded_extensions = get_downloaded_extension + @downloaded_extensions = [] # if current_site.site_token? # if current_site.store_confirmation # @extensions = get_extensions diff --git a/app/controllers/admin/sites_controller.rb b/app/controllers/admin/sites_controller.rb index 87175db..acb8485 100644 --- a/app/controllers/admin/sites_controller.rb +++ b/app/controllers/admin/sites_controller.rb @@ -106,7 +106,9 @@ class Admin::SitesController < OrbitAdminController else result = "success" # Bundler.with_clean_env { `cd #{Rails.root} && bundle update` } - Bundler.with_clean_env { `cd #{Rails.root} && BUNDLE_GEMFILE=built_in_extensions.rb bundle update && bundle` } + Bundler.with_clean_env { `cd #{Rails.root} && BUNDLE_GEMFILE=built_in_extensions.rb bundle update && bundle` } + Bundler.with_clean_env { `cd #{Rails.root} && BUNDLE_GEMFILE=downloaded_extensions.rb bundle update && bundle` } + end render :text => result @@ -117,6 +119,7 @@ class Admin::SitesController < OrbitAdminController def bundle_install Bundler.with_clean_env { `cd #{Rails.root} && BUNDLE_GEMFILE=built_in_extensions.rb bundle update && bundle` } + Bundler.with_clean_env { `cd #{Rails.root} && BUNDLE_GEMFILE=downloaded_extensions.rb bundle update && bundle` } %x(kill -s USR2 `cat tmp/pids/unicorn.pid`) sleep 5 render :nothing => true diff --git a/app/controllers/members_controller.rb b/app/controllers/members_controller.rb index 13cb49d..aba6008 100644 --- a/app/controllers/members_controller.rb +++ b/app/controllers/members_controller.rb @@ -139,29 +139,44 @@ class MembersController < ApplicationController plugins = OrbitApp::Plugin::Registration.all rescue nil plugin_list = plugins.collect.with_index do |plugin, idx| intro = PersonalPluginIntro.find_by(member_profile_id: member.id, _type: "#{plugin.app_name}Intro") rescue nil - if intro.nil? or intro.complete_list - plugin_data = plugin.app_name.constantize.where(member_profile_id: member) rescue nil - pd = plugin_data.collect do |p| - slug_title = ["JournalPaper","WritingConference"].include?(plugin.app_name) ? p.create_link : p.slug_title - { - "data_title" => slug_title, - "link_to_show" => OrbitHelper.url_to_plugin_show(p.to_param,plugin.module_app_name.underscore) - } + if !intro.blank? + if !intro.complete_list.blank? + plugin_data = plugin.app_name.constantize.where(member_profile_id: member) rescue nil + pd = plugin_data.collect do |p| + slug_title = ["JournalPaper","WritingConference"].include?(plugin.app_name) ? p.create_link : p.slug_title + { + "data_title" => slug_title, + "link_to_show" => OrbitHelper.url_to_plugin_show(p.to_param,plugin.module_app_name.underscore) + } + end end - elsif intro.brief_intro == true - pd = [] - pd << {"data_title" => intro.text.html_safe} - end - { + if !intro.brief_intro.blank? + pdi = [] + pdi << {"data_intro_title" => intro.text.html_safe} + end + + if intro.complete_list.blank? + complete_display = "hide" + end + + if intro.brief_intro.blank? + brief_display = "hide" + end + end + + { "plugin_data" => pd, + "plugin_data_intro" => pdi, + "complete_display" => complete_display, + "brief_display" => brief_display, "plugin_name" => plugin.module_app_name.underscore, "plugin_title" => t('module_name.'+plugin.module_app_name.underscore), "plugin_class" => idx==0 ? "active" : "" - } + } end - plugin_list = plugin_list.reject{|plugin| plugin['plugin_data'].blank?} + plugin_list = plugin_list.reject{|plugin| plugin['plugin_data'].blank? and plugin['plugin_data_intro'].blank?} { "plugins" => plugin_list, "profile_data" => profile_data, @@ -175,7 +190,6 @@ class MembersController < ApplicationController def member_data(member, fields_to_show) profile_data = [] fields_to_show.each do |field| - # debugger case field['type'] when 'profile' field_data = member.get_attribute_data(field) rescue {} diff --git a/app/controllers/pages_controller.rb b/app/controllers/pages_controller.rb index b243590..7bda6bf 100644 --- a/app/controllers/pages_controller.rb +++ b/app/controllers/pages_controller.rb @@ -11,7 +11,7 @@ class PagesController < ApplicationController before_filter :set_edit_mode def index - @pages = Page.all + @pages = Page.all # render json: @pages end @@ -76,10 +76,14 @@ class PagesController < ApplicationController params[:url] = page.url categories = [] if page.module == "member" - page.categories.each do |c| - category = Role.find(c) rescue nil - if !category.nil? && !category.disabled - categories << c + if page.categories.first == "all" + categories = ["all"] + else + page.categories.each do |c| + category = Role.find(c) rescue nil + if !category.nil? && !category.disabled + categories << c + end end end else @@ -89,8 +93,8 @@ class PagesController < ApplicationController categories << c end end + categories = ["all"] if categories.blank? end - categories = ["all"] if categories.blank? @manifest = @key OrbitHelper.set_params params,current_user OrbitHelper.set_site_locale locale @@ -186,30 +190,38 @@ class PagesController < ApplicationController "id" => cat.id.to_s } end + tags = module_app.tags.collect do |t| + { + "name" => t.name, + "id" => t.id.to_s + } + end else categories = [] + tags = [] end end roles = roles.nil? ? [] : roles categories = categories.nil? ? [] : categories + tags = tags.nil? ? [] : tags if module_app.data_count.nil? - render :json => {"categories" => categories, "tags" => module_app.tags,"roles" => roles,"layouts" => (get_layouts module_app.key),"data_count" => {"present"=>false}, "locale" => I18n.locale.to_s}.to_json + render :json => {"categories" => categories, "tags" => tags,"roles" => roles,"layouts" => (get_layouts module_app.key),"data_count" => {"present"=>false}, "locale" => I18n.locale.to_s}.to_json else - render :json => {"categories" => categories, "tags" => module_app.tags,"roles" => roles,"layouts" => (get_layouts module_app.key),"data_count" => {"present"=>true,"start"=>module_app.data_count.begin, "end" => module_app.data_count.end}, "locale" => I18n.locale.to_s}.to_json + render :json => {"categories" => categories, "tags" => tags,"roles" => roles,"layouts" => (get_layouts module_app.key),"data_count" => {"present"=>true,"start"=>module_app.data_count.begin, "end" => module_app.data_count.end}, "locale" => I18n.locale.to_s}.to_json end end def new - @page = Page.new( + @page = Page.new( :enabled_for_mobile=>true, :menu_enabled_for=>["en", "zh_tw"], :enabled_for=>["en", "zh_tw"], :enabled_for_sitemap=>["en", "zh_tw"] ) - @pages = Page.where(:page_id.ne => "" , :page_id.exists => true) - @modules = ModuleApp.all.frontend_enabled.order_by(:key=>'asc') + @pages = Page.where(:page_id.ne => "" , :page_id.exists => true) + @modules = ModuleApp.all.frontend_enabled.order_by(:key=>'asc') end @@ -260,7 +272,7 @@ class PagesController < ApplicationController end end - private + private def get_layouts(module_app) layout_types = [] @@ -432,6 +444,7 @@ class PagesController < ApplicationController p = params.require(:page).permit(:number, :page_type, :page_id, :module, :layout, :parent_page, :data_count, :enabled_for_mobile, :member_sort_position, enabled_for_sitemap: [], enabled_for: [],menu_enabled_for: [], categories: [], tags: [], role_status: [], name_translations: valid_locales, external_url_translations: valid_locales) p["role_status"] = p["role_status"] || [] p["categories"] = p["categories"] || [] + p["tags"] = p["tags"] || [] p["enabled_for"] = p["enabled_for"] || [] p["menu_enabled_for"] = p["menu_enabled_for"] || [] p["enabled_for_sitemap"] = p["enabled_for_sitemap"] || [] diff --git a/app/controllers/store_api_controller.rb b/app/controllers/store_api_controller.rb index 50eb645..4bd74e8 100644 --- a/app/controllers/store_api_controller.rb +++ b/app/controllers/store_api_controller.rb @@ -1,3 +1,6 @@ +require "net/http" +require 'open-uri' +require 'zip/zip' class StoreApiController < ApplicationController def confirmation site_token = params[:site_token] @@ -11,4 +14,80 @@ class StoreApiController < ApplicationController render :json => {"success" => false}.to_json end end + + def install_module + if current_site.store_token.nil? + response = {"success" => false} + elsif current_site.store_token == params[:site_token] + file = File.join(Rails.root,"downloaded_extensions.rb") + g = "gem '#{params[:module_key]}', git: '#{params[:git_path]}'" + File.open(file,"a+") { |f| f.puts(g) } + if !directory_exists?(File.join(Rails.root,"app","templates","#{Site.first.template}","modules","#{params[:module_key]}")) + download_template(params[:template],params[:template_filename]) + end + response = {"success" => true} + else + response = {"success" => false} + end + render :json => response.to_json + if response["success"] + bundle_install + # give_permissions(params[:module_key]) + end + end + + def uninstall_module + file = File.join(Rails.root,"downloaded_extensions.rb") + data = File.read(file) + g = "gem '#{params[:module_key]}', git: '#{params[:git_path]}'\n" + data = data.gsub(g,"") + File.write(file,data) + bundle_install + render :json => {"success" => true}.to_json + end + + def render_license_denied + render :layout => "back_end" + end + + private + def bundle_install + Bundler.with_clean_env { `cd #{Rails.root} && BUNDLE_GEMFILE=downloaded_extensions.rb bundle update && bundle` } + %x(kill -s USR2 `cat tmp/pids/unicorn.pid`) + sleep 5 + end + + def restart_server_after_install + %x(kill -s USR2 `cat tmp/pids/unicorn.pid`) + sleep 5 + end + + + def download_template(url,name) + dir = File.join(Rails.root,"public","template_cache") + destination = File.join(Rails.root,"app","templates","#{Site.first.template}","modules") + if !directory_exists?(dir) + Dir.mkdir dir + end + zipfile = File.join(Rails.root, "public" , "template_cache", name) + open(zipfile, 'wb') do |fo| + fo.print open(url).read + end + unzip_file(zipfile,destination) + end + + def directory_exists?(directory) + File.directory?(directory) + end + + def unzip_file (file, destination) + Zip::ZipFile.open(file) { |zip_file| + zip_file.each { |f| + f_path=File.join(destination, f.name) + FileUtils.mkdir_p(File.dirname(f_path)) + zip_file.extract(f, f_path) unless File.exist?(f_path) + } + } + FileUtils.rm_rf(File.join(Rails.root,"public","template_cache")) + end end \ No newline at end of file diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb index a794839..2c071be 100644 --- a/app/helpers/application_helper.rb +++ b/app/helpers/application_helper.rb @@ -64,6 +64,8 @@ module ApplicationHelper end site_footer = site_footer.nil? ? "" : site_footer html = html.gsub("{{footer-data}}",site_footer) + counter = Page.root.view_count.to_s rescue "" + html = html.gsub("{{site-counter}}",counter) html.html_safe end diff --git a/app/helpers/orbit_backend_helper.rb b/app/helpers/orbit_backend_helper.rb index 73734d2..25eb17a 100644 --- a/app/helpers/orbit_backend_helper.rb +++ b/app/helpers/orbit_backend_helper.rb @@ -172,8 +172,15 @@ module OrbitBackendHelper http = Net::HTTP.new(uri.host,uri.port) request = Net::HTTP::Get.new("/site/permissions") request.body = params_to_send.to_query - response = http.request(request) - data = JSON.parse(response.body) + response = http.request(request) rescue nil + if response.nil? + data = {} + data["message"] = "Could not connect to the store." + data["error"] = "CONNECTION_REFUSED" + data["success"] = false + else + data = JSON.parse(response.body) + end if !data["success"] case data["error"] when "INVALID_SITE_TOKEN" diff --git a/app/models/module_app.rb b/app/models/module_app.rb index cd1d4a1..efee743 100644 --- a/app/models/module_app.rb +++ b/app/models/module_app.rb @@ -14,6 +14,7 @@ class ModuleApp field :widget_methods field :desktop_enabled, type: Boolean, default: false field :widget_settings + field :store_permission_granted, type: Boolean, default: false has_many :categories, dependent: :destroy, :autosave => true has_and_belongs_to_many :tags, dependent: :destroy, :autosave => true diff --git a/app/models/orbit_store.rb b/app/models/orbit_store.rb index 9c9b64f..1217dc2 100644 --- a/app/models/orbit_store.rb +++ b/app/models/orbit_store.rb @@ -1,3 +1,4 @@ class OrbitStore URL = "http://store.tp.rulingcom.com" + MODULE_EXCEPTIONS = ["category","tag","authorization"] end \ No newline at end of file diff --git a/app/templates/orbit_bootstrap/assets/javascripts/app.js b/app/templates/orbit_bootstrap/assets/javascripts/app.js index a9dd1ed..276189f 100644 --- a/app/templates/orbit_bootstrap/assets/javascripts/app.js +++ b/app/templates/orbit_bootstrap/assets/javascripts/app.js @@ -1,110 +1,106 @@ (function($) { "use strict" - - // Init functions + function init () { - // Announcement modules - var annc = { - truncation : function (el, maxLength) { + var doc = document; + + var orbit = { + // Cross browser add class function + addClass : function(el, className) { + if( el.classList ) { + el.classList.add(className); + } else { + el.className += ' ' + className; + } + }, + // Cross browser has class function + hasClass : function(el, cls) { + return (' ' + el.className + ' ').indexOf(' ' + cls + ' ') > -1; + }, + // Add class name to the menu item when its children items are more than eight + addMegaDropdownClass : function(el, len) { + for( var i = 0; i < el.length; i++ ) { + if( el[i].children.length > len ) { + orbit.addClass(el[i].parentNode, 'mega-dropdown'); + } + } + }, + // Append caret to menu item if it has dropdown + addCaret : function() { + var list = doc.querySelectorAll('.page_menu.level_2'); + for( var i = 0, len = list.length; i < len; i++ ) { + var node = doc.createElement('span'); + node.className = 'caret'; + list[i].parentNode.appendChild(node); + } + }, + // Add link and cursor class name on element that has data-link attribute + addLinkOnADBanner : function(els) { + $.each(els, function(i) { + if ($(this).data('link') !== "" && !$(this).hasClass('youtube')) { + $(this).on('click', function() { + var target = $(this).data('target'), + link = $(this).data('link'); + if (target === '_blank') { + window.open(link, target); + } else { + window.location.href = link; + } + }).addClass('cursor'); + } + }); + }, + // Announcement text truncation + truncation : function (el, len) { for( var i = 0; i < el.length; i ++ ) { if ( el[i].firstChild !== null ) { - if( el[i].firstChild.length > maxLength ) { - var newTitle = el[i].firstChild.nodeValue; - var newTitle = newTitle.substring(0, maxLength) + '...' + if( el[i].firstChild.length > len ) { + var newStr = el[i].firstChild.nodeValue, + newStr = newStr.substring(0, len) + '...' el .eq(i) - .text(newTitle); + .text(newStr); } } } - } - } + }, + // Sitemenu dropdown + sitemenuDropdown : function() { + var el = doc.querySelectorAll('.sitemenu__list.level-2'); + for( var i = 0, len = el.length; i < len; i++ ) { + if( el[i].hasChildNodes() ) { + var caret = doc.createElement('span'); + caret.className = 'sitemenu___dropdown-toggle fa fa-caret-down'; + caret.setAttribute('data-toggle', 'dropdown'); - function anncFix() { - var w$ = $('.w-announcement-4'); - if( w$.length ) { - annc.truncation(w$.find('.w-annc__subtitle'), 25); - } - } - - // Necessary for Responsive images - function bullEye() { - // $(".bullseye").bullseye({ - // fadeEffect: false - // }); - } - - // Adding class to submenu that has dropdown items - function submenuFix () { - var item$ = $('.submenu__item.level-1'); - var itemLen = item$.length; - var list$ = item$.find('.submenu__list.level-2'); - - for( var i=0; i