├── .gitignore ├── MIT-LICENSE ├── README.md ├── Rakefile ├── backend ├── Gemfile ├── Rakefile ├── app │ ├── admin │ │ ├── admin_user.rb │ │ ├── api_token.rb │ │ ├── blogs.rb │ │ ├── cloudflares.rb │ │ ├── dashboard.rb │ │ ├── domains.rb │ │ ├── locales.rb │ │ ├── monitor.rb │ │ ├── permissions.rb │ │ ├── proxy.rb │ │ ├── servers.rb │ │ ├── settings.rb │ │ └── templates.rb │ ├── assets │ │ ├── images │ │ │ ├── icons │ │ │ │ ├── arrows.svg │ │ │ │ └── interface.svg │ │ │ └── wordpress │ │ │ │ ├── favicon.ico │ │ │ │ └── logo.png │ │ ├── javascripts │ │ │ └── active_admin │ │ │ │ ├── amz.js │ │ │ │ └── components │ │ │ │ └── copy_text.js │ │ └── stylesheets │ │ │ └── active_admin │ │ │ ├── _amz.scss │ │ │ └── components │ │ │ ├── _status_tags.scss │ │ │ └── _table.scss │ ├── models │ │ ├── admin_user_decorator.rb │ │ ├── api_token.rb │ │ ├── blog.rb │ │ ├── cloudflare.rb │ │ ├── domain.rb │ │ ├── locale.rb │ │ ├── monitor.rb │ │ ├── proxy.rb │ │ ├── server.rb │ │ ├── tag.rb │ │ ├── tags_blog.rb │ │ └── template.rb │ └── views │ │ └── admin │ │ ├── blogs │ │ ├── install.html.arb │ │ ├── login.html.erb │ │ └── migration.html.erb │ │ ├── import.html.erb │ │ └── proxies │ │ └── upload.html.arb ├── config │ └── locales │ │ └── en.yml ├── lib │ ├── active_admin_import.rb │ ├── active_admin_import │ │ ├── authorization.rb │ │ ├── dsl.rb │ │ ├── import_result.rb │ │ ├── importer.rb │ │ ├── model.rb │ │ ├── options.rb │ │ └── version.rb │ ├── wordpress │ │ ├── backend.rb │ │ └── backend │ │ │ ├── authorization.rb │ │ │ ├── batch │ │ │ └── dsl.rb │ │ │ ├── controller │ │ │ └── active_admin_base.rb │ │ │ ├── engine.rb │ │ │ ├── paranoia │ │ │ ├── authorization.rb │ │ │ ├── core.rb │ │ │ └── dsl.rb │ │ │ └── state_machine │ │ │ └── dsl.rb │ └── wordpress_backend.rb ├── test │ ├── backend_test.rb │ └── test_helper.rb └── wordpress_backend.gemspec ├── core ├── Gemfile ├── Gemfile.lock ├── Rakefile ├── app │ ├── controllers │ │ └── wordpress │ │ │ ├── api_controller.rb │ │ │ ├── base_controller.rb │ │ │ ├── home_controller.rb │ │ │ └── server_controller.rb │ ├── helpers │ │ └── wordpress │ │ │ └── base_helper.rb │ ├── jobs │ │ └── wordpress │ │ │ ├── blog_check_online_job.rb │ │ │ ├── blog_install_job.rb │ │ │ ├── blog_job.rb │ │ │ ├── blog_reset_password_job.rb │ │ │ ├── domain_import_job.rb │ │ │ ├── domain_job.rb │ │ │ ├── proxy_check_job.rb │ │ │ ├── proxy_install_job.rb │ │ │ ├── server_job.rb │ │ │ ├── template_install_job.rb │ │ │ ├── template_job.rb │ │ │ ├── template_reset_password_job.rb │ │ │ └── template_tar_job.rb │ ├── models │ │ ├── concerns │ │ │ └── wordpress │ │ │ │ ├── number_generator.rb │ │ │ │ ├── routeable.rb │ │ │ │ └── validates.rb │ │ └── wordpress │ │ │ ├── api_token.rb │ │ │ ├── app_configuration.rb │ │ │ ├── auth_configuration.rb │ │ │ ├── base.rb │ │ │ ├── blog.rb │ │ │ ├── blog │ │ │ ├── mysql_connect.rb │ │ │ ├── scope.rb │ │ │ ├── state_machine.rb │ │ │ └── wp_config.rb │ │ │ ├── cloudflare.rb │ │ │ ├── cloudflare │ │ │ └── preference.rb │ │ │ ├── domain.rb │ │ │ ├── locale.rb │ │ │ ├── monitor.rb │ │ │ ├── monitor │ │ │ └── state_machine.rb │ │ │ ├── preference.rb │ │ │ ├── preferences │ │ │ ├── cloudflare.rb │ │ │ ├── configuration.rb │ │ │ ├── preferable.rb │ │ │ ├── preferable_class_methods.rb │ │ │ └── scoped_cloudflare.rb │ │ │ ├── proxy.rb │ │ │ ├── server.rb │ │ │ ├── tag.rb │ │ │ ├── tags_blog.rb │ │ │ └── template.rb │ └── views │ │ └── wordpress │ │ ├── api │ │ └── code.html.erb │ │ └── server │ │ ├── install_os7_apache_php74.html.erb │ │ ├── install_os7_mysqlv8.html.erb │ │ ├── install_os8_apache_php74.html.erb │ │ └── install_os8_mysqlv8.html.erb ├── bin │ ├── rails │ └── test ├── config │ ├── initializers │ │ └── assets.rb │ ├── locales │ │ └── zh-CN.yml │ └── routes.rb ├── db │ └── migrate │ │ ├── 20200707064855_create_wordpress_blogs.rb │ │ ├── 20200707071606_create_wordpress_cloudflares.rb │ │ ├── 20200707074130_create_wordpress_templates.rb │ │ ├── 20200707074205_create_wordpress_locales.rb │ │ ├── 20200707074412_create_wordpress_servers.rb │ │ ├── 20200707081610_create_wordpress_tags.rb │ │ ├── 20200707081940_create_wordpress_api_tokens.rb │ │ ├── 20200707082208_create_wordpress_proxies.rb │ │ ├── 20200707091733_create_wordpress_tags_blogs.rb │ │ ├── 20200707095329_create_wordpress_domains.rb │ │ ├── 20200707125708_add_time_zone_to_admin_user.rb │ │ ├── 20200708072401_create_wordpress_preferences.rb │ │ ├── 20200709150917_add_domain_to_cloudflare.rb │ │ ├── 20200709160438_add_name_to_admin_user.rb │ │ ├── 20200717035207_add_directory_to_proxy.rb │ │ ├── 20200717132029_remove_domain_to_server.rb │ │ ├── 20200724094508_add_download_url_to_blogs.rb │ │ ├── 20200726082042_add_trackable_to_admin_user.rb │ │ ├── 20200728095718_add_user_id_to_cloudflares.rb │ │ ├── 20200728124406_add_zone_id_to_cloudflares.rb │ │ ├── 20200729052427_add_account_id_to_cloudflares.rb │ │ ├── 20200729084505_add_zone_id_to_domains.rb │ │ └── 20200730071621_create_wordpress_monitors.rb ├── lib │ ├── generators │ │ └── wordpress │ │ │ ├── install │ │ │ └── install_generator.rb │ │ │ └── templates │ │ │ ├── initializer.tt │ │ │ ├── sidekiq.tt │ │ │ └── sidekiq.yml │ ├── tasks │ │ ├── wordpress_sidekiq_task.rake │ │ └── wordpress_tasks.rake │ ├── wordpress │ │ ├── auth │ │ │ └── devish.rb │ │ ├── core.rb │ │ └── core │ │ │ ├── engine.rb │ │ │ ├── helpers │ │ │ ├── apache.rb │ │ │ ├── cloudflare_api.rb │ │ │ ├── mysql.rb │ │ │ └── mysql2_client.rb │ │ │ ├── routes.rb │ │ │ ├── token_generator.rb │ │ │ └── version.rb │ └── wordpress_core.rb ├── test │ ├── dummy │ │ ├── .ruby-version │ │ ├── Rakefile │ │ ├── app │ │ │ ├── assets │ │ │ │ ├── config │ │ │ │ │ └── manifest.js │ │ │ │ ├── images │ │ │ │ │ └── .keep │ │ │ │ └── stylesheets │ │ │ │ │ └── application.css │ │ │ ├── channels │ │ │ │ └── application_cable │ │ │ │ │ ├── channel.rb │ │ │ │ │ └── connection.rb │ │ │ ├── controllers │ │ │ │ ├── application_controller.rb │ │ │ │ └── concerns │ │ │ │ │ └── .keep │ │ │ ├── helpers │ │ │ │ └── application_helper.rb │ │ │ ├── javascript │ │ │ │ └── packs │ │ │ │ │ └── application.js │ │ │ ├── jobs │ │ │ │ └── application_job.rb │ │ │ ├── mailers │ │ │ │ └── application_mailer.rb │ │ │ ├── models │ │ │ │ ├── application_record.rb │ │ │ │ └── concerns │ │ │ │ │ └── .keep │ │ │ └── views │ │ │ │ └── layouts │ │ │ │ ├── application.html.erb │ │ │ │ ├── mailer.html.erb │ │ │ │ └── mailer.text.erb │ │ ├── bin │ │ │ ├── rails │ │ │ ├── rake │ │ │ └── setup │ │ ├── config.ru │ │ ├── config │ │ │ ├── application.rb │ │ │ ├── boot.rb │ │ │ ├── cable.yml │ │ │ ├── database.yml │ │ │ ├── environment.rb │ │ │ ├── environments │ │ │ │ ├── development.rb │ │ │ │ ├── production.rb │ │ │ │ └── test.rb │ │ │ ├── initializers │ │ │ │ ├── application_controller_renderer.rb │ │ │ │ ├── assets.rb │ │ │ │ ├── backtrace_silencers.rb │ │ │ │ ├── content_security_policy.rb │ │ │ │ ├── cookies_serializer.rb │ │ │ │ ├── filter_parameter_logging.rb │ │ │ │ ├── inflections.rb │ │ │ │ ├── mime_types.rb │ │ │ │ └── wrap_parameters.rb │ │ │ ├── locales │ │ │ │ └── en.yml │ │ │ ├── puma.rb │ │ │ ├── routes.rb │ │ │ ├── spring.rb │ │ │ └── storage.yml │ │ ├── lib │ │ │ └── assets │ │ │ │ └── .keep │ │ ├── log │ │ │ ├── .keep │ │ │ └── development.log │ │ ├── public │ │ │ ├── 404.html │ │ │ ├── 422.html │ │ │ ├── 500.html │ │ │ ├── apple-touch-icon-precomposed.png │ │ │ ├── apple-touch-icon.png │ │ │ └── favicon.ico │ │ ├── storage │ │ │ └── .keep │ │ └── tmp │ │ │ ├── .keep │ │ │ ├── development_secret.txt │ │ │ ├── pids │ │ │ └── .keep │ │ │ └── storage │ │ │ └── .keep │ ├── fixtures │ │ └── wordpress │ │ │ ├── api_tokens.yml │ │ │ ├── blogs.yml │ │ │ ├── cloudflares.yml │ │ │ ├── domains.yml │ │ │ ├── locales.yml │ │ │ ├── monitors.yml │ │ │ ├── preferences.yml │ │ │ ├── proxies.yml │ │ │ ├── servers.yml │ │ │ ├── tags.yml │ │ │ ├── tags_blogs.yml │ │ │ └── templates.yml │ ├── models │ │ └── wordpress │ │ │ ├── api_token_test.rb │ │ │ ├── blog_test.rb │ │ │ ├── cloudflare_test.rb │ │ │ ├── domain_test.rb │ │ │ ├── locale_test.rb │ │ │ ├── monitor_test.rb │ │ │ ├── preference_test.rb │ │ │ ├── proxy_test.rb │ │ │ ├── server_test.rb │ │ │ ├── tag_test.rb │ │ │ ├── tags_blog_test.rb │ │ │ └── template_test.rb │ ├── test_helper.rb │ └── wordpress_test.rb └── wordpress_core.gemspec ├── lib └── wordpress.rb └── wordpress.gemspec /.gitignore: -------------------------------------------------------------------------------- 1 | .bundle/ 2 | log/*.log 3 | pkg/ 4 | test/dummy/db/*.sqlite3 5 | test/dummy/db/*.sqlite3-journal 6 | test/dummy/db/*.sqlite3-* 7 | test/dummy/log/*.log 8 | test/dummy/storage/ 9 | test/dummy/tmp/ 10 | .DS_Store 11 | /*/node_modules -------------------------------------------------------------------------------- /MIT-LICENSE: -------------------------------------------------------------------------------- 1 | Copyright 2020 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining 4 | a copy of this software and associated documentation files (the 5 | "Software"), to deal in the Software without restriction, including 6 | without limitation the rights to use, copy, modify, merge, publish, 7 | distribute, sublicense, and/or sell copies of the Software, and to 8 | permit persons to whom the Software is furnished to do so, subject to 9 | the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be 12 | included in all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 15 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 17 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 18 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 19 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 20 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Cloud_wordpress is use for wordpress site group management 2 | 3 | * Is activeadmin based; 4 | * WordPress blog domain name connects to Cloudflare Partner; 5 | * WordPress host auto install; 6 | * WordPress host distributed management; 7 | * Clone an existing blog when create a new WordPress; 8 | * Multi-language WordPress management; 9 | * php proxy forwarding; 10 | * Admin user role; 11 | 12 | 13 | ## Usage 14 | How to use my plugin. 15 | 16 | ## Installation 17 | Add this line to your application's Gemfile: 18 | 19 | ```ruby 20 | gem "wordpress", github: "seadfeng/cloud_wordpress" 21 | gem "active_admin_role", github: "seadfeng/active_admin_role" 22 | ``` 23 | 24 | And then execute: 25 | ```bash 26 | $ bundle install 27 | $ rails webpacker:install 28 | $ rake db:create 29 | $ rails g active_admin:install 30 | $ rails g wordpress:install 31 | $ rake db:migrate 32 | $ rake db:seed 33 | $ rake wordpress:init 34 | $ rake assets:precompile 35 | ``` 36 | 37 | ## Update 38 | 39 | ```bash 40 | $ rake railties:install:migrations FROM=wordpress 41 | $ rake db:migrate 42 | ``` 43 | 44 | ## Application Config 45 | 46 | ```ruby 47 | # config/application.rb 48 | config.i18n.default_locale = :"zh-CN" 49 | config.active_job.default_url_options = { host: "demo.cloudwp.xyz" } 50 | Rails.application.routes.default_url_options[:host] = "demo.cloudwp.xyz" 51 | ``` 52 | 53 | ## Sidekiq Config 54 | ```ruby 55 | # config/initializers/sidekiq.rb 56 | Sidekiq.configure_server do |config| 57 | config.redis = { url: 'redis://127.0.0.1:6379/2' } 58 | end 59 | Sidekiq.configure_client do |config| 60 | config.redis = { url: 'redis://127.0.0.1:6379/2' } 61 | end 62 | ``` 63 | 64 | ## Wordpress Host System dependence 65 | Centos 8.0+ 66 | 67 | ## System dependence 68 | rails 6.0+ 69 | mysql 8.0+ 70 | 71 | ## Dependencies 72 | 73 | [activeadmin](https://github.com/activeadmin/activeadmin) 74 | 75 | [activeadmin_addons](https://github.com/platanus/activeadmin_addons) 76 | 77 | [active_admin_role](https://github.com/seadfeng/active_admin_role) 78 | 79 | [active_admin_import](https://github.com/activeadmin-plugins/active_admin_import) 80 | 81 | 82 | ## Sidekiq Service 83 | 84 | https://github.com/mperham/sidekiq/blob/07c0e1f4e60298deeab70999f6a33c86959f196a/examples/systemd/sidekiq.service 85 | 86 | ## Webpacker Using in Rails engines 87 | 88 | https://github.com/rails/webpacker/blob/master/docs/engines.md 89 | 90 | ## License 91 | The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT). 92 | 93 | -------------------------------------------------------------------------------- /Rakefile: -------------------------------------------------------------------------------- 1 | begin 2 | require 'bundler/setup' 3 | rescue LoadError 4 | puts 'You must `gem install bundler` and `bundle install` to run rake tasks' 5 | end 6 | 7 | require 'rdoc/task' 8 | 9 | RDoc::Task.new(:rdoc) do |rdoc| 10 | rdoc.rdoc_dir = 'rdoc' 11 | rdoc.title = 'Amz' 12 | rdoc.options << '--line-numbers' 13 | rdoc.rdoc_files.include('README.md') 14 | rdoc.rdoc_files.include('lib/**/*.rb') 15 | end 16 | 17 | APP_RAKEFILE = File.expand_path("test/dummy/Rakefile", __dir__) 18 | load 'rails/tasks/engine.rake' 19 | 20 | load 'rails/tasks/statistics.rake' 21 | 22 | require 'bundler/gem_tasks' 23 | 24 | require 'rake/testtask' 25 | 26 | Rake::TestTask.new(:test) do |t| 27 | t.libs << 'test' 28 | t.pattern = 'test/**/*_test.rb' 29 | t.verbose = false 30 | end 31 | 32 | task default: :test 33 | -------------------------------------------------------------------------------- /backend/Gemfile: -------------------------------------------------------------------------------- 1 | source 'https://rubygems.org' 2 | git_source(:github) { |repo| "https://github.com/#{repo}.git" } 3 | 4 | # Declare your gem's dependencies in wordpress_backend.gemspec. 5 | # Bundler will treat runtime dependencies like base dependencies, and 6 | # development dependencies will be added by default to the :development group. 7 | gemspec 8 | 9 | # Declare any dependencies that are still in development here instead of in 10 | # your gemspec. These might include edge Rails or gems from your path or 11 | # Git. Remember to move these dependencies to your gemspec before releasing 12 | # your gem to rubygems.org. 13 | 14 | # To use a debugger 15 | # gem 'byebug', group: [:development, :test] 16 | -------------------------------------------------------------------------------- /backend/Rakefile: -------------------------------------------------------------------------------- 1 | require "bundler/gem_tasks" 2 | require "rake/testtask" 3 | 4 | Rake::TestTask.new(:test) do |t| 5 | t.libs << "test" 6 | t.libs << "lib" 7 | t.test_files = FileList["test/**/*_test.rb"] 8 | end 9 | 10 | task :default => :test 11 | -------------------------------------------------------------------------------- /backend/app/admin/admin_user.rb: -------------------------------------------------------------------------------- 1 | if defined?(ActiveAdmin) && defined?(AdminUser) 2 | ActiveAdmin.register AdminUser do 3 | config.comments = false 4 | menu priority: 100 5 | init_controller 6 | begin 7 | role_changeable 8 | rescue => exception 9 | nil 10 | end 11 | 12 | permit_params :email, :password, :password_confirmation, :first_name, :last_name, :time_zone 13 | 14 | controller do 15 | def update 16 | params[:admin_user][:password] = resource.password if params[:admin_user][:password].blank? 17 | params[:admin_user][:password_confirmation] = resource.password_confirmation if params[:admin_user][:password_confirmation].blank? 18 | super 19 | end 20 | end 21 | 22 | index download_links: false do 23 | selectable_column 24 | id_column 25 | column :full_name 26 | column :email 27 | column :current_sign_in_at 28 | column :sign_in_count 29 | column :created_at 30 | actions 31 | end 32 | 33 | filter :email 34 | filter :current_sign_in_at 35 | filter :sign_in_count 36 | filter :created_at 37 | 38 | form do |f| 39 | f.inputs do 40 | f.input :email 41 | f.input :first_name 42 | f.input :last_name 43 | f.input :time_zone , as: :select, collection: TZInfo::Timezone.all_country_zone_identifiers 44 | f.input :password 45 | f.input :password_confirmation 46 | end 47 | f.actions 48 | end 49 | 50 | end 51 | end 52 | -------------------------------------------------------------------------------- /backend/app/admin/api_token.rb: -------------------------------------------------------------------------------- 1 | ActiveAdmin.register Wordpress::ApiToken, as: "ApiToken" do 2 | permit_params :name, :key 3 | active_admin_paranoia 4 | menu priority: 80, parent: "Settings" 5 | 6 | member_action :download_code, method: :put do 7 | options = { 8 | 'X-Auth-Key' => resource.key, 9 | } 10 | client = RestClient.get( wordpress.api_code_url, options ) 11 | send_data client.body, :disposition => "attachment; filename=index.php", :type => 'text/html; charset=utf-8; header=present' 12 | end 13 | 14 | index download_links: false do 15 | selectable_column 16 | id_column 17 | column :name 18 | column :download do |source| 19 | link_to "index.php", download_code_admin_api_token_path(source), method: :put 20 | end 21 | column :key 22 | column :created_at 23 | column :updated_at 24 | actions 25 | end 26 | 27 | filter :name 28 | 29 | form do |f| 30 | f.inputs I18n.t("active_admin.api_token.form" , default: "API") do 31 | f.input :name 32 | end 33 | f.actions 34 | end 35 | end -------------------------------------------------------------------------------- /backend/app/admin/cloudflares.rb: -------------------------------------------------------------------------------- 1 | ActiveAdmin.register Wordpress::Cloudflare, as: "Cloudflare" do 2 | init_controller 3 | actions :all 4 | # batch_action :destroy, false 5 | menu priority: 60 , parent: "Settings" 6 | permit_params :api_user, :name, :api_token ,:description , :domain 7 | active_admin_paranoia 8 | 9 | 10 | controller do 11 | def update 12 | params[:cloudflare][:api_token] = resource.api_token if params[:cloudflare][:api_token].blank? 13 | super 14 | end 15 | end 16 | 17 | action_item :rsync, only: :show do 18 | link_to( 19 | resource.rsynced? ? I18n.t('active_admin.rsync_info', default: "更新信息") : I18n.t('active_admin.get_info', default: "获取信息") , 20 | rsync_admin_cloudflare_path(resource), 21 | method: :put 22 | ) 23 | end 24 | 25 | member_action :rsync, method: :put do 26 | if (resource.rsync_user_id && resource.rsync_zone_id && resource.rsync_account_id) 27 | options = { notice: I18n.t('active_admin.updated', default: "更新成功") } 28 | else 29 | options = { notice: I18n.t('active_admin.update_failed', default: "更新失败") } 30 | end 31 | redirect_back({ fallback_location: ActiveAdmin.application.root_to }.merge(options)) 32 | end 33 | 34 | index download_links: false do 35 | selectable_column 36 | id_column 37 | column :user_id do |source| 38 | if (source.user_id.blank? || source.zone_id.blank?) 39 | link_to t("active_admin.cloudflare.get_user_id" , default: "手工获取") , rsync_admin_cloudflare_path(source), method: :put 40 | else 41 | source.user_id 42 | end 43 | end 44 | column :name 45 | column :remaining 46 | column :domain 47 | column :api_user 48 | column :description 49 | column :created_at 50 | column :updated_at 51 | actions 52 | end 53 | 54 | filter :name 55 | filter :code 56 | filter :created_at 57 | filter :updated_at 58 | 59 | form do |f| 60 | f.inputs I18n.t("active_admin.cloudflare.form" , default: "Cloudflare") do 61 | f.input :name, hint: "根据自己命名习惯起名" 62 | f.input :domain, hint: "Cloudflare必须有解析权限的域名,用于博客的二级域名" 63 | f.input :api_user , hint: "Cloudflare登陆账户名" 64 | f.input :api_token , as: :password , hint: raw("Cloudflare Api Key => Global API Key => View
快捷链接" ) 65 | f.input :description 66 | end 67 | f.actions 68 | end 69 | 70 | show do 71 | panel t('active_admin.details', model: resource_class.to_s.titleize) do 72 | attributes_table_for resource do 73 | row :api_user 74 | row :account_id 75 | row :zone_id 76 | row :user_id 77 | row :domain 78 | row :name 79 | row :description 80 | row :created_at 81 | row :updated_at 82 | end 83 | end 84 | end 85 | 86 | 87 | end 88 | 89 | -------------------------------------------------------------------------------- /backend/app/admin/dashboard.rb: -------------------------------------------------------------------------------- 1 | ActiveAdmin.register_page "Dashboard" do 2 | init_controller 3 | menu priority: 0, label: proc{ I18n.t("active_admin.dashboard") } 4 | 5 | content title: proc{ I18n.t("active_admin.dashboard") } do 6 | # Groupdate.time_zone = "Beijing" 7 | Groupdate.day_start = 0 8 | 9 | columns do 10 | blogs = Wordpress::Blog.published 11 | blogs = blogs.where(admin_user_id: current_admin_user.id) unless current_admin_user.admin? 12 | days_90 = blogs.where( "published_at >= ?", 3.months.ago ) 13 | column do 14 | panel "90天发布 - #{days_90.count}个" do 15 | div line_chart days_90.group_by_day(:published_at ).count 16 | end 17 | end 18 | if current_admin_user.admin? 19 | column do 20 | panel "博客主机分布" do 21 | div pie_chart Wordpress::Blog.all.joins(:server).group("#{Wordpress::Server.table_name}.name").order("count_all desc").count 22 | end 23 | end 24 | end 25 | end #columns 26 | end # content 27 | end 28 | -------------------------------------------------------------------------------- /backend/app/admin/domains.rb: -------------------------------------------------------------------------------- 1 | if defined?(ActiveAdmin) && defined?(Wordpress::Domain) 2 | ActiveAdmin.register Wordpress::Domain, as: "Domain" do 3 | init_controller 4 | permit_params :name , :description 5 | menu priority: 6 6 | active_admin_paranoia 7 | 8 | scope :active 9 | scope :not_use 10 | scope :cloudflare 11 | scope :unuse_cloudflare 12 | 13 | active_admin_import validate: true, 14 | template_object: ActiveAdminImport::Model.new( 15 | hint: I18n.t("active_admin_import.domain.import.hint" , default: "CSV: ,\"Name\",\"Description\"
示例:
下载CSV文件"), 16 | ), 17 | headers_rewrites: { :'Description' => :description, :'Name' => :name } 18 | 19 | 20 | collection_action :import_csv, method: :get do 21 | send_data "Name,Description\r\n,", :disposition => "attachment; filename=domains.csv" 22 | end 23 | 24 | 25 | member_action :rsync_cloudflare_zone, method: :put do 26 | resource.rsync_cloudflare_zone 27 | options = { notice: I18n.t('active_admin.processing', default: "正在受理") } 28 | redirect_back({ fallback_location: ActiveAdmin.application.root_to }.merge(options)) 29 | end 30 | 31 | action_item :rsync_cloudflare_zone, only: :show do 32 | if Wordpress::Config.cfp_enable 33 | link_to( 34 | I18n.t('active_admin.rsync_cloudflare_zone', default: "同步Cloudflare Partner"), 35 | rsync_cloudflare_zone_admin_domain_path(resource) , 36 | method: :put 37 | ) 38 | end 39 | end 40 | 41 | # action_item :import_cfp, only: [:index] do 42 | # if Wordpress::Config.cfp_enable 43 | # link_to( 44 | # I18n.t('active_admin.import_cfp', default: "导入Cloudflare Partner域名"), 45 | # import_cfp_admin_domains_path , 46 | # method: "put" 47 | # ) 48 | # end 49 | # end 50 | 51 | index do 52 | selectable_column 53 | id_column 54 | column :blogs do |source| 55 | ul do 56 | source.blogs.each do |blog| 57 | li auto_link blog 58 | end 59 | end 60 | end 61 | column :name 62 | column :description 63 | column :state 64 | column :cloudflare do |source| 65 | status_tag !!source.zone_id ? "Yes" : "No" 66 | end 67 | column :created_at 68 | column :updated_at 69 | actions 70 | end 71 | 72 | filter :name 73 | filter :state 74 | 75 | form do |f| 76 | f.inputs I18n.t("active_admin.domains.form" , default: "域名") do 77 | f.input :name, hint: "根域名" 78 | f.input :description 79 | end 80 | f.actions 81 | end 82 | end 83 | end -------------------------------------------------------------------------------- /backend/app/admin/locales.rb: -------------------------------------------------------------------------------- 1 | ActiveAdmin.register Wordpress::Locale, as: "Locale" do 2 | init_controller 3 | actions :all, except: [:destroy] 4 | batch_action :destroy, false 5 | menu priority: 60 , parent: "Settings" 6 | permit_params :code, :name , :position 7 | 8 | 9 | index download_links: false do 10 | selectable_column 11 | id_column 12 | column :name 13 | column :code 14 | column :position 15 | column :created_at 16 | column :updated_at 17 | actions 18 | end 19 | 20 | filter :name 21 | filter :code 22 | filter :created_at 23 | filter :updated_at 24 | 25 | end 26 | 27 | -------------------------------------------------------------------------------- /backend/app/admin/monitor.rb: -------------------------------------------------------------------------------- 1 | ActiveAdmin.register Wordpress::Monitor, as: "Monitor" do 2 | init_controller 3 | actions :all, except: [:edit, :new, :update] 4 | menu priority: 100 5 | 6 | filter :created_at 7 | filter :updated_at 8 | 9 | index do 10 | selectable_column 11 | id_column 12 | tag_column :state, machine: :state 13 | column :blog 14 | column :action 15 | column :queued_at 16 | column :completed_at 17 | column :created_at 18 | column :updated_at 19 | actions 20 | end 21 | end -------------------------------------------------------------------------------- /backend/app/admin/permissions.rb: -------------------------------------------------------------------------------- 1 | ActiveAdmin.register ::ActiveAdmin::Permission, as: "Permission" do 2 | menu priority: 100, parent: "Admin Users" 3 | actions :index 4 | 5 | filter :state, as: :select, collection: controller.resource_class.states 6 | 7 | filter :managed_resource_action_equals, as: :select, 8 | label: ::ActiveAdmin::ManagedResource.human_attribute_name(:action), 9 | collection: -> { ::ActiveAdmin::ManagedResource.distinct.order(:action).pluck(:action) } 10 | 11 | filter :managed_resource_name_equals, as: :select, 12 | label: ::ActiveAdmin::ManagedResource.human_attribute_name(:name), 13 | collection: -> { ::ActiveAdmin::ManagedResource.distinct.pluck(:name).sort } 14 | 15 | filter :managed_resource_class_name_equals, as: :select, 16 | label: ::ActiveAdmin::ManagedResource.human_attribute_name(:class_name), 17 | collection: -> { ::ActiveAdmin::ManagedResource.distinct.order(:class_name).pluck(:class_name) } 18 | 19 | scope :all, default: true 20 | 21 | controller.resource_class.manageable_roles.each_key(&method(:scope)) 22 | 23 | controller.resource_class.states.each_key do |state| 24 | batch_action state do |ids| 25 | resource_class.clear_cache 26 | resource_class.where(id: ids).update_all(state: resource_class.states[state]) 27 | redirect_back fallback_location: admin_root_url, notice: t("views.permission.notice.state_changed", state: state) 28 | end 29 | end 30 | 31 | collection_action :reload, method: :post do 32 | ::ActiveAdmin::ManagedResource.reload 33 | redirect_back(fallback_location: admin_root_url, notice: t("views.permission.notice.reloaded")) 34 | end 35 | 36 | action_item :reload do 37 | link_to t("views.permission.action_item.reload"), reload_admin_permissions_path, method: :post 38 | end 39 | 40 | includes :managed_resource 41 | 42 | index do 43 | selectable_column 44 | column :role 45 | column(:state) do |record| 46 | status_tag(record.state, class: record.can? ? "completed ok" : "null", label: record.state) 47 | end 48 | column :action 49 | column :name 50 | column :class_name 51 | end 52 | end 53 | -------------------------------------------------------------------------------- /backend/app/admin/proxy.rb: -------------------------------------------------------------------------------- 1 | ActiveAdmin.register Wordpress::Proxy, as: "Proxy" do 2 | permit_params :host, :port, :user, :password, :name, :description ,:connection_type, :installed_at 3 | batch_action :destroy, false 4 | actions :all, except: [:destroy] 5 | menu priority: 80 6 | 7 | controller do 8 | def update 9 | params[:proxy][:password] = resource.password if params[:proxy][:password].blank? 10 | super 11 | end 12 | end 13 | 14 | index download_links: false do 15 | selectable_column 16 | id_column 17 | column :host 18 | column :connection_type 19 | column :user 20 | column :name 21 | column :status 22 | column :directory 23 | # column :install do |post| 24 | # if post.installed 25 | # span "已安装" , style: "background-color: #5cb85c;display:block;min-width:35px;text-align:center" 26 | # else 27 | # link_to I18n.t("active_admin.proxy.dns" , default: "安装") , install_admin_proxy_path(post) , method: :put , class: "status_tag yes" ,style: "color:#FFF" 28 | # end 29 | # end 30 | column :installed_at 31 | column :created_at 32 | column :updated_at 33 | actions 34 | end 35 | 36 | 37 | action_item :install, only: [:show] do 38 | unless resource.installed? 39 | link_to( 40 | I18n.t('active_admin.install', default: "安装Apache+PHP"), 41 | install_admin_proxy_path(resource), 42 | method: "put" 43 | ) 44 | end 45 | end 46 | 47 | action_item :upload, only: [:show] do 48 | if resource.installed? 49 | link_to( 50 | I18n.t('active_admin.upload', default: "上传"), 51 | upload_admin_proxy_path(resource), 52 | method: "put" 53 | ) 54 | end 55 | end 56 | 57 | 58 | member_action :upload, method: :put do 59 | 60 | end 61 | 62 | member_action :do_upload, method: :put do 63 | api_id = params["api_id"] 64 | api = ApiToken.find( api_id ) 65 | if api && resource.push_code(api) 66 | redirect_to admin_proxy_path(resource), notice: "已推送" 67 | else 68 | redirect_to admin_proxy_path(resource), notice: "推送失败" 69 | end 70 | 71 | end 72 | 73 | 74 | member_action :install, method: :put do 75 | resource.install 76 | redirect_back(fallback_location: admin_proxies_path, notice: "已推送安装指令,预计3~7分钟安装完成" ) 77 | end 78 | 79 | member_action :test, method: :put do 80 | if resource.test_connection 81 | options = { notice: I18n.t('active_admin.connection_succeeded', default: "连接成功") } 82 | else 83 | options = { alert: I18n.t('active_admin.connection_failed', default: "连接失败") } 84 | end 85 | redirect_back({ fallback_location: ActiveAdmin.application.root_to }.merge(options)) 86 | end 87 | 88 | action_item :test, only: [:show , :edit] do 89 | link_to( 90 | I18n.t('active_admin.test_connection', default: "连接测试"), 91 | test_admin_proxy_path(resource), 92 | method: "put" 93 | ) 94 | end 95 | 96 | form do |f| 97 | f.inputs I18n.t("active_admin.proxy.form" , default: "代理") do 98 | f.input :host , hint: "安装脚本只支持:Centos 7/8" 99 | f.input :name 100 | f.input :connection_type, as: :select, collection: Wordpress::Proxy::CONNECTION_TYPES 101 | f.input :port 102 | f.input :user 103 | f.input :password 104 | f.input :directory, hint: "不设置默认:/var/www/html/" 105 | f.input :description 106 | f.input :installed_at, as: :date_time_picker 107 | end 108 | f.actions 109 | end 110 | 111 | end 112 | -------------------------------------------------------------------------------- /backend/app/assets/images/icons/arrows.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /backend/app/assets/images/icons/interface.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 7 | 8 | 9 | 13 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | -------------------------------------------------------------------------------- /backend/app/assets/images/wordpress/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/seadfeng/cloud_wordpress/b89f027ce3c7a82972d8279e70faf8ffee96749a/backend/app/assets/images/wordpress/favicon.ico -------------------------------------------------------------------------------- /backend/app/assets/images/wordpress/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/seadfeng/cloud_wordpress/b89f027ce3c7a82972d8279e70faf8ffee96749a/backend/app/assets/images/wordpress/logo.png -------------------------------------------------------------------------------- /backend/app/assets/javascripts/active_admin/amz.js: -------------------------------------------------------------------------------- 1 | //= require ./components/copy_text -------------------------------------------------------------------------------- /backend/app/assets/javascripts/active_admin/components/copy_text.js: -------------------------------------------------------------------------------- 1 | $(function() { 2 | $('.row-mysql_password td, .row-wordpress_password td, .row-mysql_host td, .row-mysql_user td').each(function(){ 3 | $(this).attr('title', "可复制"); 4 | $(this).click(function(){ 5 | $('.row td.active').removeClass('active'); 6 | $(this).addClass('active'); 7 | var tempInput = document.createElement("input"); 8 | tempInput.value = $(this).text(); 9 | document.body.appendChild(tempInput); 10 | tempInput.select(); 11 | tempInput.setSelectionRange(0, 99999); 12 | document.execCommand("copy"); 13 | document.body.removeChild(tempInput); 14 | }) 15 | }) 16 | }) -------------------------------------------------------------------------------- /backend/app/assets/stylesheets/active_admin/_amz.scss: -------------------------------------------------------------------------------- 1 | @import "active_admin/components/status_tags"; 2 | @import "active_admin/components/table"; -------------------------------------------------------------------------------- /backend/app/assets/stylesheets/active_admin/components/_status_tags.scss: -------------------------------------------------------------------------------- 1 | .status_tag { 2 | &.installed, 3 | &.open, 4 | &.done { background: #29c7b3; } 5 | &.complete, 6 | &.published { background: #7DB942; } 7 | &.draft, 8 | &.processing { background: orange; } 9 | } -------------------------------------------------------------------------------- /backend/app/assets/stylesheets/active_admin/components/_table.scss: -------------------------------------------------------------------------------- 1 | .index_table { 2 | .alert { 3 | color: #ff0000; 4 | } 5 | } 6 | .attributes_table { 7 | td.active { 8 | background: #57ab6a63; 9 | } 10 | } 11 | .lds-ellipsis { 12 | display: block; 13 | position: relative; 14 | margin: 0 auto; 15 | width: 100px;; 16 | height: 100px;; 17 | div { 18 | position: absolute; 19 | top: 33px; 20 | width: 13px; 21 | height: 13px; 22 | border-radius: 50%; 23 | background: #63636363; 24 | animation-timing-function: cubic-bezier(0, 1, 1, 0); 25 | } 26 | div:nth-child(1) { 27 | left: 8px; 28 | animation: lds-ellipsis1 0.6s infinite; 29 | } 30 | div:nth-child(2) { 31 | left: 8px; 32 | animation: lds-ellipsis2 0.6s infinite; 33 | } 34 | div:nth-child(3) { 35 | left: 32px; 36 | animation: lds-ellipsis2 0.6s infinite; 37 | } 38 | div:nth-child(4) { 39 | left: 56px; 40 | animation: lds-ellipsis3 0.6s infinite; 41 | } 42 | } 43 | 44 | @keyframes lds-ellipsis1 { 45 | 0% { 46 | transform: scale(0); 47 | } 48 | 100% { 49 | transform: scale(1); 50 | } 51 | } 52 | @keyframes lds-ellipsis3 { 53 | 0% { 54 | transform: scale(1); 55 | } 56 | 100% { 57 | transform: scale(0); 58 | } 59 | } 60 | @keyframes lds-ellipsis2 { 61 | 0% { 62 | transform: translate(0, 0); 63 | } 64 | 100% { 65 | transform: translate(24px, 0); 66 | } 67 | } -------------------------------------------------------------------------------- /backend/app/models/admin_user_decorator.rb: -------------------------------------------------------------------------------- 1 | class AdminUserDecorator 2 | if defined?(AdminUser) 3 | AdminUser.class_eval do 4 | devise :trackable 5 | validates :first_name, presence: true 6 | validates :last_name, presence: true 7 | 8 | def full_name 9 | "#{first_name} #{last_name}" 10 | end 11 | 12 | def display_name 13 | "#{self.full_name} - #{role}" 14 | end 15 | end 16 | end 17 | end -------------------------------------------------------------------------------- /backend/app/models/api_token.rb: -------------------------------------------------------------------------------- 1 | class ApiToken < Wordpress::ApiToken 2 | 3 | end -------------------------------------------------------------------------------- /backend/app/models/blog.rb: -------------------------------------------------------------------------------- 1 | class Blog < Wordpress::Blog 2 | 3 | end -------------------------------------------------------------------------------- /backend/app/models/cloudflare.rb: -------------------------------------------------------------------------------- 1 | class Cloudflare < Wordpress::Cloudflare 2 | 3 | end -------------------------------------------------------------------------------- /backend/app/models/domain.rb: -------------------------------------------------------------------------------- 1 | class Domain < Wordpress::Domain 2 | 3 | end 4 | -------------------------------------------------------------------------------- /backend/app/models/locale.rb: -------------------------------------------------------------------------------- 1 | class Locale < Wordpress::Locale 2 | 3 | end -------------------------------------------------------------------------------- /backend/app/models/monitor.rb: -------------------------------------------------------------------------------- 1 | class Monitor < Wordpress::Monitor 2 | 3 | end 4 | -------------------------------------------------------------------------------- /backend/app/models/proxy.rb: -------------------------------------------------------------------------------- 1 | class Proxy < Wordpress::Proxy 2 | 3 | end 4 | -------------------------------------------------------------------------------- /backend/app/models/server.rb: -------------------------------------------------------------------------------- 1 | class Server < Wordpress::Server 2 | 3 | end 4 | -------------------------------------------------------------------------------- /backend/app/models/tag.rb: -------------------------------------------------------------------------------- 1 | class Tag < Wordpress::Tag 2 | 3 | end 4 | -------------------------------------------------------------------------------- /backend/app/models/tags_blog.rb: -------------------------------------------------------------------------------- 1 | class TagsBlog < Wordpress::TagsBlog 2 | 3 | end 4 | -------------------------------------------------------------------------------- /backend/app/models/template.rb: -------------------------------------------------------------------------------- 1 | class Template < Wordpress::Template 2 | 3 | end 4 | -------------------------------------------------------------------------------- /backend/app/views/admin/blogs/install.html.arb: -------------------------------------------------------------------------------- 1 | 2 | 3 | panel "选择模版" do 4 | table_for resource.templates do 5 | column :id 6 | column :locale 7 | column :name 8 | column :install do |template| 9 | link_to I18n.t('active_admin.install', default: "安装"), do_install_admin_blog_path(resource,template_id: template.id) ,method: "put" 10 | end 11 | end 12 | end -------------------------------------------------------------------------------- /backend/app/views/admin/blogs/login.html.erb: -------------------------------------------------------------------------------- 1 | 2 |
3 | 4 | 5 | 6 | 7 | 8 |
9 | -------------------------------------------------------------------------------- /backend/app/views/admin/blogs/migration.html.erb: -------------------------------------------------------------------------------- 1 | <%= semantic_form_for @blog , url: {action: :do_migration} do |f| %> 2 | <%= f.inputs name: t("active_admin.blog.migration", default: "批量迁移设置") do %> 3 | <%= f.input :migration, as: :text, hint: raw("一行一条记录, DEMO:
number,www.demo.com,https://www.demo.com/download_url.tar.bz2") %> 4 | <% end %> 5 | <%= f.actions do %> 6 | <%= f.action :submit, label: t("active_admin.submit", default: "Submit") %> 7 | <% end %> 8 | <% end %> -------------------------------------------------------------------------------- /backend/app/views/admin/import.html.erb: -------------------------------------------------------------------------------- 1 |

2 | <%= raw(@active_admin_import_model.hint) %> 3 |

4 | <%= semantic_form_for @active_admin_import_model, url: {action: :do_import}, html: {multipart: true} do |f| %> 5 | <%= f.inputs name: t("active_admin_import.details") do %> 6 | <%= f.input :file, as: :file %> 7 | <% end %> 8 | <%= f.actions do %> 9 | <%= f.action :submit, label: t("active_admin_import.import_btn"), button_html: {data: {disable_with: t("active_admin_import.import_btn_disabled")}} %> 10 | <% end %> 11 | <% end %> -------------------------------------------------------------------------------- /backend/app/views/admin/proxies/upload.html.arb: -------------------------------------------------------------------------------- 1 | panel "选择Api" do 2 | table_for ApiToken.all do 3 | column :id 4 | column :name 5 | column :key 6 | column :upload do |source| 7 | link_to "上传", do_upload_admin_proxy_path(source, api_id: source.id), method: :put 8 | end 9 | end 10 | end -------------------------------------------------------------------------------- /backend/config/locales/en.yml: -------------------------------------------------------------------------------- 1 | en: 2 | active_admin: 3 | send_job: "#%{id} %{name} Send to Job" 4 | successfully_updated: "Successfully updated %{name}" 5 | successfully_created: "Successfully created %{name}" 6 | create_failure: "%{name} create failure" 7 | import: "Import" 8 | filters: 9 | store: "Store" 10 | asin: "ASIN" 11 | batch_actions: 12 | delete_confirmation: "Are you sure you want to archive these %{plural_model}?" 13 | succesfully_destroyed: 14 | one: "Successfully archived 1 %{model}" 15 | other: "Successfully archived %{count} %{plural_model}" 16 | labels: 17 | destroy: "Archive" 18 | active_admin_paranoia: 19 | batch_actions: 20 | restore_confirmation: "Are you sure you want to restore these %{plural_model}?" 21 | succesfully_restored: 22 | one: "Successfully restored 1 %{model}" 23 | other: "Successfully restored %{count} %{plural_model}" 24 | archived: "Archived" 25 | non_archived: "Non Archived" 26 | restore_model: "Restore %{model}" 27 | restore: "Restore" 28 | restore_confirmation: "Are you sure you want to restore this?" 29 | something_wrong: "Something went wrong. Please try again" 30 | active_admin_import: 31 | file: 'File' 32 | file_error: "Error: %{message}" 33 | file_format_error: "You can import only valid csv file" 34 | file_empty_error: "You can't import empty file" 35 | no_file_error: "Please, select file to import" 36 | details: "Please, select file to import" 37 | imported: 38 | one: "Successfully imported 1 %{model}" 39 | other: "Successfully imported %{count} %{plural_model}" 40 | failed: 41 | one: "Failed to import 1 %{model}: %{message}" 42 | other: "Failed to import %{count} %{plural_model}: %{message}" 43 | import_model: "Import %{plural_model}" 44 | import_btn: "Import" 45 | import_btn_disabled: "Wait..." 46 | csv_options: "CSV options" 47 | col_sep: 'Col sep' 48 | row_sep: 'Row sep' 49 | quote_char: 'Quote char' -------------------------------------------------------------------------------- /backend/lib/active_admin_import.rb: -------------------------------------------------------------------------------- 1 | require 'activerecord-import' 2 | require 'active_admin' 3 | require 'active_admin_import/version' 4 | require 'active_admin_import/import_result' 5 | require 'active_admin_import/options' 6 | require 'active_admin_import/dsl' 7 | require 'active_admin_import/importer' 8 | require 'active_admin_import/model' 9 | require 'active_admin_import/authorization' 10 | ::ActiveAdmin::DSL.send(:include, ActiveAdminImport::DSL) -------------------------------------------------------------------------------- /backend/lib/active_admin_import/authorization.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | module ActiveAdminImport 3 | # Default Authorization permission for ActiveAdminImport 4 | module Authorization 5 | IMPORT = :import 6 | end 7 | 8 | Auth = Authorization 9 | end 10 | -------------------------------------------------------------------------------- /backend/lib/active_admin_import/import_result.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | module ActiveAdminImport 3 | class ImportResult 4 | attr_reader :failed, :total 5 | 6 | def initialize 7 | @failed = [] 8 | @total = 0 9 | end 10 | 11 | def add(result, qty) 12 | @failed += result.failed_instances 13 | @total += qty 14 | end 15 | 16 | def imported_qty 17 | total - failed.count 18 | end 19 | 20 | def imported? 21 | imported_qty > 0 22 | end 23 | 24 | def failed? 25 | failed.any? 26 | end 27 | 28 | def empty? 29 | total == 0 30 | end 31 | 32 | def failed_message(options = {}) 33 | limit = options[:limit] || failed.count 34 | failed.first(limit).map do |record| 35 | errors = record.errors 36 | failed_values = errors.keys.map do |key| 37 | key == :base ? nil : record.public_send(key) 38 | end 39 | errors.full_messages.zip(failed_values).map { |ms| ms.compact.join(' - ') }.join(', ') 40 | end.join(' ; ') 41 | end 42 | end 43 | end 44 | -------------------------------------------------------------------------------- /backend/lib/active_admin_import/options.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | module ActiveAdminImport 3 | module Options 4 | VALID_OPTIONS = [ 5 | :back, 6 | :csv_options, 7 | :validate, 8 | :batch_size, 9 | :batch_transaction, 10 | :before_import, 11 | :after_import, 12 | :before_batch_import, 13 | :after_batch_import, 14 | :on_duplicate_key_update, 15 | :timestamps, 16 | :ignore, 17 | :template, 18 | :template_object, 19 | :resource_class, 20 | :resource_label, 21 | :plural_resource_label, 22 | :error_limit, 23 | :headers_rewrites, 24 | :if 25 | ].freeze 26 | 27 | def self.options_for(config, options = {}) 28 | unless options.key? :template_object 29 | options[:template_object] = ActiveAdminImport::Model.new 30 | end 31 | 32 | { 33 | back: { action: :import }, 34 | csv_options: {}, 35 | template: 'admin/import', 36 | resource_class: config.resource_class, 37 | resource_label: config.resource_label, 38 | plural_resource_label: config.plural_resource_label, 39 | error_limit: 5, 40 | headers_rewrites: {}, 41 | if: true 42 | }.deep_merge(options) 43 | end 44 | end 45 | end 46 | -------------------------------------------------------------------------------- /backend/lib/active_admin_import/version.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | module ActiveAdminImport 4 | VERSION = '4.1.1' 5 | end 6 | -------------------------------------------------------------------------------- /backend/lib/wordpress/backend.rb: -------------------------------------------------------------------------------- 1 | require "activeadmin" 2 | require "activeadmin_addons" 3 | require "active_admin_role" 4 | require "devise" 5 | require "draper" 6 | require "pundit" 7 | require "enumerize" 8 | require "chartkick" 9 | require "groupdate" 10 | 11 | require "wordpress/backend/authorization" 12 | require "wordpress/backend/engine" 13 | require "wordpress/backend/paranoia/core" 14 | require "wordpress/backend/batch/dsl" 15 | require "wordpress/backend/state_machine/dsl" 16 | require "wordpress/backend/controller/active_admin_base" 17 | -------------------------------------------------------------------------------- /backend/lib/wordpress/backend/authorization.rb: -------------------------------------------------------------------------------- 1 | module Wordpress 2 | module Backend 3 | module Authorization 4 | CREATE_TICKET = :create_ticket 5 | PUBLISH = :publish 6 | DONE = :done 7 | IMPORT = :import 8 | end 9 | Auth = Authorization 10 | end 11 | end 12 | ::ActiveAdmin::Authorization.send(:include, Wordpress::Backend::Authorization) -------------------------------------------------------------------------------- /backend/lib/wordpress/backend/batch/dsl.rb: -------------------------------------------------------------------------------- 1 | module Wordpress 2 | module Backend 3 | module Batch 4 | module DSL 5 | def batch_action_model( model, action_options = {} ) 6 | model = model.to_s.camelize.constantize 7 | model.all.each do |item| 8 | batch_action item.name, action_options do |ids| 9 | i = 0 10 | batch_action_collection.find(ids).each do |source| 11 | target = model.find_by(id: item.id) 12 | i += 1 if source.batch_action(target) 13 | end 14 | options = { notice: I18n.t('active_admin.batch_action.succesfully_updated', count: i, model: resource_class.to_s.camelize.constantize.model_name, plural_model: resource_class.to_s.downcase.pluralize) } 15 | redirect_back({ fallback_location: ActiveAdmin.application.root_to }.merge(options)) 16 | end 17 | end 18 | end 19 | end 20 | end 21 | end 22 | end 23 | 24 | ::ActiveAdmin::DSL.send(:include, Wordpress::Backend::Batch::DSL) 25 | -------------------------------------------------------------------------------- /backend/lib/wordpress/backend/controller/active_admin_base.rb: -------------------------------------------------------------------------------- 1 | module Wordpress 2 | module Backend 3 | module Controller 4 | module Base 5 | def init_controller 6 | controller do 7 | before_action :set_time_zone, if: :current_admin_user 8 | private 9 | def set_time_zone 10 | Time.zone = current_admin_user.time_zone if current_admin_user.time_zone.present? 11 | end 12 | end 13 | sidebar :time_now, only: [:index] do 14 | dl do 15 | dt Time.zone 16 | dd Time.current 17 | end 18 | end 19 | end 20 | end 21 | end 22 | end 23 | end 24 | ::ActiveAdmin::DSL.send(:include, Wordpress::Backend::Controller::Base) 25 | -------------------------------------------------------------------------------- /backend/lib/wordpress/backend/engine.rb: -------------------------------------------------------------------------------- 1 | module Wordpress 2 | module Backend 3 | class Engine < ::Rails::Engine 4 | 5 | initializer "active_admin.load_app_path" do 6 | app_admin = File.expand_path("../../../app/admin", __dir__) 7 | ActiveAdmin.application.load_paths += Dir[app_admin] 8 | end 9 | 10 | initializer "active_admin.memu" do 11 | ActiveAdmin.setup do |config| 12 | config.namespace :admin do |admin| 13 | admin.build_menu :default do |menu| 14 | menu.add label: I18n.t("active_admin.sidekiq", default: "Sidekiq"), url: "/sidekiq", html_options: { target: :blank }, priority: 1000 15 | end 16 | end 17 | config.default_per_page = [20, 50, 100] 18 | config.download_links = [:csv, :json] 19 | end 20 | end 21 | 22 | def self.activate 23 | Dir.glob(File.join(File.dirname(__FILE__), '../../../app/**/*_decorator*.rb')).each do |c| 24 | Rails.configuration.cache_classes ? require(c) : load(c) 25 | end 26 | end 27 | 28 | config.to_prepare(&method(:activate).to_proc) 29 | end 30 | end 31 | end -------------------------------------------------------------------------------- /backend/lib/wordpress/backend/paranoia/authorization.rb: -------------------------------------------------------------------------------- 1 | module Wordpress 2 | module Backend 3 | module Paranoia 4 | # Default Authorization permission for ActiveAdmin::Paranoia 5 | module Authorization 6 | RESTORE = :restore 7 | PERMANENT_DELETE = :permanent_delete 8 | end 9 | 10 | Auth = Authorization 11 | end 12 | end 13 | end -------------------------------------------------------------------------------- /backend/lib/wordpress/backend/paranoia/core.rb: -------------------------------------------------------------------------------- 1 | 2 | require 'wordpress/backend/paranoia/dsl' 3 | require 'wordpress/backend/paranoia/authorization' 4 | ::ActiveAdmin::DSL.send(:include, Wordpress::Backend::Paranoia::DSL) -------------------------------------------------------------------------------- /backend/lib/wordpress/backend/state_machine/dsl.rb: -------------------------------------------------------------------------------- 1 | module Wordpress 2 | module Backend 3 | module StateMachine 4 | module DSL 5 | 6 | # 7 | # Easily tie into a state_machine action 8 | # 9 | # @param [Symbol] state machine event, ie: :publish 10 | # @param [Hash] options 11 | # - permission [Symbol] permission to check authorization against 12 | # - http_verb [Symbol] :put, :post, :get, etc 13 | # 14 | # Will call "resource.publish!", if "resource.can_publish?" returns true 15 | # 16 | 17 | def state_action(action, options={}, &controller_action) 18 | singular = config.resource_name.singular 19 | plural = config.resource_name.plural 20 | 21 | options[:permission] ||= controller.new.send(:action_to_permission, action) 22 | confirmation = options.fetch(:confirm, false) 23 | if confirmation == true 24 | default = "Are you sure you want to #{action.to_s.humanize.downcase}?" 25 | confirmation = ->{ I18n.t(:confirm, scope: "#{plural}.#{action}", default: default) } 26 | end 27 | 28 | http_verb = options.fetch :http_verb, :put 29 | 30 | action_item_args = if ActiveAdmin::VERSION.start_with?('0.') 31 | [{ only: :show }] 32 | else 33 | ["state_action_#{action}", { only: :show }] 34 | end 35 | action_item(*action_item_args) do 36 | if resource.send("can_#{action}?") && authorized?(options[:permission], resource) 37 | path = resource_path << "/#{action}" 38 | label = I18n.t("#{plural}.#{action}.label", default: action.to_s.titleize) 39 | 40 | link_options = {} 41 | if confirmation.is_a?(Proc) 42 | link_options[:data] ||= {} 43 | link_options[:data][:confirm] = instance_exec(&confirmation) 44 | end 45 | 46 | link_options[:class] = "btn btn-large" 47 | link_options[:method] = http_verb 48 | 49 | link_to label, path, link_options 50 | end 51 | end 52 | 53 | unless block_given? 54 | controller_action = -> do 55 | begin 56 | resource.send("#{action}!") 57 | rescue => e 58 | flash[:error] = t("#{plural}.#{action}.flash.errors", default: e.message) 59 | redirect_to smart_resource_url and return 60 | end 61 | flash[:notice] = t("#{plural}.#{action}.flash.success") 62 | redirect_to smart_resource_url 63 | end 64 | end 65 | 66 | member_action action, method: http_verb, &controller_action 67 | end 68 | end 69 | end 70 | end 71 | end 72 | 73 | ::ActiveAdmin::DSL.send(:include, Wordpress::Backend::StateMachine::DSL) 74 | -------------------------------------------------------------------------------- /backend/lib/wordpress_backend.rb: -------------------------------------------------------------------------------- 1 | require 'active_admin_import' 2 | require 'wordpress/backend' -------------------------------------------------------------------------------- /backend/test/backend_test.rb: -------------------------------------------------------------------------------- 1 | require "test_helper" 2 | 3 | class BackendTest < Minitest::Test 4 | def test_that_it_has_a_version_number 5 | refute_nil ::Backend::VERSION 6 | end 7 | 8 | def test_it_does_something_useful 9 | assert false 10 | end 11 | end 12 | -------------------------------------------------------------------------------- /backend/test/test_helper.rb: -------------------------------------------------------------------------------- 1 | $LOAD_PATH.unshift File.expand_path("../../lib", __FILE__) 2 | require "backend" 3 | 4 | require "minitest/autorun" 5 | -------------------------------------------------------------------------------- /backend/wordpress_backend.gemspec: -------------------------------------------------------------------------------- 1 | # Maintain your gem's version: 2 | require_relative '../core/lib/wordpress/core/version' 3 | 4 | Gem::Specification.new do |spec| 5 | spec.name = "wordpress_backend" 6 | spec.version = Wordpress::VERSION 7 | spec.authors = ["Sead Feng"] 8 | spec.email = ["seadfeng@gmail.com"] 9 | spec.homepage = "https://github.com/seadfeng/cloud_wordpress" 10 | spec.summary = "Cloud Wordpress Core" 11 | spec.description = "Wordpress Core" 12 | spec.license = "MIT" 13 | 14 | 15 | spec.files = Dir["{app,config,db,lib}/**/*", "MIT-LICENSE", "Rakefile", "README.md"] 16 | spec.require_path = 'lib' 17 | spec.requirements << 'none' 18 | 19 | spec.add_dependency "wordpress_core", spec.version 20 | spec.add_dependency "activeadmin" 21 | spec.add_dependency "activeadmin_addons" 22 | 23 | spec.add_dependency 'activerecord-import', '~> 0.27' 24 | spec.add_dependency "rchardet" 25 | 26 | spec.add_dependency "active_admin_role" 27 | spec.add_dependency "devise" 28 | spec.add_dependency "draper" 29 | spec.add_dependency "pundit" 30 | spec.add_dependency "chartkick" 31 | spec.add_dependency "groupdate" 32 | 33 | spec.add_dependency "enumerize", '~> 2.3.1' 34 | end 35 | -------------------------------------------------------------------------------- /core/Gemfile: -------------------------------------------------------------------------------- 1 | source 'https://rubygems.org' 2 | git_source(:github) { |repo| "https://github.com/#{repo}.git" } 3 | 4 | # Declare your gem's dependencies in wordpress_core.gemspec. 5 | # Bundler will treat runtime dependencies like base dependencies, and 6 | # development dependencies will be added by default to the :development group. 7 | gemspec 8 | 9 | # Declare any dependencies that are still in development here instead of in 10 | # your gemspec. These might include edge Rails or gems from your path or 11 | # Git. Remember to move these dependencies to your gemspec before releasing 12 | # your gem to rubygems.org. 13 | 14 | # To use a debugger 15 | # gem 'byebug', group: [:development, :test] -------------------------------------------------------------------------------- /core/Rakefile: -------------------------------------------------------------------------------- 1 | begin 2 | require 'bundler/setup' 3 | rescue LoadError 4 | puts 'You must `gem install bundler` and `bundle install` to run rake tasks' 5 | end 6 | 7 | require 'rdoc/task' 8 | 9 | RDoc::Task.new(:rdoc) do |rdoc| 10 | rdoc.rdoc_dir = 'rdoc' 11 | rdoc.title = 'Wordpress' 12 | rdoc.options << '--line-numbers' 13 | rdoc.rdoc_files.include('README.md') 14 | rdoc.rdoc_files.include('lib/**/*.rb') 15 | end 16 | 17 | require 'bundler/gem_tasks' 18 | 19 | require 'rake/testtask' 20 | 21 | Rake::TestTask.new(:test) do |t| 22 | t.libs << 'test' 23 | t.pattern = 'test/**/*_test.rb' 24 | t.verbose = false 25 | end 26 | 27 | task default: :test 28 | -------------------------------------------------------------------------------- /core/app/controllers/wordpress/api_controller.rb: -------------------------------------------------------------------------------- 1 | module Wordpress 2 | class ApiController < Wordpress::BaseController 3 | before_action :load_data 4 | 5 | def show 6 | auth_domain = request.headers["X-Auth-Domain"] 7 | request_uri = request.headers["Request-Uri"] 8 | forwarded_proto = request.headers["X-Forwarded-Proto"] 9 | subdomain = "#{auth_domain}".gsub!(/(.*)\.[^\.]*\.[^\.]*/,'\1') 10 | 11 | if subdomain.nil? 12 | root_domain = auth_domain 13 | else 14 | root_domain = auth_domain.gsub(/#{subdomain}\./,'') 15 | end 16 | 17 | domain = Wordpress::Domain.cache_by_name(root_domain) 18 | 19 | if @api && domain && blog = domain.blog_cache_by_subname(subdomain) 20 | uri = "#{blog.cloudflare_origin}#{request_uri}" 21 | 22 | if blog.published? 23 | @headers = { 24 | 'X-Forwarded-Host' => blog.origin, 25 | 'X-Forwarded-Proto' => forwarded_proto, 26 | 'User-Agent' => request.headers["User-Agent"], 27 | 'Cache-Control'=> request.headers["Cache-Control"], 28 | } 29 | 30 | client = rest_client(uri, request.method, request.query_parameters.to_json) 31 | if client 32 | response.status = client.code 33 | body = client.body 34 | if request_uri =~ /(\.jpg|\.jpeg)/i 35 | send_data(body, disposition:'inline', :type => 'image/jpeg') 36 | elsif request_uri =~ /(\.png)/i 37 | send_data(body, disposition:'inline', :type => 'image/png') 38 | elsif request_uri =~ /(\.gif)/i 39 | send_data(body, disposition:'inline', :type => 'image/gif') 40 | elsif request_uri =~ /(\.jpg)/i 41 | send_data(body, disposition:'inline', :type => 'image/jpg') 42 | elsif request_uri =~ /(\.ico)/i 43 | send_data(body, disposition:'inline', :type => 'image/x-icon') 44 | elsif request_uri =~ /(\.svg)/i 45 | send_data(body, disposition:'inline', :type => 'image/svg+xml') 46 | elsif request_uri =~ /(robots\.txt)/i 47 | render inline: "User-agent: *" 48 | else 49 | render inline: body 50 | end 51 | else 52 | render_404 53 | end 54 | # render inline: "#{@api.key}, #{request.method}, #{params}" 55 | else 56 | render_404 57 | end 58 | else 59 | render_404 60 | end 61 | 62 | end 63 | 64 | def code 65 | render layout: false, content_type: 'text/plain', locals: { api_url: wordpress.api_url, auth_key: @api.key } 66 | end 67 | 68 | private 69 | 70 | def rest_client( url, method, *options ) 71 | options = options.first || {} 72 | begin 73 | if method === "POST" 74 | RestClient.post url, options, @headers 75 | elsif method === "PUT" 76 | RestClient.put url, options, @headers 77 | else 78 | RestClient.get url, @headers 79 | end 80 | rescue RestClient::ExceptionWithResponse => e 81 | case e.http_code 82 | when 301, 302, 307 83 | e.response.follow_redirection 84 | else 85 | raise 86 | end 87 | end 88 | end 89 | 90 | def render_404 91 | response.status = 404 92 | body = "404" 93 | render inline: body 94 | end 95 | 96 | def load_data 97 | auth_key = request.headers["X-Auth-Key"] 98 | @api = Wordpress::ApiToken.api_token_cache(auth_key) 99 | if @api.blank? 100 | return render_404 101 | end 102 | end 103 | 104 | end 105 | end 106 | -------------------------------------------------------------------------------- /core/app/controllers/wordpress/base_controller.rb: -------------------------------------------------------------------------------- 1 | 2 | module Wordpress 3 | class BaseController < ApplicationController 4 | 5 | respond_to :html 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /core/app/controllers/wordpress/home_controller.rb: -------------------------------------------------------------------------------- 1 | module Wordpress 2 | class HomeController < Wordpress::BaseController 3 | 4 | def index 5 | puts Wordpress::Config 6 | render inline: "Ok" 7 | end 8 | 9 | end 10 | end -------------------------------------------------------------------------------- /core/app/controllers/wordpress/server_controller.rb: -------------------------------------------------------------------------------- 1 | module Wordpress 2 | class ServerController < Wordpress::BaseController 3 | 4 | def index 5 | if params[:os] == "v7" 6 | install_os7_apache_php74 7 | elsif params[:os] == "v8" 8 | install_os8_apache_php74 9 | else 10 | render inline: "# v7 or v8", layout: false, content_type: 'text/plain' 11 | end 12 | end 13 | 14 | def mysql 15 | if params[:os] == "v7" 16 | install_os7_mysqlv8 17 | elsif params[:os] == "v8" 18 | install_os8_mysqlv8 19 | else 20 | render inline: "# v7 or v8", layout: false, content_type: 'text/plain' 21 | end 22 | end 23 | 24 | private 25 | 26 | def install_os7_mysqlv8 27 | render "wordpress/server/install_os7_mysqlv8", layout: false, content_type: 'text/plain' 28 | end 29 | 30 | def install_os8_mysqlv8 31 | render "wordpress/server/install_os8_mysqlv8", layout: false, content_type: 'text/plain' 32 | end 33 | 34 | def install_os7_apache_php74 35 | render "wordpress/server/install_os7_apache_php74", layout: false, content_type: 'text/plain' 36 | end 37 | 38 | def install_os8_apache_php74 39 | render "wordpress/server/install_os8_apache_php74", layout: false, content_type: 'text/plain' 40 | end 41 | 42 | end 43 | end 44 | -------------------------------------------------------------------------------- /core/app/helpers/wordpress/base_helper.rb: -------------------------------------------------------------------------------- 1 | module Wordpress 2 | module BaseHelper 3 | end 4 | end -------------------------------------------------------------------------------- /core/app/jobs/wordpress/blog_check_online_job.rb: -------------------------------------------------------------------------------- 1 | module Wordpress 2 | class BlogCheckOnlineJob < ApplicationJob 3 | queue_as :default 4 | sidekiq_options retry: 3 5 | attr_reader :blog 6 | 7 | def perform(blog) 8 | begin 9 | cli = RestClient.get blog.online_origin 10 | blog.update_attribute(:status, cli.code) 11 | rescue RestClient::ExceptionWithResponse => e 12 | blog.update_attribute(:status, blog.http_code) if blog.http_code 13 | case e.http_code 14 | when 301, 302, 307 15 | e.response.follow_redirection 16 | else 17 | raise 18 | end 19 | end 20 | end 21 | 22 | private 23 | 24 | def log_file 25 | File.open('log/wordpress_check_job.log', File::WRONLY | File::APPEND | File::CREAT) 26 | end 27 | 28 | end 29 | end -------------------------------------------------------------------------------- /core/app/jobs/wordpress/blog_job.rb: -------------------------------------------------------------------------------- 1 | require 'wordpress/core/helpers/apache' 2 | require 'wordpress/core/helpers/mysql' 3 | module Wordpress 4 | class BlogJob < ApplicationJob 5 | queue_as :wordpress 6 | sidekiq_options retry: 3 7 | attr_reader :blog 8 | 9 | def perform(blog) 10 | RestClient.get url 11 | end 12 | 13 | private 14 | 15 | def log_file 16 | # To create new (and to remove old) logfile, add File::CREAT like; 17 | # file = open('foo.log', File::WRONLY | File::APPEND | File::CREAT) 18 | File.open('log/wordpress_job.log', File::WRONLY | File::APPEND | File::CREAT) 19 | end 20 | 21 | end 22 | end -------------------------------------------------------------------------------- /core/app/jobs/wordpress/blog_reset_password_job.rb: -------------------------------------------------------------------------------- 1 | module Wordpress 2 | class BlogResetPasswordJob < Wordpress::BlogJob 3 | 4 | def perform(blog) 5 | logger = Logger.new(log_file) 6 | begin 7 | server = blog.server 8 | mysql_info = { 9 | # user: blog.mysql_user, 10 | # user_host: server.mysql_host_user , 11 | # user_password: blog.mysql_password, 12 | database: blog.mysql_db, 13 | collection_user: blog.mysql_user, 14 | collection_password: blog.mysql_password, 15 | collection_host: server.mysql_host 16 | } 17 | mysql = Wordpress::Core::Helpers::Mysql.new(mysql_info) 18 | Net::SSH.start( server.host, server.host_user, :password => server.host_password, :port => server.host_port) do |ssh| 19 | logger.info("ssh connected") 20 | channel = ssh.open_channel do |ch| 21 | ch.exec "#{mysql.only_update_password(blog.password, blog.user)}" do |ch, success| 22 | logger.info("#{mysql.only_update_password(blog.password, blog.user)}") 23 | ch.on_data do |c, data| 24 | $stdout.print data 25 | if /^#{mysql_info[:database]}$/.match(data) 26 | logger.info("Database checked: #{mysql_info[:database]}") 27 | logger.info("Password has Updated!") 28 | end 29 | end 30 | end 31 | end 32 | channel.wait 33 | end 34 | rescue Exception, ActiveJob::DeserializationError => e 35 | logger.error("Blog Id:#{blog.id} ================") 36 | logger.error(I18n.t('active_admin.active_job', message: e.message, default: "ActiveJob: #{e.message}")) 37 | logger.error(e.backtrace.join("\n")) 38 | nil 39 | end 40 | 41 | end 42 | 43 | private 44 | 45 | def log_file 46 | # To create new (and to remove old) logfile, add File::CREAT like; 47 | # file = open('foo.log', File::WRONLY | File::APPEND | File::CREAT) 48 | File.open('log/wordpress_reset_password_job.log', File::WRONLY | File::APPEND | File::CREAT) 49 | end 50 | 51 | end 52 | end -------------------------------------------------------------------------------- /core/app/jobs/wordpress/domain_import_job.rb: -------------------------------------------------------------------------------- 1 | module Wordpress 2 | class DomainImportJob < ApplicationJob 3 | queue_as :default 4 | sidekiq_options retry: 3 5 | attr_reader :page, :total_pages, :next_page, :result 6 | 7 | def perform(page) 8 | @page = page 9 | cloudflare = { 10 | api_user: Wordpress::Config.api_user, 11 | api_token: Wordpress::Config.api_token, 12 | } 13 | cloudflare_api = Wordpress::Core::Helpers::CloudflareApi.new(cloudflare) 14 | body = cloudflare_api.list_all_zone(page) 15 | if body["success"] 16 | @total_pages = body["result_info"]["total_pages"] 17 | @result = body["result"] 18 | @result.each do |zone| 19 | Domain.find_or_create( name: zone["name"] ) 20 | end 21 | if page < @total_pages 22 | @next_page = @total_pages - page 23 | Wordpress::DomainImportJob.perform_later(@next_page) 24 | end 25 | end 26 | end 27 | 28 | private 29 | 30 | def log_file 31 | # To create new (and to remove old) logfile, add File::CREAT like; 32 | # file = open('foo.log', File::WRONLY | File::APPEND | File::CREAT) 33 | File.open('log/domain_job.log', File::WRONLY | File::APPEND | File::CREAT) 34 | end 35 | 36 | end 37 | end -------------------------------------------------------------------------------- /core/app/jobs/wordpress/domain_job.rb: -------------------------------------------------------------------------------- 1 | module Wordpress 2 | class DomainJob < ApplicationJob 3 | queue_as :default 4 | sidekiq_options retry: 3 5 | attr_reader :domain, :options, :config 6 | 7 | def perform(domain, *options) 8 | @domain = domain 9 | @config = Wordpress::Config 10 | @options = options.first || {} 11 | if (@options[:action] == "find_or_create_zone" || @options[:action] == :find_or_create_zone) 12 | find_or_create_zone 13 | elsif ( @options[:action] == "find_zone" || @options[:action] == :find_zone) 14 | find_zone 15 | elsif ( @options[:action] == "create_zone" || @options[:action] == :create_zone) 16 | create_zone 17 | end 18 | end 19 | 20 | private 21 | 22 | def find_or_create_zone 23 | return find_zone if find_zone 24 | if create_zone 25 | find_zone 26 | end 27 | end 28 | 29 | def find_zone 30 | if config.cfp_enable 31 | api = cloudflare_api 32 | zone_id = api.find_zone( domain.name ) 33 | domain.update_attribute(:zone_id, zone_id) unless zone_id.blank? 34 | end 35 | end 36 | 37 | def create_zone 38 | data = { 39 | :domain => domain.name, 40 | :submit => '' 41 | } 42 | 43 | url = "#{config.cfp_site}/?action=add" 44 | 45 | cookies = { 46 | :user_api_key => config.cfp_token, 47 | :user_key => config.cfp_user_key, 48 | :cloudflare_email => config.cfp_user 49 | } 50 | client = RestClient::Request.execute url: url, method: :post, payload: data, :cookies => cookies, :headers => { :"Content-Type" => "application/x-www-form-urlencoded" } 51 | if client && client.code == 200 52 | if /Go to console/.match( client.body ) 53 | ActiveAdmin::Comment.create( 54 | resource_type: "Wordpress::Domain", 55 | resource_id: domain.id, 56 | author_type: "AdminUser", 57 | author_id: AdminUser.where(role: "admin")&.first&.id, 58 | body: "成功添加域名到Cloudflare Partner", 59 | namespace: "admin" 60 | ) 61 | else 62 | ActiveAdmin::Comment.create( 63 | namespace: "admin", 64 | resource_type: "Wordpress::Domain", 65 | resource_id: domain.id, 66 | author_type: "AdminUser", 67 | author_id: AdminUser.where(role: "admin")&.first&.id, 68 | body: "CloudFlare is already activated for \"#{domain.name}\" under a different account. If you want to enable CloudFlare through this partner, please log in to your CloudFlare account and choose \"Disconnect\" on your CloudFlare DNS Settings page." 69 | ) 70 | end 71 | end 72 | end 73 | 74 | 75 | def cloudflare_api 76 | cfp_cloudflare = { 77 | api_user: config.cfp_user, 78 | api_token: config.cfp_token 79 | } 80 | Wordpress::Core::Helpers::CloudflareApi.new(cfp_cloudflare) 81 | end 82 | 83 | def log_file 84 | # To create new (and to remove old) logfile, add File::CREAT like; 85 | # file = open('foo.log', File::WRONLY | File::APPEND | File::CREAT) 86 | File.open('log/domain_job.log', File::WRONLY | File::APPEND | File::CREAT) 87 | end 88 | 89 | end 90 | end -------------------------------------------------------------------------------- /core/app/jobs/wordpress/proxy_check_job.rb: -------------------------------------------------------------------------------- 1 | module Wordpress 2 | class ProxyCheckJob < ApplicationJob 3 | queue_as :wordpress 4 | sidekiq_options retry: 3 5 | attr_reader :proxy 6 | 7 | def perform(proxy) 8 | begin 9 | if proxy.connection_type == "SSH" 10 | Net::SSH.start(proxy.host, proxy.user, :password => proxy.password, :port => proxy.port ) do |ssh| 11 | proxy.status = 1 12 | proxy.save 13 | end 14 | else 15 | proxy.status = 0 16 | proxy.save 17 | nil 18 | end 19 | rescue Exception => e 20 | proxy.status = 0 21 | proxy.save 22 | logger = Logger.new(log_file) 23 | logger.error("Proxy Id:#{proxy.id} ================") 24 | logger.error(I18n.t('active_admin.active_job', message: e.message, default: "ActiveJob: #{e.message}")) 25 | logger.error(e.backtrace.join("\n")) 26 | if /fingerprint/.match(e.message) 27 | system("sed -i \"/#{proxy.host}/d\" .ssh/known_hosts") 28 | end 29 | nil 30 | end 31 | end 32 | 33 | private 34 | 35 | def log_file 36 | File.open('log/proxy_job.log', File::WRONLY | File::APPEND | File::CREAT) 37 | end 38 | 39 | end 40 | end -------------------------------------------------------------------------------- /core/app/jobs/wordpress/proxy_install_job.rb: -------------------------------------------------------------------------------- 1 | 2 | module Wordpress 3 | class ProxyInstallJob < ApplicationJob 4 | include Wordpress::Routeable 5 | queue_as :wordpress 6 | sidekiq_options retry: 3 7 | attr_reader :proxy, :host 8 | 9 | def perform(proxy,host = nil) 10 | @host = host 11 | logger = Logger.new(log_file) 12 | logger.info("Proxy Id:#{proxy.id} ================") 13 | begin 14 | Net::SSH.start(proxy.host, proxy.user, :password => proxy.password, :port => proxy.port) do |ssh| 15 | logger.info("SSH connected") 16 | centos_ver = 0 17 | channela = ssh.open_channel do |ch| 18 | ch.exec "rpm --eval '%{centos_ver}'" do |ch, success| 19 | if success 20 | ch.on_data do |c, data| 21 | $stdout.print data 22 | centos_ver = data 23 | end 24 | end 25 | end 26 | end 27 | channela.wait 28 | logger.info("Centos #{centos_ver}") 29 | ssh_exec = "" 30 | if centos_ver.to_i == 7 31 | ssh_exec = "curl -o- -L #{server_url("v7")} | sh" 32 | elsif centos_ver.to_i == 8 33 | ssh_exec = "curl -o- -L #{server_url("v8")} | sh" 34 | end 35 | unless ssh_exec.blank? 36 | channel = ssh.open_channel do |ch| 37 | logger.info("SSH Exec:#{ssh_exec}") 38 | ch.exec ssh_exec do |ch, success| 39 | if success 40 | ch.on_data do |c, data| 41 | $stdout.print data 42 | if /Install OK/.match(data) 43 | logger.info("Install OK") 44 | proxy.installed_at = Time.now 45 | proxy.save 46 | end 47 | end 48 | end 49 | end 50 | end 51 | channel.wait 52 | else 53 | nil 54 | end 55 | end 56 | rescue Exception, ActiveJob::DeserializationError => e 57 | logger.error("Proxy Id:#{proxy.id} ================") 58 | logger.error(I18n.t('active_admin.active_job', message: e.message, default: "ActiveJob: #{e.message}")) 59 | logger.error(e.backtrace.join("\n")) 60 | nil 61 | end 62 | end 63 | 64 | protected 65 | 66 | def default_url_options 67 | host || Rails.application.config.active_job.default_url_options || {} 68 | end 69 | 70 | private 71 | 72 | def log_file 73 | # To create new (and to remove old) logfile, add File::CREAT like; 74 | # file = open('foo.log', File::WRONLY | File::APPEND | File::CREAT) 75 | File.open('log/proxy_install_job.log', File::WRONLY | File::APPEND | File::CREAT) 76 | end 77 | 78 | end 79 | end -------------------------------------------------------------------------------- /core/app/jobs/wordpress/server_job.rb: -------------------------------------------------------------------------------- 1 | 2 | module Wordpress 3 | class ServerJob < ApplicationJob 4 | include Wordpress::Routeable 5 | queue_as :wordpress 6 | sidekiq_options retry: 3 7 | attr_reader :server, :host 8 | 9 | def perform(server,host = nil) 10 | @host = host 11 | logger = Logger.new(log_file) 12 | logger.info("Sever Id:#{server.id} ================") 13 | begin 14 | Net::SSH.start(server.host, server.host_user, :password => server.host_password, :port => server.host_port) do |ssh| 15 | logger.info("SSH connected") 16 | centos_ver = 0 17 | channela = ssh.open_channel do |ch| 18 | ch.exec "rpm --eval '%{centos_ver}'" do |ch, success| 19 | if success 20 | ch.on_data do |c, data| 21 | $stdout.print data 22 | centos_ver = data 23 | end 24 | end 25 | end 26 | end 27 | channela.wait 28 | logger.info("Centos #{centos_ver}") 29 | ssh_exec = "" 30 | if centos_ver.to_i == 7 31 | ssh_exec = "curl -o- -L #{server_url("v7")} | sh" 32 | elsif centos_ver.to_i == 8 33 | ssh_exec = "curl -o- -L #{server_url("v8")} | sh" 34 | end 35 | unless ssh_exec.blank? 36 | channel = ssh.open_channel do |ch| 37 | logger.info("SSH Exec:#{ssh_exec}") 38 | ch.exec ssh_exec do |ch, success| 39 | if success 40 | ch.on_data do |c, data| 41 | $stdout.print data 42 | if /Install OK/.match(data) 43 | logger.info("Install OK") 44 | server.installed = 1 45 | server.save 46 | end 47 | end 48 | end 49 | end 50 | end 51 | channel.wait 52 | else 53 | nil 54 | end 55 | end 56 | rescue Exception, ActiveJob::DeserializationError => e 57 | logger.error("Sever Id:#{server.id} ================") 58 | logger.error(I18n.t('active_admin.active_job', message: e.message, default: "ActiveJob: #{e.message}")) 59 | logger.error(e.backtrace.join("\n")) 60 | nil 61 | end 62 | end 63 | 64 | protected 65 | 66 | def default_url_options 67 | host || Rails.application.config.active_job.default_url_options || {} 68 | end 69 | 70 | private 71 | 72 | def log_file 73 | # To create new (and to remove old) logfile, add File::CREAT like; 74 | # file = open('foo.log', File::WRONLY | File::APPEND | File::CREAT) 75 | File.open('log/server_job.log', File::WRONLY | File::APPEND | File::CREAT) 76 | end 77 | 78 | end 79 | end -------------------------------------------------------------------------------- /core/app/jobs/wordpress/template_job.rb: -------------------------------------------------------------------------------- 1 | require 'wordpress/core/helpers/mysql' 2 | module Wordpress 3 | class TemplateJob < ApplicationJob 4 | queue_as :wordpress 5 | sidekiq_options retry: 3 6 | attr_reader :template 7 | 8 | def perform(template) 9 | @template = template 10 | end 11 | 12 | private 13 | 14 | def log_file 15 | # To create new (and to remove old) logfile, add File::CREAT like; 16 | # file = open('foo.log', File::WRONLY | File::APPEND | File::CREAT) 17 | File.open('log/template_job.log', File::WRONLY | File::APPEND | File::CREAT) 18 | end 19 | 20 | end 21 | end -------------------------------------------------------------------------------- /core/app/jobs/wordpress/template_reset_password_job.rb: -------------------------------------------------------------------------------- 1 | module Wordpress 2 | class TemplateResetPasswordJob < Wordpress::TemplateJob 3 | 4 | def perform(template) 5 | 6 | begin 7 | config = Wordpress::Config 8 | mysql_info = { user: template.mysql_user, 9 | user_host: config.template_mysql_host , 10 | user_password: template.mysql_password, 11 | database: template.mysql_user, 12 | collection_user: template.mysql_user, 13 | collection_password: template.mysql_password, 14 | collection_host: config.template_mysql_connection_host } 15 | mysql = Wordpress::Core::Helpers::Mysql.new(mysql_info) 16 | 17 | logger = Logger.new(log_file) 18 | logger.info("Template Id:#{template.id} --------") 19 | 20 | Net::SSH.start( config.template_host, config.template_host_user, :password => config.template_host_password, :port => config.template_host_port) do |ssh| 21 | 22 | logger.info("ssh connected") 23 | 24 | channel = ssh.open_channel do |ch| 25 | ch.exec "#{mysql.only_update_password(template.wordpress_password, template.wordpress_user)}" do |ch, success| 26 | ch.on_data do |c, data| 27 | $stdout.print data 28 | logger.info("Database checked: #{mysql_info[:database]}") if /^#{mysql_info[:database]}$/.match(data) 29 | end 30 | end 31 | end 32 | channel.wait 33 | 34 | end 35 | 36 | rescue Exception, ActiveJob::DeserializationError => e 37 | logger = Logger.new(log_file) 38 | logger.error("Template Id:#{template.id} ================") 39 | logger.error(I18n.t('active_admin.active_job', message: e.message, default: "ActiveJob: #{e.message}")) 40 | logger.error(e.backtrace.join("\n")) 41 | nil 42 | end 43 | 44 | end 45 | 46 | private 47 | 48 | def log_file 49 | # To create new (and to remove old) logfile, add File::CREAT like; 50 | # file = open('foo.log', File::WRONLY | File::APPEND | File::CREAT) 51 | File.open('log/template_reset_password_job.log', File::WRONLY | File::APPEND | File::CREAT) 52 | end 53 | 54 | end 55 | end -------------------------------------------------------------------------------- /core/app/jobs/wordpress/template_tar_job.rb: -------------------------------------------------------------------------------- 1 | module Wordpress 2 | class TemplateTarJob < Wordpress::TemplateJob 3 | 4 | def perform(template) 5 | logger = Logger.new(log_file) 6 | begin 7 | logger.info("Template Id:#{template.id} ================") 8 | config = Wordpress::Config 9 | directory = "#{config.template_directory}/#{template.id}" 10 | mysql_info = { 11 | database: template.database, 12 | collection_user: template.mysql_user, 13 | collection_password: template.mysql_password, 14 | collection_host: config.template_mysql_connection_host 15 | } 16 | mysql = Wordpress::Core::Helpers::Mysql.new(mysql_info) 17 | Net::SSH.start( config.template_host, config.template_host_user, :password => config.template_host_password, :port => config.template_host_port ) do |ssh| 18 | logger.info("ssh connected") 19 | channel = ssh.open_channel do |ch| 20 | ssh_exec = "cd #{directory} && #{mysql.dump_mysql} && tar cjf #{template.template_tar_file} #{mysql_info[:database]}.sql wordpress" 21 | logger.info("#{ssh_exec}") 22 | ch.exec ssh_exec do |ch, success| 23 | ch.on_data do |c, data| 24 | $stdout.print data 25 | end 26 | end 27 | end 28 | channel.wait 29 | end 30 | rescue Exception, ActiveJob::DeserializationError => e 31 | logger.error("Template Id:#{template.id} ================") 32 | logger.error(I18n.t('active_admin.active_job', message: e.message, default: "ActiveJob: #{e.message}")) 33 | logger.error(e.backtrace.join("\n")) 34 | nil 35 | end 36 | 37 | end 38 | 39 | private 40 | 41 | def log_file 42 | # To create new (and to remove old) logfile, add File::CREAT like; 43 | # file = open('foo.log', File::WRONLY | File::APPEND | File::CREAT) 44 | File.open('log/template_tar_job.log', File::WRONLY | File::APPEND | File::CREAT) 45 | end 46 | 47 | end 48 | end -------------------------------------------------------------------------------- /core/app/models/concerns/wordpress/number_generator.rb: -------------------------------------------------------------------------------- 1 | module Wordpress 2 | class NumberGenerator < Module 3 | extend ActiveSupport::Concern 4 | BASE = 10 5 | DEFAULT_LENGTH = 9 6 | 7 | attr_accessor :prefix, :length 8 | 9 | def initialize(options) 10 | @prefix = options.fetch(:prefix) 11 | @length = options.fetch(:length, DEFAULT_LENGTH) 12 | @letters = options[:letters] 13 | end 14 | 15 | def included(host) 16 | generator_method = method(:generate_permalink) 17 | generator_instance = self 18 | 19 | host.class_eval do 20 | validates_uniqueness_of :number, presence: true 21 | before_validation do |instance| 22 | instance.number ||= generator_method.call(host) 23 | end 24 | 25 | define_singleton_method(:number_generator) { generator_instance } 26 | end 27 | end 28 | 29 | private 30 | 31 | def generate_permalink(host) 32 | length = @length 33 | 34 | loop do 35 | candidate = new_candidate(length) 36 | return candidate unless host.exists?(number: candidate) 37 | 38 | # If over half of all possible options are taken add another digit. 39 | length += 1 if host.count > Rational(BASE**length, 2) 40 | end 41 | end 42 | 43 | def new_candidate(length) 44 | characters = @letters ? 36 : 10 45 | @prefix + SecureRandom.random_number(characters**length).to_s(characters).rjust(length, '0').upcase 46 | end 47 | end 48 | end -------------------------------------------------------------------------------- /core/app/models/concerns/wordpress/routeable.rb: -------------------------------------------------------------------------------- 1 | module Wordpress 2 | module Routeable 3 | extend ActiveSupport::Concern 4 | 5 | included do 6 | include Wordpress::Core::Engine.routes.url_helpers 7 | end 8 | 9 | protected 10 | 11 | def default_url_options 12 | Rails.application.routes.default_url_options || {} 13 | end 14 | end 15 | end -------------------------------------------------------------------------------- /core/app/models/concerns/wordpress/validates.rb: -------------------------------------------------------------------------------- 1 | module Wordpress 2 | module Validates 3 | extend ActiveSupport::Concern 4 | 5 | class EmailValidator < ActiveModel::EachValidator 6 | def validate_each(record, attribute, value) 7 | unless value =~ /\A([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})\z/i 8 | record.errors[attribute] << (options[:message] || "is not an email") 9 | end 10 | end 11 | end 12 | 13 | class UrlValidator < ActiveModel::EachValidator 14 | def validate_each(record, attribute, value) 15 | unless value =~ URI::regexp 16 | record.errors[attribute] << (options[:message] || "is not an url") 17 | end 18 | end 19 | end 20 | 21 | class DomainValidator < ActiveModel::EachValidator 22 | def validate_each(record, attribute, value) 23 | unless value =~ /\A([^\/]*\.[^\/]*)\z/i 24 | record.errors[attribute] << (options[:message] || I18n.t("activerecord.errors.models.site.attributes.origin.validator" , default: "域名有误")) 25 | end 26 | end 27 | end 28 | 29 | class RedirectUrlValidator < ActiveModel::EachValidator 30 | def validate_each(record, attribute, value) 31 | unless value =~ /\A(^\/.*)\z/i 32 | record.errors[attribute] << (options[:message] || I18n.t("activerecord.errors.models.site.attributes.redirect_url.validator" , default: "必须'/'开头的站内链接")) 33 | end 34 | end 35 | end 36 | end 37 | end 38 | -------------------------------------------------------------------------------- /core/app/models/wordpress/api_token.rb: -------------------------------------------------------------------------------- 1 | 2 | module Wordpress 3 | class ApiToken < Wordpress::Base 4 | include Wordpress::Core::TokenGenerator 5 | acts_as_paranoid 6 | before_validation :set_token 7 | 8 | with_options presence: true do 9 | validates_uniqueness_of :key, allow_blank: false 10 | validates :name 11 | end 12 | 13 | after_commit :clear_cache 14 | 15 | 16 | def self.api_token_cache(token) 17 | # find_api_token = ApiToken.find_by_key(token) 18 | # return nil if find_api_token.blank? 19 | find_api_token = Rails.cache.fetch("api_token_key_#{token}") do 20 | ApiToken.find_by_key(token) 21 | end 22 | 23 | if find_api_token.blank? 24 | Rails.cache.delete( "api_token_key_#{token}" ) 25 | else 26 | find_api_token 27 | end 28 | 29 | end 30 | 31 | def clear_cache 32 | Rails.cache.delete( "api_token_key_#{self.key}" ) 33 | end 34 | 35 | private 36 | 37 | def set_token 38 | self.key = generate_token if self.key.blank? 39 | end 40 | 41 | end 42 | end 43 | -------------------------------------------------------------------------------- /core/app/models/wordpress/app_configuration.rb: -------------------------------------------------------------------------------- 1 | module Wordpress 2 | class AppConfiguration < Preferences::Configuration 3 | 4 | preference :server_directory, :string, default: '/home/deploy/wwwroot/' 5 | 6 | preference :template_origin, :string, default: 'http://localhost/' 7 | preference :template_host, :string, default: '127.0.0.1' 8 | preference :template_host_port, :integer, default: 22 9 | preference :template_host_user, :string, default: 'root' 10 | preference :template_host_password, :string, default: '' 11 | preference :template_directory, :string, default: '/home/deploy/wwwroot/' 12 | 13 | # Mysql 14 | preference :template_mysql_connection_host, :string, default: '127.0.0.1' 15 | preference :template_mysql_host, :string, default: '127.0.0.1' 16 | preference :template_mysql_host_port, :integer, default: 3306 17 | preference :template_mysql_host_user, :string, default: '' 18 | preference :template_mysql_host_password, :string, default: '' 19 | 20 | ## Cloudflare Partner User Api 21 | 22 | preference :cfp_site, :string, default: 'https://dns.advertcn.com' 23 | preference :cfp_user, :string, default: '' 24 | preference :cfp_token, :string, default: '' 25 | preference :cfp_user_key, :string, default: '' 26 | preference :cfp_account_id, :string, default: '' 27 | preference :cfp_user_id, :string, default: '' 28 | preference :cfp_all_in_one_cname, :string, default: '' 29 | preference :cfp_enable, :boolean, default: 0 30 | 31 | 32 | 33 | 34 | end 35 | end -------------------------------------------------------------------------------- /core/app/models/wordpress/auth_configuration.rb: -------------------------------------------------------------------------------- 1 | module Wordpress 2 | class AuthConfiguration < Preferences::Configuration 3 | 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /core/app/models/wordpress/base.rb: -------------------------------------------------------------------------------- 1 | module Wordpress 2 | class Base < ApplicationRecord 3 | include Wordpress::Preferences::Preferable 4 | serialize :preferences, Hash 5 | 6 | after_initialize do 7 | if has_attribute?(:preferences) && !preferences.nil? 8 | self.preferences = default_preferences.merge(preferences) 9 | end 10 | end 11 | 12 | self.abstract_class = true 13 | 14 | def self.belongs_to_required_by_default 15 | false 16 | end 17 | 18 | def self.wordpress_base_scopes 19 | where(nil) 20 | end 21 | end 22 | end -------------------------------------------------------------------------------- /core/app/models/wordpress/blog/mysql_connect.rb: -------------------------------------------------------------------------------- 1 | module Wordpress 2 | class Blog < Wordpress::Base 3 | module MysqlConnect 4 | extend ActiveSupport::Concern 5 | included do 6 | def post_publish_count 7 | mysql2.post_status('publish') 8 | end 9 | 10 | private 11 | 12 | def mysql2 13 | Wordpress::Core::Helpers::Mysql2Client.new( 14 | :host => server.mysql_host, 15 | :password => server.mysql_password, 16 | :username => server.mysql_user, 17 | :database => self.installed? ? self.mysql_db : nil , 18 | :port => server.mysql_port 19 | ) 20 | end 21 | 22 | end 23 | end 24 | end 25 | end -------------------------------------------------------------------------------- /core/app/models/wordpress/blog/scope.rb: -------------------------------------------------------------------------------- 1 | module Wordpress 2 | class Blog < Wordpress::Base 3 | module Scope 4 | extend ActiveSupport::Concern 5 | included do 6 | scope :by_states, lambda { |status| where( "#{Blog.table_name}.state": status) unless status.blank? } 7 | scope :processing, -> { by_states("processing") } 8 | scope :pending, -> { by_states("pending") } 9 | scope :installed, -> { by_states("installed") } 10 | scope :published, -> { by_states("published") } 11 | scope :done, -> { by_states("done") } 12 | 13 | scope :ssl_on, -> { where("#{Blog.quoted_table_name}.use_ssl = ?", 1 ) } 14 | scope :ssl_off, -> { where("#{Blog.quoted_table_name}.use_ssl = ?", 0 ) } 15 | scope :published_today , -> { where("#{Blog.quoted_table_name}.published_at >= ?", Date.today ) } 16 | scope :published_month , -> { where("#{Blog.quoted_table_name}.published_at >= ?", Date.today - 30 ) } 17 | scope :cname_null, -> { where("#{Blog.quoted_table_name}.cname is NOT NULL" ) } 18 | end 19 | end 20 | end 21 | end -------------------------------------------------------------------------------- /core/app/models/wordpress/blog/state_machine.rb: -------------------------------------------------------------------------------- 1 | module Wordpress 2 | class Blog < Wordpress::Base 3 | module StateMachine 4 | extend ActiveSupport::Concern 5 | included do 6 | extend Enumerize 7 | enumerize :state, in: [:pending, :pending_migration, :processing, :installed, :done, :published], default: :pending 8 | state_machine :state, initial: :pending do 9 | # before_transition [:pending ] => :processing, :do => :send_job 10 | before_transition [:processing ] => :installed, :do => :touch_installed_at 11 | before_transition [:done ] => :published, :do => :touch_published_at 12 | 13 | event :install do 14 | transition [:pending, :pending_migration] => :processing 15 | end 16 | 17 | event :processed do 18 | transition [:processing] => :installed 19 | end 20 | 21 | event :has_done do 22 | transition [:installed] => :done 23 | end 24 | 25 | event :error do 26 | transition [:processing] => :pending 27 | end 28 | 29 | event :publish do 30 | transition [:done] => :published 31 | end 32 | 33 | state :pending 34 | state :pending_migration 35 | 36 | state :processing do 37 | validate :validate_server_and_cloudflare 38 | end 39 | state :installed 40 | state :done 41 | state :published do 42 | validate :validate_published 43 | end 44 | end 45 | 46 | def validate_server_and_cloudflare 47 | errors.add(:state, :cannot_install_if_none_server) if server.blank? 48 | errors.add(:state, :cannot_install_if_none_cloudflare) if cloudflare.blank? 49 | end 50 | 51 | def validate_published 52 | errors.add(:state, :cannot_published_if_none_domain) if domain.blank? 53 | end 54 | 55 | private 56 | 57 | # def send_job 58 | # Wordpress::BlogInstallJob.perform_later(self) 59 | # end 60 | 61 | def touch_installed_at 62 | update_attribute(:installed_at, Time.current) 63 | self.set_dns 64 | end 65 | 66 | def touch_published_at 67 | update_attribute(:published_at, Time.current) 68 | self.set_online_dns 69 | # self.create_online_virtual_host 70 | end 71 | end 72 | end 73 | end 74 | end -------------------------------------------------------------------------------- /core/app/models/wordpress/blog/wp_config.rb: -------------------------------------------------------------------------------- 1 | module Wordpress 2 | class Blog < Wordpress::Base 3 | module WpConfig 4 | extend ActiveSupport::Concern 5 | 6 | included do 7 | def update_wp_config 8 | logger = Logger.new(log_file) 9 | begin 10 | Net::SSH.start( server.host, server.host_user, :password => server.host_password) do |ssh| 11 | logger.info("Blog Id:#{self.id} Start! ********************************/") 12 | logger.info("SSH Connected: #{server.host}") 13 | ssh_str = " 14 | #{config_replace_db} 15 | #{config_replace_user} 16 | #{config_replace_db_password} 17 | #{config_replace_db_host} 18 | grep '#{self.mysql_password}' #{directory_wordpress_config} 19 | " 20 | channel = ssh.open_channel do |ch| 21 | puts ssh_str 22 | ch.exec ssh_str do |ch, success| 23 | ch.on_data do |c, data| 24 | $stdout.print data 25 | if /#{self.mysql_password}/.match(data) 26 | logger.info("wp-config.php updated!") 27 | end 28 | end 29 | end 30 | end 31 | channel.wait 32 | logger.info("Blog Id:#{self.id} End! ********************************/") 33 | end 34 | rescue Exception => e 35 | logger.error("Blog Id:#{self.id} ================") 36 | logger.error(e.backtrace.join("\n")) 37 | nil 38 | end 39 | end 40 | 41 | private 42 | 43 | def config_replace_db 44 | "sed -i \"/'DB_NAME'/ c define( 'DB_NAME', '#{mysql_db}' );\" #{directory_wordpress_config}" 45 | end 46 | 47 | def config_replace_user 48 | "sed -i \"/'DB_USER'/ c define( 'DB_USER', '#{self.mysql_user}' );\" #{directory_wordpress_config}" 49 | end 50 | 51 | def config_replace_db_password 52 | "sed -i \"/'DB_PASSWORD'/ c define( 'DB_PASSWORD', '#{self.mysql_password}' );\" #{directory_wordpress_config}" 53 | end 54 | 55 | def config_replace_db_host 56 | "sed -i \"/'DB_HOST'/ c define( 'DB_HOST', '#{server.mysql_host}' );\" #{directory_wordpress_config}" 57 | end 58 | 59 | def directory_wordpress 60 | "#{directory}/wordpress" 61 | end 62 | 63 | def directory_wordpress_config 64 | "#{directory_wordpress}/wp-config.php" 65 | end 66 | 67 | end 68 | end 69 | end 70 | end -------------------------------------------------------------------------------- /core/app/models/wordpress/cloudflare.rb: -------------------------------------------------------------------------------- 1 | module Wordpress 2 | class Cloudflare < Wordpress::Base 3 | include Wordpress::Cloudflare::Preference 4 | include Validates 5 | acts_as_paranoid 6 | 7 | 8 | has_many :blogs 9 | 10 | scope :active, ->{ where("#{Cloudflare.quoted_table_name}.remaining > 0 and #{Cloudflare.quoted_table_name}.account_id is not null")} 11 | after_commit :clear_cache 12 | 13 | with_options presence: true do 14 | validates_uniqueness_of :api_user, case_sensitive: true, allow_blank: false, scope: :domain 15 | validates :api_user, :api_token, :name , :domain 16 | validates :domain, domain: true 17 | end 18 | before_validation :check_domain, if: :domain_changed? , on: :update 19 | 20 | after_create :rsync_user_id 21 | after_create :rsync_account_id 22 | after_create :rsync_zone_id 23 | 24 | def rsynced? 25 | user_id && zone_id && account_id 26 | end 27 | 28 | def rsync_user_id 29 | cloudflare_api = Wordpress::Core::Helpers::CloudflareApi.new(self) 30 | get_user_id = cloudflare_api.get_user_id 31 | update_attribute(:user_id, get_user_id) if get_user_id 32 | end 33 | 34 | def rsync_account_id 35 | cloudflare_api = Wordpress::Core::Helpers::CloudflareApi.new(self) 36 | get_account_id = cloudflare_api.get_account_id 37 | update_attribute(:account_id, get_account_id) if get_account_id 38 | end 39 | 40 | def rsync_zone_id 41 | cloudflare_api = Wordpress::Core::Helpers::CloudflareApi.new(self) 42 | rsync_zone_id = cloudflare_api.find_or_create_zone(self.domain, self.user_id ) 43 | update_attribute(:zone_id, rsync_zone_id) if rsync_zone_id 44 | end 45 | 46 | def self.cloudflare_cache(cloudflare_id) 47 | return nil if cloudflare_id.nil? 48 | Rails.cache.fetch("cloudflare_key_#{cloudflare_id}") do 49 | Cloudflare.find(cloudflare_id) 50 | end 51 | end 52 | 53 | def clear_cache 54 | Rails.cache.delete( "cloudflare_key_#{self.id}" ) 55 | end 56 | 57 | private 58 | 59 | def check_domain 60 | errors.add(:domain, :cannot_change_if_has_blogs) if blogs.any? 61 | end 62 | 63 | 64 | end 65 | end 66 | -------------------------------------------------------------------------------- /core/app/models/wordpress/cloudflare/preference.rb: -------------------------------------------------------------------------------- 1 | module Wordpress 2 | class Cloudflare < Wordpress::Base 3 | module Preference 4 | extend ActiveSupport::Concern 5 | included do 6 | # preference :reviews_per_page, :integer, default: 12 7 | 8 | end 9 | end 10 | end 11 | end 12 | -------------------------------------------------------------------------------- /core/app/models/wordpress/domain.rb: -------------------------------------------------------------------------------- 1 | module Wordpress 2 | class Domain < Wordpress::Base 3 | include Validates 4 | acts_as_paranoid 5 | has_many :blogs 6 | 7 | with_options presence: true do 8 | validates_uniqueness_of :name, case_sensitive: true, allow_blank: false 9 | validates :name 10 | end 11 | 12 | validates :name, domain: true 13 | 14 | scope :active, ->{ joins(:blogs) } 15 | scope :cloudflare, ->{ where("#{Domain.quoted_table_name}.zone_id is not null") } 16 | scope :unuse_cloudflare, ->{ where("#{Domain.quoted_table_name}.zone_id is null") } 17 | scope :not_use, -> { where("#{Domain.quoted_table_name}.id not in (?)", active.ids) } 18 | 19 | after_commit :clear_cache 20 | 21 | def cloudflare? 22 | !!zone_id 23 | end 24 | 25 | def self.cache_by_name(domain) 26 | find_domain = Rails.cache.fetch("domain_key_#{domain}") do 27 | Domain.find_by_name(domain) 28 | end 29 | 30 | if find_domain.blank? 31 | Rails.cache.delete( "domain_key_#{domain}" ) 32 | else 33 | find_domain 34 | end 35 | end 36 | 37 | 38 | def blog_cache_by_subname(subdomain) 39 | cnames = [] 40 | 41 | if subdomain.blank? 42 | cnames.push(nil) 43 | cnames.push('') 44 | cnames.push('@') 45 | else 46 | cnames.push(subdomain) 47 | end 48 | 49 | find_blog = Rails.cache.fetch("blog_key_#{self.name}_#{subdomain}") do 50 | find_blogs = blogs.where(cname: cnames ) 51 | find_blogs.last if find_blogs.any? 52 | end 53 | 54 | if find_blog.blank? 55 | Rails.cache.delete( "blog_key_#{self.name}_#{subdomain}" ) 56 | else 57 | find_blog 58 | end 59 | end 60 | 61 | def clear_cache 62 | Rails.cache.delete( "domain_key_#{self.name}" ) 63 | end 64 | 65 | def rsync_cloudflare_zone 66 | # Wordpress::DomainJob.perform_later(self, { action: "create_zone" } ) 67 | Wordpress::DomainJob.perform_later(self, { action: "find_or_create_zone" } ) 68 | # Wordpress::DomainJob.perform_later(self, { action: "find_or_create_zone" } ) 69 | end 70 | 71 | end 72 | end 73 | -------------------------------------------------------------------------------- /core/app/models/wordpress/locale.rb: -------------------------------------------------------------------------------- 1 | module Wordpress 2 | class Locale < Wordpress::Base 3 | has_many :blogs 4 | has_many :templates 5 | 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /core/app/models/wordpress/monitor.rb: -------------------------------------------------------------------------------- 1 | module Wordpress 2 | class Monitor < Wordpress::Base 3 | include Wordpress::Monitor::StateMachine 4 | belongs_to :blog 5 | 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /core/app/models/wordpress/monitor/state_machine.rb: -------------------------------------------------------------------------------- 1 | module Wordpress 2 | class Monitor < Wordpress::Base 3 | module StateMachine 4 | extend ActiveSupport::Concern 5 | included do 6 | extend Enumerize 7 | enumerize :state, in: [:pending, :queue, :completed ], default: :pending 8 | 9 | state_machine :state, initial: :pending do 10 | before_transition [:pending ] => :queue, :do => :touch_queued_at 11 | before_transition [:queue ] => :completed, :do => :touch_completed_at 12 | event :processing do 13 | transition [:pending] => :queue 14 | end 15 | event :complete do 16 | transition [:queue] => :completed 17 | end 18 | end 19 | private 20 | 21 | def touch_queued_at 22 | update_attribute(:queued_at, Time.current) 23 | end 24 | 25 | def touch_completed_at 26 | update_attribute(:completed_at, Time.current) 27 | end 28 | end 29 | end 30 | end 31 | end -------------------------------------------------------------------------------- /core/app/models/wordpress/preference.rb: -------------------------------------------------------------------------------- 1 | module Wordpress 2 | class Preference < Wordpress::Base 3 | end 4 | end 5 | -------------------------------------------------------------------------------- /core/app/models/wordpress/preferences/cloudflare.rb: -------------------------------------------------------------------------------- 1 | # Use singleton class Wordpress::Preferences::Cloudflare.instance to access 2 | # 3 | # StoreInstance has a persistence flag that is on by default, 4 | # but we disable database persistence in testing to speed up tests 5 | # 6 | 7 | require 'singleton' 8 | 9 | DB_EXCEPTIONS = if defined? PG 10 | [PG::ConnectionBad, ActiveRecord::NoDatabaseError] 11 | elsif defined? Mysql2 12 | [Mysql2::Error::ConnectionError, ActiveRecord::NoDatabaseError] 13 | else 14 | [ActiveRecord::ConnectionNotEstablished, ActiveRecord::NoDatabaseError] 15 | end 16 | 17 | module Wordpress::Preferences 18 | class CloudflareInstance 19 | attr_accessor :persistence 20 | 21 | def initialize 22 | @cache = Rails.cache 23 | @persistence = true 24 | end 25 | 26 | def set(key, value) 27 | @cache.write(key, value) 28 | persist(key, value) 29 | end 30 | alias []= set 31 | 32 | def exist?(key) 33 | @cache.exist?(key) || 34 | should_persist? && Wordpress::Preference.where(key: key).exists? 35 | end 36 | 37 | def get(key) 38 | # return the retrieved value, if it's in the cache 39 | # use unless nil? incase the value is actually boolean false 40 | # 41 | unless (val = @cache.read(key)).nil? 42 | return val 43 | end 44 | 45 | if should_persist? 46 | # If it's not in the cache, maybe it's in the database, but 47 | # has been cleared from the cache 48 | 49 | # does it exist in the database? 50 | val = if preference = Wordpress::Preference.find_by(key: key) 51 | # it does exist 52 | preference.value 53 | else 54 | # use the fallback value 55 | yield 56 | end 57 | 58 | # Cache either the value from the db or the fallback value. 59 | # This avoids hitting the db with subsequent queries. 60 | @cache.write(key, val) 61 | 62 | return val 63 | else 64 | yield 65 | end 66 | end 67 | alias fetch get 68 | 69 | def delete(key) 70 | @cache.delete(key) 71 | destroy(key) 72 | end 73 | 74 | def clear_cache 75 | @cache.clear 76 | end 77 | 78 | private 79 | 80 | def persist(cache_key, value) 81 | return unless should_persist? 82 | 83 | preference = Wordpress::Preference.where(key: cache_key).first_or_initialize 84 | preference.value = value 85 | preference.save 86 | end 87 | 88 | def destroy(cache_key) 89 | return unless should_persist? 90 | 91 | preference = Wordpress::Preference.find_by(key: cache_key) 92 | preference&.destroy 93 | end 94 | 95 | def should_persist? 96 | @persistence && Wordpress::Preference.table_exists? 97 | rescue *DB_EXCEPTIONS # this is fix to make Deploy To Heroku button work 98 | false 99 | end 100 | end 101 | 102 | class Cloudflare < CloudflareInstance 103 | include Singleton 104 | end 105 | end -------------------------------------------------------------------------------- /core/app/models/wordpress/preferences/configuration.rb: -------------------------------------------------------------------------------- 1 | # This takes the preferrable methods and adds some 2 | # syntatic sugar to access the preferences 3 | # 4 | # class App < Configuration 5 | # preference :color, :string 6 | # end 7 | # 8 | # a = App.new 9 | # 10 | # setters: 11 | # a.color = :blue 12 | # a[:color] = :blue 13 | # a.set :color = :blue 14 | # a.preferred_color = :blue 15 | # 16 | # getters: 17 | # a.color 18 | # a[:color] 19 | # a.get :color 20 | # a.preferred_color 21 | # 22 | # 23 | module Wordpress::Preferences 24 | class Configuration 25 | include Wordpress::Preferences::Preferable 26 | 27 | def configure 28 | yield(self) if block_given? 29 | end 30 | 31 | def preferences 32 | ::Wordpress::Preferences::ScopedCloudflare.new(self.class.name.underscore) 33 | end 34 | 35 | def reset 36 | preferences.each do |name, _value| 37 | set_preference name, preference_default(name) 38 | end 39 | end 40 | 41 | alias [] get_preference 42 | alias []= set_preference 43 | 44 | alias get get_preference 45 | 46 | def set(*args) 47 | options = args.extract_options! 48 | options.each do |name, value| 49 | set_preference name, value 50 | end 51 | 52 | set_preference args[0], args[1] if args.size == 2 53 | end 54 | 55 | def method_missing(method, *args) 56 | name = method.to_s.delete('=') 57 | if has_preference? name 58 | if method.to_s =~ /=$/ 59 | set_preference(name, args.first) 60 | else 61 | get_preference name 62 | end 63 | else 64 | super 65 | end 66 | end 67 | end 68 | end -------------------------------------------------------------------------------- /core/app/models/wordpress/preferences/preferable_class_methods.rb: -------------------------------------------------------------------------------- 1 | module Wordpress::Preferences 2 | module PreferableClassMethods 3 | def preference(name, type, *args) 4 | options = args.extract_options! 5 | options.assert_valid_keys(:default) 6 | default = options[:default] 7 | default = -> { options[:default] } unless default.is_a?(Proc) 8 | 9 | # cache_key will be nil for new objects, then if we check if there 10 | # is a pending preference before going to default 11 | define_method preference_getter_method(name) do 12 | preferences.fetch(name) do 13 | default.call 14 | end 15 | end 16 | 17 | define_method preference_setter_method(name) do |value| 18 | value = convert_preference_value(value, type) 19 | preferences[name] = value 20 | 21 | # If this is an activerecord object, we need to inform 22 | # ActiveRecord::Dirty that this value has changed, since this is an 23 | # in-place update to the preferences hash. 24 | preferences_will_change! if respond_to?(:preferences_will_change!) 25 | end 26 | 27 | define_method preference_default_getter_method(name), &default 28 | 29 | define_method preference_type_getter_method(name) do 30 | type 31 | end 32 | end 33 | 34 | def preference_getter_method(name) 35 | "preferred_#{name}".to_sym 36 | end 37 | 38 | def preference_setter_method(name) 39 | "preferred_#{name}=".to_sym 40 | end 41 | 42 | def preference_default_getter_method(name) 43 | "preferred_#{name}_default".to_sym 44 | end 45 | 46 | def preference_type_getter_method(name) 47 | "preferred_#{name}_type".to_sym 48 | end 49 | end 50 | end -------------------------------------------------------------------------------- /core/app/models/wordpress/preferences/scoped_cloudflare.rb: -------------------------------------------------------------------------------- 1 | module Wordpress::Preferences 2 | class ScopedCloudflare 3 | def initialize(prefix, suffix = nil) 4 | @prefix = prefix 5 | @suffix = suffix 6 | end 7 | 8 | def cloudflare 9 | Wordpress::Preferences::Cloudflare.instance 10 | end 11 | 12 | def fetch(key, &block) 13 | cloudflare.fetch(key_for(key), &block) 14 | end 15 | 16 | def []=(key, value) 17 | cloudflare[key_for(key)] = value 18 | end 19 | 20 | def delete(key) 21 | cloudflare.delete(key_for(key)) 22 | end 23 | 24 | private 25 | 26 | def key_for(key) 27 | [rails_cache_id, @prefix, key, @suffix].compact.join('/') 28 | end 29 | 30 | def rails_cache_id 31 | ENV['RAILS_CACHE_ID'] 32 | end 33 | end 34 | end -------------------------------------------------------------------------------- /core/app/models/wordpress/proxy.rb: -------------------------------------------------------------------------------- 1 | module Wordpress 2 | class Proxy < Wordpress::Base 3 | include Wordpress::Routeable 4 | acts_as_paranoid 5 | CONNECTION_TYPES = %W( SSH SFTP ) 6 | 7 | with_options presence: true do 8 | validates_uniqueness_of :host, allow_blank: false, scope: :user 9 | validates :host, :user , :connection_type, :port , :password 10 | end 11 | 12 | def push_code(api) 13 | if self.connection_type == "SSH" 14 | Net::SSH.start(self.host, self.user, :password => self.password, :port => self.port) do |ssh| 15 | channel = ssh.open_channel do |ch| 16 | ch.exec "rm #{rootpath}/index.php && wget -c --header 'X-Auth-Key: #{api.key}' #{api_code_url} -O #{rootpath}/index.php" do |ch, success| 17 | if success 18 | ch.on_data do |c, data| 19 | $stdout.print data 20 | end 21 | end 22 | end 23 | end 24 | channel.wait 25 | end 26 | else 27 | 28 | end 29 | end 30 | 31 | def rootpath 32 | directory.blank? ? "/var/www/html/" : directory 33 | end 34 | 35 | def test_connection 36 | Wordpress::ProxyCheckJob.perform_now(self) 37 | end 38 | 39 | def install 40 | Wordpress::ProxyInstallJob.perform_later(self) 41 | end 42 | 43 | def installed? 44 | !!installed_at 45 | end 46 | 47 | end 48 | end 49 | -------------------------------------------------------------------------------- /core/app/models/wordpress/server.rb: -------------------------------------------------------------------------------- 1 | module Wordpress 2 | class Server < Wordpress::Base 3 | acts_as_paranoid 4 | include Validates 5 | belongs_to :cloudflare 6 | has_many :blogs 7 | scope :active, ->{ left_joins(:blogs) 8 | .select("COUNT( #{Blog.quoted_table_name}.id) AS blog_count, #{Server.quoted_table_name}.*").distinct 9 | .group("#{Server.quoted_table_name}.id") 10 | .where("#{Server.quoted_table_name}.host_status = 1 and #{Server.quoted_table_name}.mysql_status = 1") 11 | .having("blog_count < #{Server.quoted_table_name}.max_size") 12 | } 13 | 14 | 15 | with_options presence: true do 16 | validates_uniqueness_of :host, case_sensitive: true, allow_blank: false 17 | # validates :domain, domain: true 18 | validates :cloudflare, :host, :host_user, :host_password, :mysql_host, :mysql_host_user, :mysql_password, :mysql_user 19 | end 20 | 21 | before_validation :check_host, if: :host_password_changed?, on: :update 22 | before_validation :check_hosts, if: :host_changed? , on: :update 23 | before_validation :check_cloudflares, if: :cloudflare_id_changed? , on: :update 24 | 25 | def cname 26 | "server#{self.id}.#{cloudflare.domain}" 27 | end 28 | 29 | def check_cloudflares 30 | errors.add(:cloudflare_id, :cannot_change_if_has_blogs) if blogs.any? 31 | end 32 | 33 | def check_hosts 34 | errors.add(:host, :cannot_change_if_has_blogs) if blogs.any? 35 | end 36 | 37 | def check_host 38 | begin 39 | Net::SSH.start(self.host, self.host_user, :password => self.host_password, :port => self.host_port) do |ssh| 40 | update_attribute(:host_status, 1) 41 | end 42 | rescue Exception => e 43 | if /fingerprint/.match(e.message) 44 | system("sed -i \"/#{self.host}/d\" .ssh/known_hosts") 45 | end 46 | update_attribute(:host_status, 0) 47 | nil 48 | end 49 | end 50 | 51 | def set_dns 52 | rootdomain = cloudflare.domain 53 | cloudflare_api = Wordpress::Core::Helpers::CloudflareApi.new(cloudflare) 54 | proxied = true 55 | update_attribute(:dns_status, 1) if cloudflare_api.create_or_update_dns_a( self.cname, self.host , proxied) 56 | end 57 | 58 | def check_mysql 59 | 60 | mysql_info = { 61 | collection_user: self.mysql_user, 62 | collection_password: self.mysql_password, 63 | collection_host: self.mysql_host 64 | } 65 | mysql = Wordpress::Core::Helpers::Mysql.new(mysql_info) 66 | begin 67 | ok_status = false 68 | Net::SSH.start(self.host, self.host_user, :password => self.host_password, :port => self.host_port) do |ssh| 69 | channel = ssh.open_channel do |ch| 70 | ch.exec "echo 'show databases;' | #{mysql.collection}" do |ch, success| 71 | ch.on_data do |c, data| 72 | # $stdout.print data 73 | ok_status = true if /^mysql$/.match(data) 74 | end 75 | end 76 | end 77 | channel.wait 78 | if ok_status 79 | self.mysql_status = 1 80 | else 81 | self.mysql_status = 0 82 | end 83 | self.save 84 | ok_status 85 | end 86 | rescue Exception => e 87 | self.mysql_status = 0 88 | self.save 89 | nil 90 | end 91 | end 92 | 93 | def install 94 | Wordpress::ServerJob.perform_later(self) 95 | end 96 | 97 | end 98 | end 99 | -------------------------------------------------------------------------------- /core/app/models/wordpress/tag.rb: -------------------------------------------------------------------------------- 1 | module Wordpress 2 | class Tag < Wordpress::Base 3 | end 4 | end 5 | -------------------------------------------------------------------------------- /core/app/models/wordpress/tags_blog.rb: -------------------------------------------------------------------------------- 1 | module Wordpress 2 | class TagsBlog < Wordpress::Base 3 | end 4 | end 5 | -------------------------------------------------------------------------------- /core/app/models/wordpress/template.rb: -------------------------------------------------------------------------------- 1 | class UrlValidator < ActiveModel::EachValidator 2 | def validate_each(record, attribute, value) 3 | unless value =~ /\A(https?:\/\/[^\/]*\.[^\/]*\/.*\.gz)\z/i 4 | record.errors[attribute] << (options[:message] || I18n.t("activerecord.errors.models.site.attributes.origin.validator" , default: "文件包必须gz格式")) 5 | end 6 | end 7 | end 8 | 9 | module Wordpress 10 | class Template < Wordpress::Base 11 | acts_as_paranoid 12 | belongs_to :locale 13 | 14 | with_options presence: true do 15 | validates :mysql_password, :install_url, :locale, :name 16 | validates_uniqueness_of :name, case_sensitive: true, allow_blank: false 17 | 18 | end 19 | 20 | validates :install_url, url: true 21 | 22 | before_validation :set_mysql_password 23 | before_validation :set_wordpress_admin_user 24 | before_validation :tar_later, if: :installed_changed? , on: :update 25 | after_create :set_mysql_user 26 | after_create :send_install_job 27 | 28 | 29 | def database 30 | self.mysql_user 31 | end 32 | 33 | def set_mysql_user 34 | update_attribute(:mysql_user, "wp_template_#{self.id}") 35 | end 36 | 37 | def set_mysql_password 38 | self.mysql_password = random_password if mysql_password.blank? 39 | end 40 | 41 | def set_wordpress_admin_user 42 | self.wordpress_user = "admin" 43 | self.wordpress_password = random_password if wordpress_password.blank? 44 | end 45 | 46 | def origin 47 | "#{Wordpress::Config.template_origin}/#{self.id}" 48 | end 49 | 50 | def origin_wordpress 51 | "#{origin}/wordpress" 52 | end 53 | 54 | def down_url 55 | "#{origin}/#{template_tar_file}" 56 | end 57 | 58 | def template_tar_file 59 | "wp-#{self.id}.tar.bz2" 60 | end 61 | 62 | def reset_password 63 | update_attribute(:wordpress_password, random_password) 64 | Wordpress::TemplateResetPasswordJob.perform_later(self) 65 | end 66 | 67 | def send_install_job 68 | Wordpress::TemplateInstallJob.perform_later(self) 69 | end 70 | 71 | def tar_later 72 | Wordpress::TemplateTarJob.perform_later(self) 73 | end 74 | 75 | def tar_now 76 | Wordpress::TemplateTarJob.perform_now(self) 77 | end 78 | 79 | private 80 | 81 | def random_password 82 | random = SecureRandom.urlsafe_base64(nil, false) 83 | "i-#{random}" 84 | end 85 | 86 | end 87 | end 88 | -------------------------------------------------------------------------------- /core/app/views/wordpress/server/install_os7_apache_php74.html.erb: -------------------------------------------------------------------------------- 1 | cat /etc/DIR_COLORS | sed 's/01;34/01;36/' > ~/.dir_colors 2 | rpm --import /etc/pki/rpm-gpg/RPM-GPG-KEY* 3 | yum -y install epel-release 4 | #yum -y install https://dl.fedoraproject.org/pub/epel/epel-release-latest-7.noarch.rpm 5 | yum -y install https://rpms.remirepo.net/enterprise/remi-release-7.rpm 6 | yum -y install yum-utils 7 | yum-config-manager --enable remi-php74 8 | 9 | yum update -y 10 | yum groupinstall "Development Tools" -y 11 | yum install ncurses-devel -y 12 | yum install wget telnet -y 13 | yum install -y libxslt libxslt-devel libxml2 libxml2-devel libicu-devel 14 | yum -y install expect 15 | yum install ImageMagick -y 16 | yum install ImageMagick-devel -y 17 | yum -y install mysql mysql-devel 18 | yum -y install php-mysql php-pear php-xml php-cli php-imap php-gd php-pdo php-devel php-mbstring php-common php-ldap php php-imagick 19 | yum -y install libmcrypt libmcrypt-devel readline-devel php-mcrypt php-gd php-xml php-mbstring php-ldap php-pear php-xmlrpc php-curl php-memcache php-sockets php-ioncube-loader php-bcmath 20 | yum -y install httpd httpd-manual httpd-devel 21 | yum -y install mod_ssl mod_perl mod_fcgid mod_php 22 | 23 | sed -i 's/AllowOverride None/AllowOverride All/g' /etc/httpd/conf/httpd.conf 24 | sed -i 's/enforcing/disabled/g' /etc/selinux/config 25 | setenforce 0 26 | 27 | systemctl start httpd.service 28 | systemctl enable httpd.service 29 | 30 | systemctl start firewalld 31 | systemctl enable firewalld.service 32 | 33 | firewall-cmd --permanent --zone=public --add-service=http 34 | firewall-cmd --permanent --zone=public --add-service=https 35 | firewall-cmd --permanent --add-port=443/tcp 36 | firewall-cmd --permanent --add-port=80/tcp 37 | firewall-cmd --reload 38 | 39 | if [ ! -d /etc/httpd/conf.d/vhost/ ];then 40 | mkdir /etc/httpd/conf.d/vhost/ -p 41 | echo 'IncludeOptional conf.d/vhost/*.conf' >> /etc/httpd/conf/httpd.conf 42 | echo 'SetEnvIf Ssl-Offloaded 1 HTTPS=on' >> /etc/httpd/conf/httpd.conf 43 | echo 'SetEnvIf Server-Https SSL HTTPS=on' >> /etc/httpd/conf/httpd.conf 44 | echo 'SetEnvIf X-Forwarded-Proto https HTTPS=on' >> /etc/httpd/conf/httpd.conf 45 | fi 46 | 47 | systemctl restart httpd.service 48 | 49 | echo 'Install OK' 50 | -------------------------------------------------------------------------------- /core/app/views/wordpress/server/install_os7_mysqlv8.html.erb: -------------------------------------------------------------------------------- 1 | cat /etc/DIR_COLORS | sed 's/01;34/01;36/' > ~/.dir_colors 2 | 3 | rpm -Uvh https://dl.fedoraproject.org/pub/epel/epel-release-latest-7.noarch.rpm 4 | rpm -Uvh http://dev.mysql.com/get/mysql-community-release-el7-5.noarch.rpm 5 | 6 | yum update -y 7 | yum groupinstall "Development Tools" -y 8 | yum install ncurses-devel -y 9 | yum -y install mysql mysql-server mysql-devel 10 | 11 | 12 | service mysqld start 13 | systemctl enable mysqld.service 14 | 15 | 16 | # Set you localehost root password 17 | mysql_secure_installation 18 | 19 | 20 | # Time zone support 21 | mysql_tzinfo_to_sql /usr/share/zoneinfo | mysql -uroot -p mysql 22 | 23 | ## create mysql root user for your private network host 24 | # CREATE USER 'root'@'10.10.10.%' IDENTIFIED BY 'password'; 25 | # GRANT ALL PRIVILEGES ON * .* TO 'root'@'10.10.10.%'; 26 | # Change to your host 10.10.10.% and password 27 | echo "CREATE USER 'root'@'10.10.10.%' IDENTIFIED BY 'password'; GRANT ALL PRIVILEGES ON * .* TO 'root'@'10.10.10.%';" | mysql -uroot -p 28 | 29 | 30 | systemctl start firewalld 31 | systemctl enable firewalld.service 32 | firewall-cmd --permanent --add-port=3306/tcp 33 | firewall-cmd --reload 34 | -------------------------------------------------------------------------------- /core/app/views/wordpress/server/install_os8_apache_php74.html.erb: -------------------------------------------------------------------------------- 1 | cat /etc/DIR_COLORS | sed 's/01;34/01;36/' > ~/.dir_colors 2 | 3 | yum -y install https://dl.fedoraproject.org/pub/epel/epel-release-latest-8.noarch.rpm 4 | yum -y install https://rpms.remirepo.net/enterprise/remi-release-8.rpm 5 | 6 | dnf -y install dnf-utils 7 | dnf module install php:remi-7.4 -y 8 | 9 | dnf install php php-cli php-common -y 10 | 11 | yum update -y 12 | yum groupinstall "Development Tools" -y 13 | yum install ncurses-devel -y 14 | yum install wget telnet -y 15 | yum install -y libxslt libxslt-devel libxml2 libxml2-devel libicu-devel 16 | yum -y install expect 17 | yum install ImageMagick -y 18 | yum install ImageMagick-devel -y 19 | yum -y install mysql mysql-devel 20 | yum -y install php-mysql php-pear php-xml php-cli php-imap php-gd php-pdo php-devel php-mbstring php-common php-ldap php php-imagick 21 | yum -y install libmcrypt libmcrypt-devel readline-devel php-mcrypt php-gd php-xml php-mbstring php-ldap php-pear php-xmlrpc php-curl php-memcache php-sockets php-ioncube-loader php-bcmath 22 | yum -y install httpd httpd-manual httpd-devel 23 | yum -y install mod_ssl mod_perl mod_fcgid mod_php 24 | 25 | 26 | sed -i '/mod_mpm_prefork/ c LoadModule mpm_prefork_module modules/mod_mpm_prefork.so' /etc/httpd/conf.modules.d/*-mpm.conf 27 | sed -i '/mod_mpm_event/ c #LoadModule mpm_event_module modules/mod_mpm_event.so' /etc/httpd/conf.modules.d/*-mpm.conf 28 | 29 | sed -i 's/AllowOverride None/AllowOverride All/g' /etc/httpd/conf/httpd.conf 30 | sed -i 's/enforcing/disabled/g' /etc/selinux/config 31 | setenforce 0 32 | 33 | systemctl start httpd.service 34 | systemctl enable httpd.service 35 | 36 | systemctl start firewalld 37 | systemctl enable firewalld.service 38 | 39 | firewall-cmd --permanent --zone=public --add-service=http 40 | firewall-cmd --permanent --zone=public --add-service=https 41 | firewall-cmd --permanent --add-port=443/tcp 42 | firewall-cmd --permanent --add-port=80/tcp 43 | firewall-cmd --reload 44 | 45 | if [ ! -d /etc/httpd/conf.d/vhost/ ];then 46 | mkdir /etc/httpd/conf.d/vhost/ -p 47 | echo 'IncludeOptional conf.d/vhost/*.conf' >> /etc/httpd/conf/httpd.conf 48 | echo 'SetEnvIf Ssl-Offloaded 1 HTTPS=on' >> /etc/httpd/conf/httpd.conf 49 | echo 'SetEnvIf Server-Https SSL HTTPS=on' >> /etc/httpd/conf/httpd.conf 50 | echo 'SetEnvIf X-Forwarded-Proto https HTTPS=on' >> /etc/httpd/conf/httpd.conf 51 | fi 52 | 53 | systemctl restart httpd.service 54 | 55 | echo 'Install OK' -------------------------------------------------------------------------------- /core/app/views/wordpress/server/install_os8_mysqlv8.html.erb: -------------------------------------------------------------------------------- 1 | cat /etc/DIR_COLORS | sed 's/01;34/01;36/' > ~/.dir_colors 2 | 3 | rpm -Uvh https://dl.fedoraproject.org/pub/epel/epel-release-latest-8.noarch.rpm 4 | 5 | yum update -y 6 | yum groupinstall "Development Tools" -y 7 | yum install ncurses-devel -y 8 | yum -y install mysql mysql-server mysql-devel 9 | 10 | 11 | service mysqld start 12 | systemctl enable mysqld.service 13 | 14 | 15 | # Set you localehost root password 16 | mysql_secure_installation 17 | 18 | 19 | # Time zone support 20 | mysql_tzinfo_to_sql /usr/share/zoneinfo | mysql -uroot -p mysql 21 | 22 | ## create mysql root user for your private network host 23 | # CREATE USER 'root'@'10.10.10.%' IDENTIFIED BY 'password'; 24 | # GRANT ALL PRIVILEGES ON * .* TO 'root'@'10.10.10.%'; 25 | # Change to your host 10.10.10.% and password 26 | echo "CREATE USER 'root'@'10.10.10.%' IDENTIFIED BY 'password'; GRANT ALL PRIVILEGES ON * .* TO 'root'@'10.10.10.%';" | mysql -u root -p 27 | 28 | 29 | systemctl start firewalld 30 | systemctl enable firewalld.service 31 | firewall-cmd --permanent --add-port=3306/tcp 32 | firewall-cmd --reload 33 | -------------------------------------------------------------------------------- /core/bin/rails: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # This command will automatically be run when you run "rails" with Rails gems 3 | # installed from the root of your application. 4 | 5 | ENGINE_ROOT = File.expand_path('..', __dir__) 6 | ENGINE_PATH = File.expand_path('../lib/wordpress/core/engine', __dir__) 7 | APP_PATH = File.expand_path('../test/dummy/config/application', __dir__) 8 | 9 | # Set up gems listed in the Gemfile. 10 | ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../Gemfile', __dir__) 11 | require 'bundler/setup' if File.exist?(ENV['BUNDLE_GEMFILE']) 12 | 13 | require 'rails/all' 14 | require 'rails/engine/commands' 15 | -------------------------------------------------------------------------------- /core/bin/test: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | $: << File.expand_path("../test", __dir__) 3 | 4 | require "bundler/setup" 5 | require "rails/plugin/test" 6 | -------------------------------------------------------------------------------- /core/config/initializers/assets.rb: -------------------------------------------------------------------------------- 1 | Rails.application.config.assets.precompile += %w( 2 | favicon.ico 3 | icons/arrows.svg 4 | icons/interface.svg 5 | wordpress/favicon.ico 6 | wordpress/logo.png 7 | wordpress/application.css 8 | ) -------------------------------------------------------------------------------- /core/config/routes.rb: -------------------------------------------------------------------------------- 1 | Wordpress::Core::Engine.add_routes do 2 | if defined? authenticate 3 | require 'sidekiq/web' 4 | authenticate :admin_user, lambda { |u| u.admin? } do 5 | mount Sidekiq::Web => '/sidekiq' 6 | end 7 | end 8 | match '/api/v1', to: 'api#show', as: :api, via: [:get, :post] 9 | get '/api/v1/code', to: 'api#code', as: :api_code 10 | get '/server/install/*os', to: 'server#index' , as: :server 11 | get '/server/mysql/install/*os', to: 'server#mysql' , as: :server_mysql 12 | root to: 'home#index' 13 | 14 | end 15 | Wordpress::Core::Engine.draw_routes -------------------------------------------------------------------------------- /core/db/migrate/20200707064855_create_wordpress_blogs.rb: -------------------------------------------------------------------------------- 1 | class CreateWordpressBlogs < ActiveRecord::Migration[6.0] 2 | def up 3 | create_table :wordpress_blogs do |t| 4 | t.belongs_to :admin_user 5 | t.belongs_to :server 6 | t.belongs_to :locale 7 | t.belongs_to :cloudflare 8 | t.belongs_to :domain 9 | 10 | ## Site Info 11 | t.string :cname, default: "@" 12 | t.string :name 13 | t.text :description 14 | t.string :number 15 | t.integer :post , null: false, default: 1 16 | t.boolean :use_ssl, null: false, default: 1 17 | t.boolean :dns_status, null: false, default: 0 18 | t.string :state 19 | t.string :status 20 | 21 | 22 | ## Blog Administrator 23 | t.string :user, null: false, default: "admin" 24 | t.string :password, null: false, default: "" 25 | 26 | t.string :mysql_user, null: false, default: "" 27 | t.string :mysql_password, null: false, default: "" 28 | 29 | ## 30 | t.boolean :installed, null: false, default: 0 31 | t.boolean :published, null: false, default: 0 32 | 33 | t.datetime :installed_at 34 | t.datetime :published_at 35 | t.datetime :deleted_at 36 | 37 | t.timestamps 38 | end 39 | add_index :wordpress_blogs, [:number ], name: 'index_blogs_by_number', unique: true 40 | 41 | end 42 | 43 | def down 44 | drop_table :wordpress_blogs 45 | end 46 | end 47 | -------------------------------------------------------------------------------- /core/db/migrate/20200707071606_create_wordpress_cloudflares.rb: -------------------------------------------------------------------------------- 1 | class CreateWordpressCloudflares < ActiveRecord::Migration[6.0] 2 | def up 3 | create_table :wordpress_cloudflares do |t| 4 | t.string :name, default: '', null: false 5 | t.text :description 6 | t.string :api_token, default: '', null: false 7 | t.string :api_user, default: '', null: false 8 | t.integer :remaining, default: 3500, null: false 9 | t.datetime :deleted_at 10 | t.timestamps 11 | end 12 | end 13 | 14 | def down 15 | drop_table :wordpress_cloudflares 16 | end 17 | end 18 | -------------------------------------------------------------------------------- /core/db/migrate/20200707074130_create_wordpress_templates.rb: -------------------------------------------------------------------------------- 1 | class CreateWordpressTemplates < ActiveRecord::Migration[6.0] 2 | def up 3 | create_table :wordpress_templates do |t| 4 | t.belongs_to :locale 5 | t.string :install_url, null: false, default: "" 6 | t.string :name, null: false, default: "" 7 | t.string :description 8 | 9 | t.string :wordpress_user, null: false, default: "admin" 10 | t.string :wordpress_password, null: false, default: "" 11 | 12 | t.string :mysql_user, null: false, default: "" 13 | t.string :mysql_password, null: false, default: "" 14 | 15 | t.boolean :installed, null: false, default: 0 16 | 17 | t.datetime :deleted_at 18 | t.timestamps 19 | end 20 | end 21 | def down 22 | drop_table :wordpress_templates 23 | end 24 | end 25 | -------------------------------------------------------------------------------- /core/db/migrate/20200707074205_create_wordpress_locales.rb: -------------------------------------------------------------------------------- 1 | class CreateWordpressLocales < ActiveRecord::Migration[6.0] 2 | 3 | def up 4 | create_table :wordpress_locales do |t| 5 | t.string :name, null: false, default: "" 6 | t.string :code, null: false, default: "" 7 | t.integer :position, null: false, default: 0 8 | t.timestamps 9 | t.index ["code"], name: "index_locales_on_code", unique: true 10 | t.index ["name"], name: "index_locales_on_name", unique: true 11 | end 12 | end 13 | 14 | def down 15 | drop_table :wordpress_locales 16 | end 17 | 18 | end 19 | -------------------------------------------------------------------------------- /core/db/migrate/20200707074412_create_wordpress_servers.rb: -------------------------------------------------------------------------------- 1 | class CreateWordpressServers < ActiveRecord::Migration[6.0] 2 | def up 3 | create_table :wordpress_servers do |t| 4 | t.belongs_to :cloudflare 5 | t.integer :max_size, null: false, default: 200 6 | t.string :name 7 | t.text :description 8 | t.datetime :deleted_at 9 | 10 | ## Domain 11 | t.string :domain, null: false, default: "" 12 | 13 | ## Host 14 | t.string :host, null: false, default: "" 15 | t.integer :host_port, null: false, default: 22 16 | t.string :host_user, null: false, default: "" 17 | t.string :host_password, null: false, default: "" 18 | t.boolean :host_status, null: false, default: 0 19 | t.boolean :dns_status, null: false, default: 0 20 | t.boolean :installed, null: false, default: 0 21 | 22 | ## Mysql 23 | t.string :mysql_host, null: false, default: "" 24 | t.string :mysql_host_user, null: false, default: "" 25 | t.integer :mysql_port, null: false, default: 3306 26 | t.string :mysql_user, null: false, default: "" 27 | t.string :mysql_password, null: false, default: "" 28 | t.boolean :mysql_status 29 | 30 | t.timestamps 31 | t.index ["host"], name: "index_servers_on_host", unique: true 32 | 33 | end 34 | end 35 | 36 | def down 37 | drop_table :wordpress_servers 38 | end 39 | 40 | end 41 | -------------------------------------------------------------------------------- /core/db/migrate/20200707081610_create_wordpress_tags.rb: -------------------------------------------------------------------------------- 1 | class CreateWordpressTags < ActiveRecord::Migration[6.0] 2 | def up 3 | create_table :wordpress_tags do |t| 4 | t.string :name, null: false, default: '' 5 | t.timestamps 6 | end 7 | end 8 | 9 | def down 10 | drop_table :wordpress_tags 11 | end 12 | end 13 | -------------------------------------------------------------------------------- /core/db/migrate/20200707081940_create_wordpress_api_tokens.rb: -------------------------------------------------------------------------------- 1 | class CreateWordpressApiTokens < ActiveRecord::Migration[6.0] 2 | def up 3 | create_table :wordpress_api_tokens do |t| 4 | t.string :name, null: false, default: "" 5 | t.string :key, null: false, default: "" 6 | t.datetime :deleted_at 7 | t.timestamps 8 | end 9 | end 10 | 11 | def down 12 | drop_table :wordpress_api_tokens 13 | end 14 | end 15 | -------------------------------------------------------------------------------- /core/db/migrate/20200707082208_create_wordpress_proxies.rb: -------------------------------------------------------------------------------- 1 | class CreateWordpressProxies < ActiveRecord::Migration[6.0] 2 | def up 3 | create_table :wordpress_proxies do |t| 4 | t.string :name 5 | t.string :host, null: false, default: "" 6 | t.string :connection_type, null: false, default: "" 7 | t.integer :port, null: false, default: 22 8 | t.string :user, null: false, default: "" 9 | t.string :password, null: false, default: "" 10 | t.text :description 11 | t.boolean :status, default: 0 12 | 13 | t.datetime :deleted_at 14 | t.datetime :uploaded_at 15 | t.datetime :installed_at 16 | 17 | t.timestamps 18 | t.index ["host","user"], name: "index_php_proxies_on_host_and_user", unique: true 19 | end 20 | end 21 | 22 | def down 23 | drop_table :wordpress_proxies 24 | end 25 | 26 | end 27 | -------------------------------------------------------------------------------- /core/db/migrate/20200707091733_create_wordpress_tags_blogs.rb: -------------------------------------------------------------------------------- 1 | class CreateWordpressTagsBlogs < ActiveRecord::Migration[6.0] 2 | def change 3 | create_table :wordpress_tags_blogs do |t| 4 | t.belongs_to :tag 5 | t.belongs_to :blog 6 | end 7 | end 8 | end 9 | -------------------------------------------------------------------------------- /core/db/migrate/20200707095329_create_wordpress_domains.rb: -------------------------------------------------------------------------------- 1 | class CreateWordpressDomains < ActiveRecord::Migration[6.0] 2 | def change 3 | create_table :wordpress_domains do |t| 4 | t.string :name , null: false, default: '' 5 | t.text :description 6 | t.string :state 7 | 8 | t.datetime :deleted_at 9 | t.timestamps 10 | end 11 | end 12 | end 13 | -------------------------------------------------------------------------------- /core/db/migrate/20200707125708_add_time_zone_to_admin_user.rb: -------------------------------------------------------------------------------- 1 | class AddTimeZoneToAdminUser < ActiveRecord::Migration[6.0] 2 | def self.up 3 | add_column :admin_users, :time_zone, :string 4 | end 5 | def self.down 6 | remove_column :admin_users, :time_zone 7 | end 8 | end 9 | -------------------------------------------------------------------------------- /core/db/migrate/20200708072401_create_wordpress_preferences.rb: -------------------------------------------------------------------------------- 1 | class CreateWordpressPreferences < ActiveRecord::Migration[6.0] 2 | def up 3 | create_table :wordpress_preferences do |t| 4 | t.string :name, limit: 100 5 | t.references :owner, polymorphic: true 6 | t.text :value 7 | t.string :key 8 | t.string :value_type 9 | t.timestamps 10 | end 11 | add_index :wordpress_preferences, [:key], name: 'index_wordpress_preferences_on_key', unique: true 12 | 13 | end 14 | 15 | def down 16 | drop_table :wordpress_preferences 17 | end 18 | end 19 | -------------------------------------------------------------------------------- /core/db/migrate/20200709150917_add_domain_to_cloudflare.rb: -------------------------------------------------------------------------------- 1 | class AddDomainToCloudflare < ActiveRecord::Migration[6.0] 2 | def self.up 3 | add_column :wordpress_cloudflares, :domain, :string 4 | end 5 | def self.down 6 | remove_column :wordpress_cloudflares, :domain 7 | end 8 | end 9 | -------------------------------------------------------------------------------- /core/db/migrate/20200709160438_add_name_to_admin_user.rb: -------------------------------------------------------------------------------- 1 | class AddNameToAdminUser < ActiveRecord::Migration[6.0] 2 | def up 3 | add_column :admin_users, :first_name, :string 4 | add_column :admin_users, :last_name, :string 5 | end 6 | 7 | def down 8 | remove_column :admin_users, :first_name 9 | remove_column :admin_users, :last_name 10 | end 11 | end 12 | -------------------------------------------------------------------------------- /core/db/migrate/20200717035207_add_directory_to_proxy.rb: -------------------------------------------------------------------------------- 1 | class AddDirectoryToProxy < ActiveRecord::Migration[6.0] 2 | def up 3 | add_column :wordpress_proxies, :directory, :string 4 | end 5 | 6 | def down 7 | remove_column :wordpress_proxies, :directory 8 | end 9 | end 10 | -------------------------------------------------------------------------------- /core/db/migrate/20200717132029_remove_domain_to_server.rb: -------------------------------------------------------------------------------- 1 | class RemoveDomainToServer < ActiveRecord::Migration[6.0] 2 | 3 | def up 4 | remove_column :wordpress_servers, :domain 5 | end 6 | 7 | def down 8 | add_column :wordpress_servers, :domain, :string, null: false, default: "" 9 | end 10 | 11 | end 12 | -------------------------------------------------------------------------------- /core/db/migrate/20200724094508_add_download_url_to_blogs.rb: -------------------------------------------------------------------------------- 1 | class AddDownloadUrlToBlogs < ActiveRecord::Migration[6.0] 2 | 3 | def up 4 | add_column :wordpress_blogs, :download_url, :string 5 | end 6 | 7 | def down 8 | remove_column :wordpress_blogs, :download_url 9 | end 10 | 11 | end 12 | -------------------------------------------------------------------------------- /core/db/migrate/20200726082042_add_trackable_to_admin_user.rb: -------------------------------------------------------------------------------- 1 | class AddTrackableToAdminUser < ActiveRecord::Migration[6.0] 2 | def up 3 | add_column :admin_users, :sign_in_count, :integer , default: 0, null: false 4 | add_column :admin_users, :current_sign_in_at, :datetime 5 | add_column :admin_users, :last_sign_in_at, :datetime 6 | add_column :admin_users, :current_sign_in_ip, :string 7 | add_column :admin_users, :last_sign_in_ip, :string 8 | end 9 | 10 | def down 11 | remove_column :admin_users, :sign_in_count 12 | remove_column :admin_users, :current_sign_in_at 13 | remove_column :admin_users, :last_sign_in_at 14 | remove_column :admin_users, :current_sign_in_ip 15 | remove_column :admin_users, :last_sign_in_ip 16 | end 17 | end 18 | -------------------------------------------------------------------------------- /core/db/migrate/20200728095718_add_user_id_to_cloudflares.rb: -------------------------------------------------------------------------------- 1 | class AddUserIdToCloudflares < ActiveRecord::Migration[6.0] 2 | def self.up 3 | add_column :wordpress_cloudflares, :user_id, :string 4 | end 5 | def self.down 6 | remove_column :wordpress_cloudflares, :user_id 7 | end 8 | end 9 | -------------------------------------------------------------------------------- /core/db/migrate/20200728124406_add_zone_id_to_cloudflares.rb: -------------------------------------------------------------------------------- 1 | class AddZoneIdToCloudflares < ActiveRecord::Migration[6.0] 2 | def self.up 3 | add_column :wordpress_cloudflares, :zone_id, :string 4 | end 5 | def self.down 6 | remove_column :wordpress_cloudflares, :zone_id 7 | end 8 | end 9 | -------------------------------------------------------------------------------- /core/db/migrate/20200729052427_add_account_id_to_cloudflares.rb: -------------------------------------------------------------------------------- 1 | class AddAccountIdToCloudflares < ActiveRecord::Migration[6.0] 2 | def self.up 3 | add_column :wordpress_cloudflares, :account_id, :string 4 | end 5 | def self.down 6 | remove_column :wordpress_cloudflares, :account_id 7 | end 8 | end 9 | -------------------------------------------------------------------------------- /core/db/migrate/20200729084505_add_zone_id_to_domains.rb: -------------------------------------------------------------------------------- 1 | class AddZoneIdToDomains < ActiveRecord::Migration[6.0] 2 | def self.up 3 | add_column :wordpress_domains, :zone_id, :string 4 | end 5 | def self.down 6 | remove_column :wordpress_domains, :zone_id 7 | end 8 | end 9 | -------------------------------------------------------------------------------- /core/db/migrate/20200730071621_create_wordpress_monitors.rb: -------------------------------------------------------------------------------- 1 | class CreateWordpressMonitors < ActiveRecord::Migration[6.0] 2 | def change 3 | create_table :wordpress_monitors do |t| 4 | t.belongs_to :blog 5 | t.string :state 6 | t.string :action 7 | t.datetime :queued_at 8 | t.datetime :completed_at 9 | t.timestamps 10 | end 11 | end 12 | end 13 | -------------------------------------------------------------------------------- /core/lib/generators/wordpress/install/install_generator.rb: -------------------------------------------------------------------------------- 1 | require 'rails/generators' 2 | 3 | # require 'amz/core' 4 | 5 | module Wordpress 6 | module Generators 7 | class InstallGenerator < Rails::Generators::Base 8 | source_root File.expand_path("../templates", __dir__) 9 | 10 | def add_stylesheets 11 | file_path = 'app/assets/stylesheets/active_admin' 12 | begin 13 | append_file("#{file_path}.scss", css_assets) 14 | rescue 15 | append_file("#{file_path}.css.scss", css_assets) 16 | end 17 | end 18 | 19 | def add_javascripts 20 | file_path = 'app/assets/javascripts/active_admin' 21 | append_file("#{file_path}.js", js_assets) 22 | end 23 | 24 | def install_active_admin_role 25 | run 'rails g active_admin_role:install' 26 | end 27 | 28 | def install_activeadmin_addons 29 | run 'rails active_storage:install' 30 | run 'rails g activeadmin_addons:install' 31 | end 32 | 33 | def add_migrations 34 | run 'bundle exec rake railties:install:migrations FROM=wordpress' 35 | end 36 | 37 | def copy_initializer_file 38 | template "initializer.tt", "config/initializers/wordpress.rb" 39 | template "sidekiq.tt", "config/initializers/sidekiq.rb" 40 | template "sidekiq.yml", "config/sidekiq.yml" 41 | end 42 | 43 | def notify_about_routes 44 | insert_into_file(File.join('config', 'routes.rb'), 45 | after: "Rails.application.routes.draw do\n") do 46 | <<-ROUTES.strip_heredoc.indent!(2) 47 | # This line mounts Am z's routes at the root of your application. 48 | # This means, any requests to URLs such as /products, will go to 49 | # Amz::ProductsController. 50 | # If you would like to change where this engine is mounted, simply change the 51 | # :at option to something different. 52 | # 53 | # We ask that you don't use the :as option here, as Amz relies on it being 54 | # the default of "spree". 55 | mount Wordpress::Core::Engine, at: '/' 56 | ROUTES 57 | end 58 | 59 | unless options[:quiet] 60 | puts '*' * 50 61 | puts "We added the following line to your application's config/routes.rb file:" 62 | puts ' ' 63 | puts " mount Wordpress::Core::Engine, at: '/'" 64 | end 65 | end 66 | 67 | def ck_js 68 | insert_into_file(File.join('config/initializers', 'active_admin.rb'), after: "ActiveAdmin.setup do |config|\n") do 69 | <<-EOF 70 | config.register_javascript 'chartkick' 71 | config.register_javascript 'Chart.bundle' 72 | config.favicon = 'wordpress/favicon.ico' 73 | config.site_title_image = 'wordpress/logo.png' 74 | EOF 75 | end 76 | end 77 | 78 | def install_js_packages 79 | packages = " chartkick" 80 | packages += " chart.js" 81 | run "yarn add #{packages}" 82 | end 83 | 84 | private 85 | 86 | def js_assets 87 | to_add = "//= require active_admin/amz\n" 88 | end 89 | 90 | def coffee_assets 91 | to_add = "#= require active_admin/amz\n" 92 | end 93 | 94 | def css_assets 95 | "@import 'active_admin/amz';\n" 96 | end 97 | 98 | end 99 | end 100 | end -------------------------------------------------------------------------------- /core/lib/generators/wordpress/templates/initializer.tt: -------------------------------------------------------------------------------- 1 | Wordpress.configure do |config| 2 | 3 | end -------------------------------------------------------------------------------- /core/lib/generators/wordpress/templates/sidekiq.tt: -------------------------------------------------------------------------------- 1 | Sidekiq.configure_server do |config| 2 | config.redis = { url: 'redis://127.0.0.1:6379/12' } 3 | #config.log_formatter = Sidekiq::Logger::Formatters::JSON.new 4 | end 5 | Sidekiq.configure_client do |config| 6 | config.redis = { url: 'redis://127.0.0.1:6379/12' } 7 | end -------------------------------------------------------------------------------- /core/lib/generators/wordpress/templates/sidekiq.yml: -------------------------------------------------------------------------------- 1 | --- 2 | :verbose: false 3 | :pidfile: ./tmp/pids/sidekiq.pid 4 | :logfile: ./log/sidekiq.log 5 | :concurrency: 4 6 | :queues: 7 | - default 8 | - mailers 9 | - wordpress 10 | -------------------------------------------------------------------------------- /core/lib/tasks/wordpress_sidekiq_task.rake: -------------------------------------------------------------------------------- 1 | namespace :sidekiq do 2 | sidekiq_pid_file = Rails.root+'/tmp/pids/sidekiq.pid' 3 | 4 | desc "Sidekiq stop" 5 | task :stop do 6 | puts "#### Trying to stop Sidekiq Now !!! ####" 7 | if File.exist?(sidekiq_pid_file) 8 | puts "Stopping sidekiq now #PID-#{File.readlines(sidekiq_pid_file).first}..." 9 | system "sidekiqctl stop #{Rails.root}/tmp/pids/sidekiq.pid" # stops sidekiq process here 10 | else 11 | puts "--- Sidekiq Not Running !!!" 12 | end 13 | end 14 | 15 | desc "Sidekiq start" 16 | task :start do 17 | puts "Starting Sidekiq..." 18 | system "bundle exec sidekiq -e#{Rails.env} -C #{Rails.root}/config/sidekiq.yml" # starts sidekiq process here 19 | sleep(2) 20 | puts "Sidekiq started #PID-#{File.readlines(sidekiq_pid_file).first}." 21 | end 22 | 23 | desc "Sidekiq restart" 24 | task :restart do 25 | puts "#### Trying to restart Sidekiq Now !!! ####" 26 | Rake::Task['sidekiq:stop'].invoke 27 | Rake::Task['sidekiq:start'].invoke 28 | puts "#### Sidekiq restarted successfully !!! ####" 29 | end 30 | end -------------------------------------------------------------------------------- /core/lib/tasks/wordpress_tasks.rake: -------------------------------------------------------------------------------- 1 | # desc "Explaining what the task does" 2 | # task :wordpress_core do 3 | # # Task goes here 4 | # end 5 | namespace :wordpress do 6 | desc "Initial" 7 | task :init => :environment do 8 | unless Wordpress::Locale.first 9 | Wordpress::Locale.create(name: 'English (United States)', code: 'en-US', position: 1) 10 | Wordpress::Locale.create(name: 'English (United Kingdom)', code: 'en-GB', position: 2) 11 | Wordpress::Locale.create(name: 'English (Australia)', code: 'en-AU', position: 3) 12 | Wordpress::Locale.create(name: 'English (Canada)', code: 'en-CA', position: 4) 13 | Wordpress::Locale.create(name: 'English (India)', code: 'en-IN', position: 4) 14 | Wordpress::Locale.create(name: 'Spanish (Spain)', code: 'es-ES', position: 4) 15 | end 16 | end 17 | 18 | task :monitor_blog => :environment do 19 | blogs = Blog.publishedBlog.published 20 | puts "Monitor BLog Job #{blogs.size}" 21 | blogs.each do |blog| 22 | blog.monitors.create(action: blog.check_online_job_class_name) 23 | end 24 | end 25 | end -------------------------------------------------------------------------------- /core/lib/wordpress/auth/devish.rb: -------------------------------------------------------------------------------- 1 | require 'devise' 2 | require 'devise-encryptable' 3 | Devise.secret_key = SecureRandom.hex(50) 4 | 5 | module Wordpress 6 | module Auth 7 | mattr_accessor :default_secret_key 8 | 9 | def self.config 10 | yield(Wordpress::Auth::Config) 11 | end 12 | 13 | end 14 | end 15 | 16 | Wordpress::Auth.default_secret_key = Devise.secret_key 17 | -------------------------------------------------------------------------------- /core/lib/wordpress/core.rb: -------------------------------------------------------------------------------- 1 | require "wordpress/core/engine" 2 | require 'rails/all' 3 | require 'paranoia' 4 | require 'sidekiq' 5 | require 'rest-client' 6 | require 'mysql2' 7 | require 'state_machine' 8 | require 'net/ssh' 9 | require 'net/sftp' 10 | require 'wordpress/auth/devish' 11 | 12 | #helpers 13 | require 'wordpress/core/helpers/cloudflare_api' 14 | require "wordpress/core/helpers/mysql" 15 | require "wordpress/core/helpers/mysql2_client" 16 | require "wordpress/core/helpers/apache" 17 | 18 | module Wordpress 19 | ROOT_PATH = Pathname.new(File.join(__dir__, "../../")) 20 | 21 | # Used to configure Wordpress. 22 | # 23 | # Example: 24 | # 25 | # Wordpress.configure do |config| 26 | # config.track_inventory_levels = false 27 | # end 28 | # 29 | # This method is defined within the core gem on purpose. 30 | # Some people may only wish to use the Core part of Wordpress. 31 | def self.configure 32 | yield(Wordpress::Config) 33 | end 34 | 35 | def self.config 36 | yield(Wordpress::Config) 37 | end 38 | 39 | module Core 40 | autoload :TokenGenerator, 'wordpress/core/token_generator' 41 | end 42 | 43 | end 44 | 45 | -------------------------------------------------------------------------------- /core/lib/wordpress/core/engine.rb: -------------------------------------------------------------------------------- 1 | 2 | module Wordpress 3 | module Core 4 | class Engine < ::Rails::Engine 5 | Environment = Struct.new( 6 | :preferences, 7 | ) 8 | 9 | isolate_namespace Wordpress 10 | engine_name 'wordpress' 11 | 12 | initializer 'wordpress.environment', before: :load_config_initializers do |app| 13 | app.config.wordpress = Environment.new( Wordpress::AppConfiguration.new ) 14 | Wordpress::Config = app.config.wordpress.preferences 15 | end 16 | 17 | initializer "wordpress.active_job" do |app| 18 | app.config.active_job.queue_adapter = :sidekiq 19 | end 20 | 21 | initializer "wordpress.auth.environment", before: :load_config_initializers do |_app| 22 | Wordpress::Auth::Config = Wordpress::AuthConfiguration.new 23 | end 24 | 25 | initializer "wordpress_auth_devise.check_secret_token" do 26 | if Wordpress::Auth.default_secret_key == Devise.secret_key 27 | puts "[WARNING] You are not setting Devise.secret_key within your application!" 28 | puts "You must set this in config/initializers/devise.rb. Here's an example:" 29 | puts " " 30 | puts %{Devise.secret_key = "#{SecureRandom.hex(50)}"} 31 | end 32 | end 33 | 34 | end 35 | end 36 | end 37 | require 'wordpress/core/routes' 38 | -------------------------------------------------------------------------------- /core/lib/wordpress/core/helpers/apache.rb: -------------------------------------------------------------------------------- 1 | module Wordpress 2 | module Core 3 | module Helpers 4 | class Apache 5 | attr_reader :ssh_info, :virtual 6 | 7 | def initialize( virtual ) 8 | @virtual = virtual 9 | end 10 | 11 | def create_virtual_host(wordpress = '/wordpress/', server_alias = nil) 12 | vhost_file = "/etc/httpd/conf.d/vhost/#{conf_file_name}" 13 | ssh = " 14 | mkdir /etc/httpd/conf.d/vhost -p 15 | echo \"#{virtual_host(wordpress)}\" > #{vhost_file} 16 | service httpd restart 17 | echo 'Restart OK' 18 | " 19 | end 20 | 21 | def mkdir_directory 22 | "mkdir #{virtual[:directory]} -p" 23 | end 24 | 25 | def download_and_install(options) 26 | wordpress_config = "wordpress/wp-config.php" 27 | " 28 | #{mkdir_directory} 29 | if [ ! -f \"#{virtual[:directory]}/#{options[:template][:file_name]}\" ];then 30 | cd #{virtual[:directory]} && wget #{virtual[:wordpress_down_url]} && tar xf #{options[:template][:file_name]} && chown apache:apache ./ -R 31 | sed -i \"s/#{ options[:template][:mysql_user]}/#{options[:blog][:mysql_user]}/g\" #{wordpress_config} 32 | sed -i \"s/#{ options[:template][:mysql_password]}/#{options[:blog][:mysql_password]}/g\" #{wordpress_config} 33 | sed -i \"s/#{ options[:template][:mysql_host] }/#{options[:blog][:mysql_host]}/g\" #{wordpress_config} 34 | sed -i \"/'WP_DEBUG'/a\\\if (\\\$_SERVER['HTTP_X_FORWARDED_HOST']) { \\\$scheme = 'http://'; if (\\\$_SERVER['HTTPS']=='on') { \\\$scheme = 'https://' ;} \\\$home = \\\$scheme.\\\$_SERVER['HTTP_X_FORWARDED_HOST']; \\\$siteurl = \\\$scheme.\\\$_SERVER['HTTP_X_FORWARDED_HOST']; define('WP_HOME', \\\$home); define('WP_SITEURL', \\\$siteurl); }\" #{wordpress_config} 35 | sed -i \"/'WP_DEBUG'/a\\\if (\\\$_SERVER['HTTP_X_FORWARDED_PROTO']=='https') { \\\$_SERVER['HTTPS'] = 'on'; }\" #{wordpress_config} 36 | sed -i \"s/#{options[:template][:id]}\\\/wordpress\\\///g\" #{virtual[:directory]}/wordpress/.htaccess 37 | fi 38 | " 39 | end 40 | 41 | private 42 | 43 | 44 | def conf_file_name 45 | "#{virtual[:server_name]}.conf" 46 | end 47 | 48 | def virtual_host(wordpress, server_alias = nil) 49 | server_alias = "ServerAlias #{server_alias}" unless server_alias.blank? 50 | " 51 | 52 | ServerName #{virtual[:server_name]} 53 | #{server_alias} 54 | DocumentRoot #{virtual[:directory]}#{wordpress} 55 | 56 | Options All 57 | AllowOverride All 58 | Require all granted 59 | 60 | 61 | php_admin_value open_basedir #{virtual[:directory]}#{wordpress}:/tmp/ 62 | 63 | 64 | php_value open_basedir #{virtual[:directory]}#{wordpress}:/tmp/ 65 | 66 | 67 | " 68 | end 69 | end 70 | end 71 | end 72 | end -------------------------------------------------------------------------------- /core/lib/wordpress/core/helpers/mysql.rb: -------------------------------------------------------------------------------- 1 | # require 'wordpress/core/helpers/mysql' 2 | # ssh_info = { host: '127.0.0.1', user: 'root', password: 'password' } 3 | # mysql = { user: 'root', user_host: '127.0.0.1' , user_password: 'user_password', database: "user_database", collection_user: "root", collection_password: "pwd", collection_host: "127.0.0.1" } 4 | # my = Wordpress::Core::Helpers::Mysql.new( ssh_info, mysql) 5 | # Net::SSH.start( ssh_info[:host], ssh_info[:user] , :password => ssh_info[:password]) do |ssh| 6 | module Wordpress 7 | module Core 8 | module Helpers 9 | class Mysql 10 | attr_reader :mysql 11 | 12 | def initialize( mysql ) 13 | @mysql = mysql 14 | end 15 | 16 | def create_db_and_user 17 | "echo '#{create_database} #{create_mysql_user} #{mysql_grant} show databases;' | #{collection_mysql}" 18 | end 19 | 20 | def import_mysql(file_path) 21 | "#{collection_mysql} #{mysql[:database]} < #{file_path}" 22 | end 23 | 24 | def dump_mysql 25 | "mysqldump -u#{mysql[:collection_user]} -p#{mysql[:collection_password]} -h#{mysql[:collection_host]} #{mysql[:database]} > #{mysql[:database]}.sql" 26 | end 27 | 28 | def only_update_password(wp_password, wp_user) 29 | "echo 'show databases; use #{mysql[:database]}; #{update_password(wp_password, wp_user)}' | #{collection_mysql} " 30 | end 31 | 32 | def only_update_siteurl(new_url) 33 | "echo 'show databases; use #{mysql[:database]}; #{update_siteurl(new_url)}' | #{collection_mysql}" 34 | end 35 | 36 | def collection 37 | collection_mysql 38 | end 39 | 40 | def import_mysql_sql(file_path) 41 | "show databases; use #{mysql[:database]}; source #{file_path};" 42 | end 43 | 44 | private 45 | 46 | def update_password(wp_password, wp_user= 'admin') 47 | "update wp_users set user_pass=md5(\"#{wp_password}\"), user_login=\"#{wp_user}\", user_nicename=\"#{wp_user}\" where id=1;" 48 | end 49 | 50 | def update_siteurl(new_url) 51 | "update wp_options set option_value=\"#{new_url}\" where option_name=\"siteurl\"; 52 | update wp_options set option_value=\"#{new_url}\" where option_name=\"home\";" 53 | end 54 | 55 | def create_database 56 | "create database IF not EXISTS #{mysql[:database]};" 57 | end 58 | 59 | def create_mysql_user 60 | "CREATE USER \"#{mysql[:user]}\"@\"#{mysql[:user_host]}\" IDENTIFIED BY \"#{mysql[:user_password]}\";" 61 | end 62 | 63 | def mysql_grant 64 | "GRANT ALL PRIVILEGES ON #{mysql[:database]} .* TO \"#{mysql[:user]}\"@\"#{mysql[:user_host]}\";" 65 | end 66 | 67 | def collection_mysql 68 | "mysql -u#{mysql[:collection_user]} -p#{mysql[:collection_password]} -h#{mysql[:collection_host]}" 69 | end 70 | 71 | end 72 | end 73 | end 74 | end -------------------------------------------------------------------------------- /core/lib/wordpress/core/routes.rb: -------------------------------------------------------------------------------- 1 | module Wordpress 2 | module Core 3 | class Engine < ::Rails::Engine 4 | def self.add_routes(&block) 5 | @amz_routes ||= [] 6 | 7 | # Anything that causes the application's routes to be reloaded, 8 | # will cause this method to be called more than once 9 | # i.e. https://github.com/plataformatec/devise/blob/31971e69e6a1bcf6c7f01eaaa44f227c4af5d4d2/lib/devise/rails.rb#L14 10 | # In the case of Devise, this *only* happens in the production env 11 | # This coupled with Rails 4's insistence that routes are not drawn twice, 12 | # poses quite a serious problem. 13 | # 14 | # This is mainly why this whole file exists in the first place. 15 | # 16 | # Thus we need to make sure that the routes aren't drawn twice. 17 | @amz_routes << block unless @amz_routes.include?(block) 18 | end 19 | 20 | def self.append_routes(&block) 21 | @append_routes ||= [] 22 | # See comment in add_routes. 23 | @append_routes << block unless @append_routes.include?(block) 24 | end 25 | 26 | def self.draw_routes(&block) 27 | @amz_routes ||= [] 28 | @append_routes ||= [] 29 | eval_block(block) if block_given? 30 | @amz_routes.each { |r| eval_block(&r) } 31 | @append_routes.each { |r| eval_block(&r) } 32 | # # Clear out routes so that they aren't drawn twice. 33 | @amz_routes = [] 34 | @append_routes = [] 35 | end 36 | 37 | def eval_block(&block) 38 | Wordpress::Core::Engine.routes.send :eval_block, block 39 | end 40 | end 41 | end 42 | end -------------------------------------------------------------------------------- /core/lib/wordpress/core/token_generator.rb: -------------------------------------------------------------------------------- 1 | module Wordpress 2 | module Core 3 | module TokenGenerator 4 | def generate_token(model_class = Wordpress::ApiToken, key_name = 'key') 5 | loop do 6 | token = "#{random_token}#{unique_ending}" 7 | break token unless model_class.exists?("#{key_name}": token) 8 | end 9 | end 10 | 11 | private 12 | 13 | def random_token 14 | SecureRandom.urlsafe_base64(nil, false) 15 | end 16 | 17 | def unique_ending 18 | (Time.now.to_f * 1000).to_i 19 | end 20 | end 21 | end 22 | end 23 | -------------------------------------------------------------------------------- /core/lib/wordpress/core/version.rb: -------------------------------------------------------------------------------- 1 | module Wordpress 2 | VERSION = '1.1.2' 3 | end 4 | -------------------------------------------------------------------------------- /core/lib/wordpress_core.rb: -------------------------------------------------------------------------------- 1 | require "wordpress/core" 2 | 3 | -------------------------------------------------------------------------------- /core/test/dummy/.ruby-version: -------------------------------------------------------------------------------- 1 | ruby-2.5.1 2 | -------------------------------------------------------------------------------- /core/test/dummy/Rakefile: -------------------------------------------------------------------------------- 1 | # Add your own tasks in files placed in lib/tasks ending in .rake, 2 | # for example lib/tasks/capistrano.rake, and they will automatically be available to Rake. 3 | 4 | require_relative 'config/application' 5 | 6 | Rails.application.load_tasks 7 | -------------------------------------------------------------------------------- /core/test/dummy/app/assets/config/manifest.js: -------------------------------------------------------------------------------- 1 | //= link_tree ../images 2 | //= link_directory ../stylesheets .css 3 | -------------------------------------------------------------------------------- /core/test/dummy/app/assets/images/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/seadfeng/cloud_wordpress/b89f027ce3c7a82972d8279e70faf8ffee96749a/core/test/dummy/app/assets/images/.keep -------------------------------------------------------------------------------- /core/test/dummy/app/assets/stylesheets/application.css: -------------------------------------------------------------------------------- 1 | /* 2 | * This is a manifest file that'll be compiled into application.css, which will include all the files 3 | * listed below. 4 | * 5 | * Any CSS and SCSS file within this directory, lib/assets/stylesheets, vendor/assets/stylesheets, 6 | * or any plugin's vendor/assets/stylesheets directory can be referenced here using a relative path. 7 | * 8 | * You're free to add application-wide styles to this file and they'll appear at the bottom of the 9 | * compiled file so the styles you add here take precedence over styles defined in any other CSS/SCSS 10 | * files in this directory. Styles in this file should be added after the last require_* statement. 11 | * It is generally better to create a new file per style scope. 12 | * 13 | *= require_tree . 14 | *= require_self 15 | */ 16 | -------------------------------------------------------------------------------- /core/test/dummy/app/channels/application_cable/channel.rb: -------------------------------------------------------------------------------- 1 | module ApplicationCable 2 | class Channel < ActionCable::Channel::Base 3 | end 4 | end 5 | -------------------------------------------------------------------------------- /core/test/dummy/app/channels/application_cable/connection.rb: -------------------------------------------------------------------------------- 1 | module ApplicationCable 2 | class Connection < ActionCable::Connection::Base 3 | end 4 | end 5 | -------------------------------------------------------------------------------- /core/test/dummy/app/controllers/application_controller.rb: -------------------------------------------------------------------------------- 1 | class ApplicationController < ActionController::Base 2 | end 3 | -------------------------------------------------------------------------------- /core/test/dummy/app/controllers/concerns/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/seadfeng/cloud_wordpress/b89f027ce3c7a82972d8279e70faf8ffee96749a/core/test/dummy/app/controllers/concerns/.keep -------------------------------------------------------------------------------- /core/test/dummy/app/helpers/application_helper.rb: -------------------------------------------------------------------------------- 1 | module ApplicationHelper 2 | end 3 | -------------------------------------------------------------------------------- /core/test/dummy/app/javascript/packs/application.js: -------------------------------------------------------------------------------- 1 | // This is a manifest file that'll be compiled into application.js, which will include all the files 2 | // listed below. 3 | // 4 | // Any JavaScript/Coffee file within this directory, lib/assets/javascripts, vendor/assets/javascripts, 5 | // or any plugin's vendor/assets/javascripts directory can be referenced here using a relative path. 6 | // 7 | // It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the 8 | // compiled file. JavaScript code in this file should be added after the last require_* statement. 9 | // 10 | // Read Sprockets README (https://github.com/rails/sprockets#sprockets-directives) for details 11 | // about supported directives. 12 | // 13 | //= require rails-ujs 14 | //= require activestorage 15 | //= require_tree . 16 | -------------------------------------------------------------------------------- /core/test/dummy/app/jobs/application_job.rb: -------------------------------------------------------------------------------- 1 | class ApplicationJob < ActiveJob::Base 2 | # Automatically retry jobs that encountered a deadlock 3 | # retry_on ActiveRecord::Deadlocked 4 | 5 | # Most jobs are safe to ignore if the underlying records are no longer available 6 | # discard_on ActiveJob::DeserializationError 7 | end 8 | -------------------------------------------------------------------------------- /core/test/dummy/app/mailers/application_mailer.rb: -------------------------------------------------------------------------------- 1 | class ApplicationMailer < ActionMailer::Base 2 | default from: 'from@example.com' 3 | layout 'mailer' 4 | end 5 | -------------------------------------------------------------------------------- /core/test/dummy/app/models/application_record.rb: -------------------------------------------------------------------------------- 1 | class ApplicationRecord < ActiveRecord::Base 2 | self.abstract_class = true 3 | end 4 | -------------------------------------------------------------------------------- /core/test/dummy/app/models/concerns/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/seadfeng/cloud_wordpress/b89f027ce3c7a82972d8279e70faf8ffee96749a/core/test/dummy/app/models/concerns/.keep -------------------------------------------------------------------------------- /core/test/dummy/app/views/layouts/application.html.erb: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Dummy 5 | <%= csrf_meta_tags %> 6 | <%= csp_meta_tag %> 7 | 8 | <%= stylesheet_link_tag 'application', media: 'all' %> 9 | 10 | 11 | 12 | <%= yield %> 13 | 14 | 15 | -------------------------------------------------------------------------------- /core/test/dummy/app/views/layouts/mailer.html.erb: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 8 | 9 | 10 | 11 | <%= yield %> 12 | 13 | 14 | -------------------------------------------------------------------------------- /core/test/dummy/app/views/layouts/mailer.text.erb: -------------------------------------------------------------------------------- 1 | <%= yield %> 2 | -------------------------------------------------------------------------------- /core/test/dummy/bin/rails: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | APP_PATH = File.expand_path('../config/application', __dir__) 3 | require_relative '../config/boot' 4 | require 'rails/commands' 5 | -------------------------------------------------------------------------------- /core/test/dummy/bin/rake: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | require_relative '../config/boot' 3 | require 'rake' 4 | Rake.application.run 5 | -------------------------------------------------------------------------------- /core/test/dummy/bin/setup: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | require 'fileutils' 3 | 4 | # path to your application root. 5 | APP_ROOT = File.expand_path('..', __dir__) 6 | 7 | def system!(*args) 8 | system(*args) || abort("\n== Command #{args} failed ==") 9 | end 10 | 11 | FileUtils.chdir APP_ROOT do 12 | # This script is a way to setup or update your development environment automatically. 13 | # This script is idempotent, so that you can run it at anytime and get an expectable outcome. 14 | # Add necessary setup steps to this file. 15 | 16 | puts '== Installing dependencies ==' 17 | system! 'gem install bundler --conservative' 18 | system('bundle check') || system!('bundle install') 19 | 20 | # puts "\n== Copying sample files ==" 21 | # unless File.exist?('config/database.yml') 22 | # FileUtils.cp 'config/database.yml.sample', 'config/database.yml' 23 | # end 24 | 25 | puts "\n== Preparing database ==" 26 | system! 'bin/rails db:prepare' 27 | 28 | puts "\n== Removing old logs and tempfiles ==" 29 | system! 'bin/rails log:clear tmp:clear' 30 | 31 | puts "\n== Restarting application server ==" 32 | system! 'bin/rails restart' 33 | end 34 | -------------------------------------------------------------------------------- /core/test/dummy/config.ru: -------------------------------------------------------------------------------- 1 | # This file is used by Rack-based servers to start the application. 2 | 3 | require_relative 'config/environment' 4 | 5 | run Rails.application 6 | -------------------------------------------------------------------------------- /core/test/dummy/config/application.rb: -------------------------------------------------------------------------------- 1 | require_relative 'boot' 2 | 3 | require 'rails/all' 4 | 5 | Bundler.require(*Rails.groups) 6 | require "wordpress_core" 7 | 8 | module Dummy 9 | class Application < Rails::Application 10 | # Initialize configuration defaults for originally generated Rails version. 11 | config.load_defaults 6.0 12 | 13 | # Settings in config/environments/* take precedence over those specified here. 14 | # Application configuration can go into files in config/initializers 15 | # -- all .rb files in that directory are automatically loaded after loading 16 | # the framework and any gems in your application. 17 | end 18 | end 19 | 20 | -------------------------------------------------------------------------------- /core/test/dummy/config/boot.rb: -------------------------------------------------------------------------------- 1 | # Set up gems listed in the Gemfile. 2 | ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../../Gemfile', __dir__) 3 | 4 | require 'bundler/setup' if File.exist?(ENV['BUNDLE_GEMFILE']) 5 | $LOAD_PATH.unshift File.expand_path('../../../lib', __dir__) 6 | -------------------------------------------------------------------------------- /core/test/dummy/config/cable.yml: -------------------------------------------------------------------------------- 1 | development: 2 | adapter: async 3 | 4 | test: 5 | adapter: test 6 | 7 | production: 8 | adapter: redis 9 | url: <%= ENV.fetch("REDIS_URL") { "redis://localhost:6379/1" } %> 10 | channel_prefix: dummy_production 11 | -------------------------------------------------------------------------------- /core/test/dummy/config/database.yml: -------------------------------------------------------------------------------- 1 | # SQLite. Versions 3.8.0 and up are supported. 2 | # gem install sqlite3 3 | # 4 | # Ensure the SQLite 3 gem is defined in your Gemfile 5 | # gem 'sqlite3' 6 | # 7 | default: &default 8 | adapter: sqlite3 9 | pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %> 10 | timeout: 5000 11 | 12 | development: 13 | <<: *default 14 | database: db/development.sqlite3 15 | 16 | # Warning: The database defined as "test" will be erased and 17 | # re-generated from your development database when you run "rake". 18 | # Do not set this db to the same as development or production. 19 | test: 20 | <<: *default 21 | database: db/test.sqlite3 22 | 23 | production: 24 | <<: *default 25 | database: db/production.sqlite3 26 | -------------------------------------------------------------------------------- /core/test/dummy/config/environment.rb: -------------------------------------------------------------------------------- 1 | # Load the Rails application. 2 | require_relative 'application' 3 | 4 | # Initialize the Rails application. 5 | Rails.application.initialize! 6 | -------------------------------------------------------------------------------- /core/test/dummy/config/environments/development.rb: -------------------------------------------------------------------------------- 1 | Rails.application.configure do 2 | # Settings specified here will take precedence over those in config/application.rb. 3 | 4 | # In the development environment your application's code is reloaded on 5 | # every request. This slows down response time but is perfect for development 6 | # since you don't have to restart the web server when you make code changes. 7 | config.cache_classes = false 8 | 9 | # Do not eager load code on boot. 10 | config.eager_load = false 11 | 12 | # Show full error reports. 13 | config.consider_all_requests_local = true 14 | 15 | # Enable/disable caching. By default caching is disabled. 16 | # Run rails dev:cache to toggle caching. 17 | if Rails.root.join('tmp', 'caching-dev.txt').exist? 18 | config.action_controller.perform_caching = true 19 | config.action_controller.enable_fragment_cache_logging = true 20 | 21 | config.cache_store = :memory_store 22 | config.public_file_server.headers = { 23 | 'Cache-Control' => "public, max-age=#{2.days.to_i}" 24 | } 25 | else 26 | config.action_controller.perform_caching = false 27 | 28 | config.cache_store = :null_store 29 | end 30 | 31 | # Store uploaded files on the local file system (see config/storage.yml for options). 32 | config.active_storage.service = :local 33 | 34 | # Don't care if the mailer can't send. 35 | config.action_mailer.raise_delivery_errors = false 36 | 37 | config.action_mailer.perform_caching = false 38 | 39 | # Print deprecation notices to the Rails logger. 40 | config.active_support.deprecation = :log 41 | 42 | # Raise an error on page load if there are pending migrations. 43 | config.active_record.migration_error = :page_load 44 | 45 | # Highlight code that triggered database queries in logs. 46 | config.active_record.verbose_query_logs = true 47 | 48 | # Debug mode disables concatenation and preprocessing of assets. 49 | # This option may cause significant delays in view rendering with a large 50 | # number of complex assets. 51 | config.assets.debug = true 52 | 53 | # Suppress logger output for asset requests. 54 | config.assets.quiet = true 55 | 56 | # Raises error for missing translations. 57 | # config.action_view.raise_on_missing_translations = true 58 | 59 | # Use an evented file watcher to asynchronously detect changes in source code, 60 | # routes, locales, etc. This feature depends on the listen gem. 61 | # config.file_watcher = ActiveSupport::EventedFileUpdateChecker 62 | end 63 | -------------------------------------------------------------------------------- /core/test/dummy/config/environments/test.rb: -------------------------------------------------------------------------------- 1 | # The test environment is used exclusively to run your application's 2 | # test suite. You never need to work with it otherwise. Remember that 3 | # your test database is "scratch space" for the test suite and is wiped 4 | # and recreated between test runs. Don't rely on the data there! 5 | 6 | Rails.application.configure do 7 | # Settings specified here will take precedence over those in config/application.rb. 8 | 9 | config.cache_classes = false 10 | 11 | # Do not eager load code on boot. This avoids loading your whole application 12 | # just for the purpose of running a single test. If you are using a tool that 13 | # preloads Rails for running tests, you may have to set it to true. 14 | config.eager_load = false 15 | 16 | # Configure public file server for tests with Cache-Control for performance. 17 | config.public_file_server.enabled = true 18 | config.public_file_server.headers = { 19 | 'Cache-Control' => "public, max-age=#{1.hour.to_i}" 20 | } 21 | 22 | # Show full error reports and disable caching. 23 | config.consider_all_requests_local = true 24 | config.action_controller.perform_caching = false 25 | config.cache_store = :null_store 26 | 27 | # Raise exceptions instead of rendering exception templates. 28 | config.action_dispatch.show_exceptions = false 29 | 30 | # Disable request forgery protection in test environment. 31 | config.action_controller.allow_forgery_protection = false 32 | 33 | # Store uploaded files on the local file system in a temporary directory. 34 | config.active_storage.service = :test 35 | 36 | config.action_mailer.perform_caching = false 37 | 38 | # Tell Action Mailer not to deliver emails to the real world. 39 | # The :test delivery method accumulates sent emails in the 40 | # ActionMailer::Base.deliveries array. 41 | config.action_mailer.delivery_method = :test 42 | 43 | # Print deprecation notices to the stderr. 44 | config.active_support.deprecation = :stderr 45 | 46 | # Raises error for missing translations. 47 | # config.action_view.raise_on_missing_translations = true 48 | end 49 | -------------------------------------------------------------------------------- /core/test/dummy/config/initializers/application_controller_renderer.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # ActiveSupport::Reloader.to_prepare do 4 | # ApplicationController.renderer.defaults.merge!( 5 | # http_host: 'example.org', 6 | # https: false 7 | # ) 8 | # end 9 | -------------------------------------------------------------------------------- /core/test/dummy/config/initializers/assets.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # Version of your assets, change this if you want to expire all your assets. 4 | Rails.application.config.assets.version = '1.0' 5 | 6 | # Add additional assets to the asset load path. 7 | # Rails.application.config.assets.paths << Emoji.images_path 8 | 9 | # Precompile additional assets. 10 | # application.js, application.css, and all non-JS/CSS in the app/assets 11 | # folder are already added. 12 | # Rails.application.config.assets.precompile += %w( admin.js admin.css ) 13 | -------------------------------------------------------------------------------- /core/test/dummy/config/initializers/backtrace_silencers.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # You can add backtrace silencers for libraries that you're using but don't wish to see in your backtraces. 4 | # Rails.backtrace_cleaner.add_silencer { |line| line =~ /my_noisy_library/ } 5 | 6 | # You can also remove all the silencers if you're trying to debug a problem that might stem from framework code. 7 | # Rails.backtrace_cleaner.remove_silencers! 8 | -------------------------------------------------------------------------------- /core/test/dummy/config/initializers/content_security_policy.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # Define an application-wide content security policy 4 | # For further information see the following documentation 5 | # https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy 6 | 7 | # Rails.application.config.content_security_policy do |policy| 8 | # policy.default_src :self, :https 9 | # policy.font_src :self, :https, :data 10 | # policy.img_src :self, :https, :data 11 | # policy.object_src :none 12 | # policy.script_src :self, :https 13 | # policy.style_src :self, :https 14 | 15 | # # Specify URI for violation reports 16 | # # policy.report_uri "/csp-violation-report-endpoint" 17 | # end 18 | 19 | # If you are using UJS then enable automatic nonce generation 20 | # Rails.application.config.content_security_policy_nonce_generator = -> request { SecureRandom.base64(16) } 21 | 22 | # Set the nonce only to specific directives 23 | # Rails.application.config.content_security_policy_nonce_directives = %w(script-src) 24 | 25 | # Report CSP violations to a specified URI 26 | # For further information see the following documentation: 27 | # https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy-Report-Only 28 | # Rails.application.config.content_security_policy_report_only = true 29 | -------------------------------------------------------------------------------- /core/test/dummy/config/initializers/cookies_serializer.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # Specify a serializer for the signed and encrypted cookie jars. 4 | # Valid options are :json, :marshal, and :hybrid. 5 | Rails.application.config.action_dispatch.cookies_serializer = :json 6 | -------------------------------------------------------------------------------- /core/test/dummy/config/initializers/filter_parameter_logging.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # Configure sensitive parameters which will be filtered from the log file. 4 | Rails.application.config.filter_parameters += [:password] 5 | -------------------------------------------------------------------------------- /core/test/dummy/config/initializers/inflections.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # Add new inflection rules using the following format. Inflections 4 | # are locale specific, and you may define rules for as many different 5 | # locales as you wish. All of these examples are active by default: 6 | # ActiveSupport::Inflector.inflections(:en) do |inflect| 7 | # inflect.plural /^(ox)$/i, '\1en' 8 | # inflect.singular /^(ox)en/i, '\1' 9 | # inflect.irregular 'person', 'people' 10 | # inflect.uncountable %w( fish sheep ) 11 | # end 12 | 13 | # These inflection rules are supported but not enabled by default: 14 | # ActiveSupport::Inflector.inflections(:en) do |inflect| 15 | # inflect.acronym 'RESTful' 16 | # end 17 | -------------------------------------------------------------------------------- /core/test/dummy/config/initializers/mime_types.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # Add new mime types for use in respond_to blocks: 4 | # Mime::Type.register "text/richtext", :rtf 5 | -------------------------------------------------------------------------------- /core/test/dummy/config/initializers/wrap_parameters.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # This file contains settings for ActionController::ParamsWrapper which 4 | # is enabled by default. 5 | 6 | # Enable parameter wrapping for JSON. You can disable this by setting :format to an empty array. 7 | ActiveSupport.on_load(:action_controller) do 8 | wrap_parameters format: [:json] 9 | end 10 | 11 | # To enable root element in JSON for ActiveRecord objects. 12 | # ActiveSupport.on_load(:active_record) do 13 | # self.include_root_in_json = true 14 | # end 15 | -------------------------------------------------------------------------------- /core/test/dummy/config/locales/en.yml: -------------------------------------------------------------------------------- 1 | # Files in the config/locales directory are used for internationalization 2 | # and are automatically loaded by Rails. If you want to use locales other 3 | # than English, add the necessary files in this directory. 4 | # 5 | # To use the locales, use `I18n.t`: 6 | # 7 | # I18n.t 'hello' 8 | # 9 | # In views, this is aliased to just `t`: 10 | # 11 | # <%= t('hello') %> 12 | # 13 | # To use a different locale, set it with `I18n.locale`: 14 | # 15 | # I18n.locale = :es 16 | # 17 | # This would use the information in config/locales/es.yml. 18 | # 19 | # The following keys must be escaped otherwise they will not be retrieved by 20 | # the default I18n backend: 21 | # 22 | # true, false, on, off, yes, no 23 | # 24 | # Instead, surround them with single quotes. 25 | # 26 | # en: 27 | # 'true': 'foo' 28 | # 29 | # To learn more, please read the Rails Internationalization guide 30 | # available at https://guides.rubyonrails.org/i18n.html. 31 | 32 | en: 33 | hello: "Hello world" 34 | -------------------------------------------------------------------------------- /core/test/dummy/config/puma.rb: -------------------------------------------------------------------------------- 1 | # Puma can serve each request in a thread from an internal thread pool. 2 | # The `threads` method setting takes two numbers: a minimum and maximum. 3 | # Any libraries that use thread pools should be configured to match 4 | # the maximum value specified for Puma. Default is set to 5 threads for minimum 5 | # and maximum; this matches the default thread size of Active Record. 6 | # 7 | max_threads_count = ENV.fetch("RAILS_MAX_THREADS") { 5 } 8 | min_threads_count = ENV.fetch("RAILS_MIN_THREADS") { max_threads_count } 9 | threads min_threads_count, max_threads_count 10 | 11 | # Specifies the `port` that Puma will listen on to receive requests; default is 3000. 12 | # 13 | port ENV.fetch("PORT") { 3000 } 14 | 15 | # Specifies the `environment` that Puma will run in. 16 | # 17 | environment ENV.fetch("RAILS_ENV") { "development" } 18 | 19 | # Specifies the `pidfile` that Puma will use. 20 | pidfile ENV.fetch("PIDFILE") { "tmp/pids/server.pid" } 21 | 22 | # Specifies the number of `workers` to boot in clustered mode. 23 | # Workers are forked web server processes. If using threads and workers together 24 | # the concurrency of the application would be max `threads` * `workers`. 25 | # Workers do not work on JRuby or Windows (both of which do not support 26 | # processes). 27 | # 28 | # workers ENV.fetch("WEB_CONCURRENCY") { 2 } 29 | 30 | # Use the `preload_app!` method when specifying a `workers` number. 31 | # This directive tells Puma to first boot the application and load code 32 | # before forking the application. This takes advantage of Copy On Write 33 | # process behavior so workers use less memory. 34 | # 35 | # preload_app! 36 | 37 | # Allow puma to be restarted by `rails restart` command. 38 | plugin :tmp_restart 39 | -------------------------------------------------------------------------------- /core/test/dummy/config/routes.rb: -------------------------------------------------------------------------------- 1 | Rails.application.routes.draw do 2 | # For details on the DSL available within this file, see https://guides.rubyonrails.org/routing.html 3 | end 4 | -------------------------------------------------------------------------------- /core/test/dummy/config/spring.rb: -------------------------------------------------------------------------------- 1 | Spring.watch( 2 | ".ruby-version", 3 | ".rbenv-vars", 4 | "tmp/restart.txt", 5 | "tmp/caching-dev.txt" 6 | ) 7 | -------------------------------------------------------------------------------- /core/test/dummy/config/storage.yml: -------------------------------------------------------------------------------- 1 | test: 2 | service: Disk 3 | root: <%= Rails.root.join("tmp/storage") %> 4 | 5 | local: 6 | service: Disk 7 | root: <%= Rails.root.join("storage") %> 8 | 9 | # Use rails credentials:edit to set the AWS secrets (as aws:access_key_id|secret_access_key) 10 | # amazon: 11 | # service: S3 12 | # access_key_id: <%= Rails.application.credentials.dig(:aws, :access_key_id) %> 13 | # secret_access_key: <%= Rails.application.credentials.dig(:aws, :secret_access_key) %> 14 | # region: us-east-1 15 | # bucket: your_own_bucket 16 | 17 | # Remember not to checkin your GCS keyfile to a repository 18 | # google: 19 | # service: GCS 20 | # project: your_project 21 | # credentials: <%= Rails.root.join("path/to/gcs.keyfile") %> 22 | # bucket: your_own_bucket 23 | 24 | # Use rails credentials:edit to set the Azure Storage secret (as azure_storage:storage_access_key) 25 | # microsoft: 26 | # service: AzureStorage 27 | # storage_account_name: your_account_name 28 | # storage_access_key: <%= Rails.application.credentials.dig(:azure_storage, :storage_access_key) %> 29 | # container: your_container_name 30 | 31 | # mirror: 32 | # service: Mirror 33 | # primary: local 34 | # mirrors: [ amazon, google, microsoft ] 35 | -------------------------------------------------------------------------------- /core/test/dummy/lib/assets/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/seadfeng/cloud_wordpress/b89f027ce3c7a82972d8279e70faf8ffee96749a/core/test/dummy/lib/assets/.keep -------------------------------------------------------------------------------- /core/test/dummy/log/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/seadfeng/cloud_wordpress/b89f027ce3c7a82972d8279e70faf8ffee96749a/core/test/dummy/log/.keep -------------------------------------------------------------------------------- /core/test/dummy/public/404.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | The page you were looking for doesn't exist (404) 5 | 6 | 55 | 56 | 57 | 58 | 59 |
60 |
61 |

The page you were looking for doesn't exist.

62 |

You may have mistyped the address or the page may have moved.

63 |
64 |

If you are the application owner check the logs for more information.

65 |
66 | 67 | 68 | -------------------------------------------------------------------------------- /core/test/dummy/public/422.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | The change you wanted was rejected (422) 5 | 6 | 55 | 56 | 57 | 58 | 59 |
60 |
61 |

The change you wanted was rejected.

62 |

Maybe you tried to change something you didn't have access to.

63 |
64 |

If you are the application owner check the logs for more information.

65 |
66 | 67 | 68 | -------------------------------------------------------------------------------- /core/test/dummy/public/500.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | We're sorry, but something went wrong (500) 5 | 6 | 55 | 56 | 57 | 58 | 59 |
60 |
61 |

We're sorry, but something went wrong.

62 |
63 |

If you are the application owner check the logs for more information.

64 |
65 | 66 | 67 | -------------------------------------------------------------------------------- /core/test/dummy/public/apple-touch-icon-precomposed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/seadfeng/cloud_wordpress/b89f027ce3c7a82972d8279e70faf8ffee96749a/core/test/dummy/public/apple-touch-icon-precomposed.png -------------------------------------------------------------------------------- /core/test/dummy/public/apple-touch-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/seadfeng/cloud_wordpress/b89f027ce3c7a82972d8279e70faf8ffee96749a/core/test/dummy/public/apple-touch-icon.png -------------------------------------------------------------------------------- /core/test/dummy/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/seadfeng/cloud_wordpress/b89f027ce3c7a82972d8279e70faf8ffee96749a/core/test/dummy/public/favicon.ico -------------------------------------------------------------------------------- /core/test/dummy/storage/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/seadfeng/cloud_wordpress/b89f027ce3c7a82972d8279e70faf8ffee96749a/core/test/dummy/storage/.keep -------------------------------------------------------------------------------- /core/test/dummy/tmp/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/seadfeng/cloud_wordpress/b89f027ce3c7a82972d8279e70faf8ffee96749a/core/test/dummy/tmp/.keep -------------------------------------------------------------------------------- /core/test/dummy/tmp/development_secret.txt: -------------------------------------------------------------------------------- 1 | 94d02dc8e8ed3aa0755db492b59ff8e920b541d3e975957d4845e50231823ed9b9a3bf6bbe191af1861b711c34f911abf749c16e398469dfebd4b1d51122a111 -------------------------------------------------------------------------------- /core/test/dummy/tmp/pids/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/seadfeng/cloud_wordpress/b89f027ce3c7a82972d8279e70faf8ffee96749a/core/test/dummy/tmp/pids/.keep -------------------------------------------------------------------------------- /core/test/dummy/tmp/storage/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/seadfeng/cloud_wordpress/b89f027ce3c7a82972d8279e70faf8ffee96749a/core/test/dummy/tmp/storage/.keep -------------------------------------------------------------------------------- /core/test/fixtures/wordpress/api_tokens.yml: -------------------------------------------------------------------------------- 1 | # Read about fixtures at https://api.rubyonrails.org/classes/ActiveRecord/FixtureSet.html 2 | 3 | # This model initially had no columns defined. If you add columns to the 4 | # model remove the '{}' from the fixture names and add the columns immediately 5 | # below each fixture, per the syntax in the comments below 6 | # 7 | one: {} 8 | # column: value 9 | # 10 | two: {} 11 | # column: value 12 | -------------------------------------------------------------------------------- /core/test/fixtures/wordpress/blogs.yml: -------------------------------------------------------------------------------- 1 | # Read about fixtures at https://api.rubyonrails.org/classes/ActiveRecord/FixtureSet.html 2 | 3 | # This model initially had no columns defined. If you add columns to the 4 | # model remove the '{}' from the fixture names and add the columns immediately 5 | # below each fixture, per the syntax in the comments below 6 | # 7 | one: {} 8 | # column: value 9 | # 10 | two: {} 11 | # column: value 12 | -------------------------------------------------------------------------------- /core/test/fixtures/wordpress/cloudflares.yml: -------------------------------------------------------------------------------- 1 | # Read about fixtures at https://api.rubyonrails.org/classes/ActiveRecord/FixtureSet.html 2 | 3 | # This model initially had no columns defined. If you add columns to the 4 | # model remove the '{}' from the fixture names and add the columns immediately 5 | # below each fixture, per the syntax in the comments below 6 | # 7 | one: {} 8 | # column: value 9 | # 10 | two: {} 11 | # column: value 12 | -------------------------------------------------------------------------------- /core/test/fixtures/wordpress/domains.yml: -------------------------------------------------------------------------------- 1 | # Read about fixtures at https://api.rubyonrails.org/classes/ActiveRecord/FixtureSet.html 2 | 3 | # This model initially had no columns defined. If you add columns to the 4 | # model remove the '{}' from the fixture names and add the columns immediately 5 | # below each fixture, per the syntax in the comments below 6 | # 7 | one: {} 8 | # column: value 9 | # 10 | two: {} 11 | # column: value 12 | -------------------------------------------------------------------------------- /core/test/fixtures/wordpress/locales.yml: -------------------------------------------------------------------------------- 1 | # Read about fixtures at https://api.rubyonrails.org/classes/ActiveRecord/FixtureSet.html 2 | 3 | # This model initially had no columns defined. If you add columns to the 4 | # model remove the '{}' from the fixture names and add the columns immediately 5 | # below each fixture, per the syntax in the comments below 6 | # 7 | one: {} 8 | # column: value 9 | # 10 | two: {} 11 | # column: value 12 | -------------------------------------------------------------------------------- /core/test/fixtures/wordpress/monitors.yml: -------------------------------------------------------------------------------- 1 | # Read about fixtures at https://api.rubyonrails.org/classes/ActiveRecord/FixtureSet.html 2 | 3 | # This model initially had no columns defined. If you add columns to the 4 | # model remove the '{}' from the fixture names and add the columns immediately 5 | # below each fixture, per the syntax in the comments below 6 | # 7 | one: {} 8 | # column: value 9 | # 10 | two: {} 11 | # column: value 12 | -------------------------------------------------------------------------------- /core/test/fixtures/wordpress/preferences.yml: -------------------------------------------------------------------------------- 1 | # Read about fixtures at https://api.rubyonrails.org/classes/ActiveRecord/FixtureSet.html 2 | 3 | # This model initially had no columns defined. If you add columns to the 4 | # model remove the '{}' from the fixture names and add the columns immediately 5 | # below each fixture, per the syntax in the comments below 6 | # 7 | one: {} 8 | # column: value 9 | # 10 | two: {} 11 | # column: value 12 | -------------------------------------------------------------------------------- /core/test/fixtures/wordpress/proxies.yml: -------------------------------------------------------------------------------- 1 | # Read about fixtures at https://api.rubyonrails.org/classes/ActiveRecord/FixtureSet.html 2 | 3 | # This model initially had no columns defined. If you add columns to the 4 | # model remove the '{}' from the fixture names and add the columns immediately 5 | # below each fixture, per the syntax in the comments below 6 | # 7 | one: {} 8 | # column: value 9 | # 10 | two: {} 11 | # column: value 12 | -------------------------------------------------------------------------------- /core/test/fixtures/wordpress/servers.yml: -------------------------------------------------------------------------------- 1 | # Read about fixtures at https://api.rubyonrails.org/classes/ActiveRecord/FixtureSet.html 2 | 3 | # This model initially had no columns defined. If you add columns to the 4 | # model remove the '{}' from the fixture names and add the columns immediately 5 | # below each fixture, per the syntax in the comments below 6 | # 7 | one: {} 8 | # column: value 9 | # 10 | two: {} 11 | # column: value 12 | -------------------------------------------------------------------------------- /core/test/fixtures/wordpress/tags.yml: -------------------------------------------------------------------------------- 1 | # Read about fixtures at https://api.rubyonrails.org/classes/ActiveRecord/FixtureSet.html 2 | 3 | # This model initially had no columns defined. If you add columns to the 4 | # model remove the '{}' from the fixture names and add the columns immediately 5 | # below each fixture, per the syntax in the comments below 6 | # 7 | one: {} 8 | # column: value 9 | # 10 | two: {} 11 | # column: value 12 | -------------------------------------------------------------------------------- /core/test/fixtures/wordpress/tags_blogs.yml: -------------------------------------------------------------------------------- 1 | # Read about fixtures at https://api.rubyonrails.org/classes/ActiveRecord/FixtureSet.html 2 | 3 | # This model initially had no columns defined. If you add columns to the 4 | # model remove the '{}' from the fixture names and add the columns immediately 5 | # below each fixture, per the syntax in the comments below 6 | # 7 | one: {} 8 | # column: value 9 | # 10 | two: {} 11 | # column: value 12 | -------------------------------------------------------------------------------- /core/test/fixtures/wordpress/templates.yml: -------------------------------------------------------------------------------- 1 | # Read about fixtures at https://api.rubyonrails.org/classes/ActiveRecord/FixtureSet.html 2 | 3 | # This model initially had no columns defined. If you add columns to the 4 | # model remove the '{}' from the fixture names and add the columns immediately 5 | # below each fixture, per the syntax in the comments below 6 | # 7 | one: {} 8 | # column: value 9 | # 10 | two: {} 11 | # column: value 12 | -------------------------------------------------------------------------------- /core/test/models/wordpress/api_token_test.rb: -------------------------------------------------------------------------------- 1 | require 'test_helper' 2 | 3 | module Wordpress 4 | class ApiTokenTest < ActiveSupport::TestCase 5 | # test "the truth" do 6 | # assert true 7 | # end 8 | end 9 | end 10 | -------------------------------------------------------------------------------- /core/test/models/wordpress/blog_test.rb: -------------------------------------------------------------------------------- 1 | require 'test_helper' 2 | 3 | module Wordpress 4 | class BlogTest < ActiveSupport::TestCase 5 | # test "the truth" do 6 | # assert true 7 | # end 8 | end 9 | end 10 | -------------------------------------------------------------------------------- /core/test/models/wordpress/cloudflare_test.rb: -------------------------------------------------------------------------------- 1 | require 'test_helper' 2 | 3 | module Wordpress 4 | class CloudflareTest < ActiveSupport::TestCase 5 | # test "the truth" do 6 | # assert true 7 | # end 8 | end 9 | end 10 | -------------------------------------------------------------------------------- /core/test/models/wordpress/domain_test.rb: -------------------------------------------------------------------------------- 1 | require 'test_helper' 2 | 3 | module Wordpress 4 | class DomainTest < ActiveSupport::TestCase 5 | # test "the truth" do 6 | # assert true 7 | # end 8 | end 9 | end 10 | -------------------------------------------------------------------------------- /core/test/models/wordpress/locale_test.rb: -------------------------------------------------------------------------------- 1 | require 'test_helper' 2 | 3 | module Wordpress 4 | class LocaleTest < ActiveSupport::TestCase 5 | # test "the truth" do 6 | # assert true 7 | # end 8 | end 9 | end 10 | -------------------------------------------------------------------------------- /core/test/models/wordpress/monitor_test.rb: -------------------------------------------------------------------------------- 1 | require 'test_helper' 2 | 3 | module Wordpress 4 | class MonitorTest < ActiveSupport::TestCase 5 | # test "the truth" do 6 | # assert true 7 | # end 8 | end 9 | end 10 | -------------------------------------------------------------------------------- /core/test/models/wordpress/preference_test.rb: -------------------------------------------------------------------------------- 1 | require 'test_helper' 2 | 3 | module Wordpress 4 | class PreferenceTest < ActiveSupport::TestCase 5 | # test "the truth" do 6 | # assert true 7 | # end 8 | end 9 | end 10 | -------------------------------------------------------------------------------- /core/test/models/wordpress/proxy_test.rb: -------------------------------------------------------------------------------- 1 | require 'test_helper' 2 | 3 | module Wordpress 4 | class ProxyTest < ActiveSupport::TestCase 5 | # test "the truth" do 6 | # assert true 7 | # end 8 | end 9 | end 10 | -------------------------------------------------------------------------------- /core/test/models/wordpress/server_test.rb: -------------------------------------------------------------------------------- 1 | require 'test_helper' 2 | 3 | module Wordpress 4 | class ServerTest < ActiveSupport::TestCase 5 | # test "the truth" do 6 | # assert true 7 | # end 8 | end 9 | end 10 | -------------------------------------------------------------------------------- /core/test/models/wordpress/tag_test.rb: -------------------------------------------------------------------------------- 1 | require 'test_helper' 2 | 3 | module Wordpress 4 | class TagTest < ActiveSupport::TestCase 5 | # test "the truth" do 6 | # assert true 7 | # end 8 | end 9 | end 10 | -------------------------------------------------------------------------------- /core/test/models/wordpress/tags_blog_test.rb: -------------------------------------------------------------------------------- 1 | require 'test_helper' 2 | 3 | module Wordpress 4 | class TagsBlogTest < ActiveSupport::TestCase 5 | # test "the truth" do 6 | # assert true 7 | # end 8 | end 9 | end 10 | -------------------------------------------------------------------------------- /core/test/models/wordpress/template_test.rb: -------------------------------------------------------------------------------- 1 | require 'test_helper' 2 | 3 | module Wordpress 4 | class TemplateTest < ActiveSupport::TestCase 5 | # test "the truth" do 6 | # assert true 7 | # end 8 | end 9 | end 10 | -------------------------------------------------------------------------------- /core/test/test_helper.rb: -------------------------------------------------------------------------------- 1 | # Configure Rails Environment 2 | ENV["RAILS_ENV"] = "test" 3 | 4 | require_relative "../test/dummy/config/environment" 5 | ActiveRecord::Migrator.migrations_paths = [File.expand_path("../test/dummy/db/migrate", __dir__)] 6 | require "rails/test_help" 7 | 8 | # Filter out the backtrace from minitest while preserving the one from other libraries. 9 | Minitest.backtrace_filter = Minitest::BacktraceFilter.new 10 | 11 | require "rails/test_unit/reporter" 12 | Rails::TestUnitReporter.executable = 'bin/test' 13 | 14 | # Load fixtures from the engine 15 | if ActiveSupport::TestCase.respond_to?(:fixture_path=) 16 | ActiveSupport::TestCase.fixture_path = File.expand_path("fixtures", __dir__) 17 | ActionDispatch::IntegrationTest.fixture_path = ActiveSupport::TestCase.fixture_path 18 | ActiveSupport::TestCase.file_fixture_path = ActiveSupport::TestCase.fixture_path + "/files" 19 | ActiveSupport::TestCase.fixtures :all 20 | end 21 | -------------------------------------------------------------------------------- /core/test/wordpress_test.rb: -------------------------------------------------------------------------------- 1 | require 'test_helper' 2 | 3 | class Wordpress::Test < ActiveSupport::TestCase 4 | test "truth" do 5 | assert_kind_of Module, Wordpress 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /core/wordpress_core.gemspec: -------------------------------------------------------------------------------- 1 | $:.push File.expand_path("lib", __dir__) 2 | 3 | # Maintain your gem's version: 4 | require "wordpress/core/version" 5 | 6 | # Describe your gem and declare its dependencies: 7 | Gem::Specification.new do |spec| 8 | spec.name = "wordpress_core" 9 | spec.version = Wordpress::VERSION 10 | spec.authors = ["Sead Feng"] 11 | spec.email = ["seadfeng@gmail.com"] 12 | spec.homepage = "https://github.com/seadfeng/cloud_wordpress" 13 | spec.summary = "Cloud Wordpress Core" 14 | spec.description = "Wordpress Core" 15 | spec.license = "MIT" 16 | 17 | # Prevent pushing this gem to RubyGems.org. To allow pushes either set the 'allowed_push_host' 18 | # to allow pushing to a single host or delete this section to allow pushing to any host. 19 | if spec.respond_to?(:metadata) 20 | # spec.metadata["allowed_push_host"] = "TODO: Set to 'http://mygemserver.com'" 21 | else 22 | raise "RubyGems 2.0 or newer is required to protect against " \ 23 | "public gem pushes." 24 | end 25 | 26 | spec.files = Dir["{app,config,db,lib}/**/*", "MIT-LICENSE", "Rakefile", "README.md"] 27 | 28 | spec.add_dependency "rails", "~> 6.0.2", ">= 6.0.2.2" 29 | spec.add_dependency "paranoia" 30 | spec.add_dependency "devise-encryptable" 31 | 32 | spec.add_dependency "mysql2" 33 | spec.add_dependency "rest-client" 34 | spec.add_dependency "state_machine" 35 | spec.add_dependency "net-ssh" 36 | spec.add_dependency "net-sftp" 37 | spec.add_dependency "sidekiq", "~> 6.0.3" 38 | spec.add_dependency "rack", ">= 2.0.6" , '<= 2.0.8' 39 | 40 | spec.add_development_dependency "sqlite3" 41 | end 42 | -------------------------------------------------------------------------------- /lib/wordpress.rb: -------------------------------------------------------------------------------- 1 | require 'wordpress_core' 2 | require 'wordpress_backend' -------------------------------------------------------------------------------- /wordpress.gemspec: -------------------------------------------------------------------------------- 1 | # Maintain your gem's version: 2 | require "./core/lib/wordpress/core/version" 3 | 4 | # Describe your gem and declare its dependencies: 5 | Gem::Specification.new do |spec| 6 | spec.platform = Gem::Platform::RUBY 7 | spec.name = "wordpress" 8 | spec.version = Wordpress::VERSION 9 | spec.authors = ["Sead Feng"] 10 | spec.email = ["seadfeng@gmail.com"] 11 | spec.homepage = "https://github.com/seadfeng/cloud_wordpress" 12 | spec.summary = "Cloud Wordpress" 13 | spec.description = "Wordpress" 14 | spec.license = "MIT" 15 | 16 | spec.required_ruby_version = '>= 2.5.0' 17 | 18 | # Prevent pushing this gem to RubyGems.org. To allow pushes either set the 'allowed_push_host' 19 | # to allow pushing to a single host or delete this section to allow pushing to any host. 20 | if spec.respond_to?(:metadata) 21 | # spec.metadata["allowed_push_host"] = "TODO: Set to 'http://mygemserver.com'" 22 | else 23 | raise "RubyGems 2.0 or newer is required to protect against " \ 24 | "public gem pushes." 25 | end 26 | 27 | spec.files = Dir["{app,config,db,lib}/**/*", "MIT-LICENSE", "Rakefile", "README.md"] 28 | spec.require_path = 'lib' 29 | spec.requirements << 'none' 30 | 31 | spec.add_dependency "wordpress_core", spec.version 32 | spec.add_dependency "wordpress_backend", spec.version 33 | 34 | end 35 | 36 | --------------------------------------------------------------------------------