souls 0.22.6 → 0.22.7

Sign up to get free protection for your applications and to get access to all the features.
Files changed (120) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile.lock +1 -1
  3. data/exe/souls +21 -5
  4. data/hoy/.env.sample +7 -0
  5. data/hoy/.gitignore +32 -0
  6. data/hoy/.irbrc +1 -0
  7. data/hoy/.rspec +3 -0
  8. data/hoy/.rubocop.yml +132 -0
  9. data/hoy/.ruby-version +1 -0
  10. data/hoy/CODE_OF_CONDUCT.md +74 -0
  11. data/hoy/Dockerfile +16 -0
  12. data/hoy/Dockerfile.dev +17 -0
  13. data/hoy/Gemfile +50 -0
  14. data/hoy/Gemfile.lock +407 -0
  15. data/hoy/LICENSE.txt +67 -0
  16. data/hoy/Procfile +2 -0
  17. data/hoy/Procfile.dev +2 -0
  18. data/hoy/README.md +61 -0
  19. data/hoy/Rakefile +5 -0
  20. data/hoy/app.rb +116 -0
  21. data/hoy/app/graphql/mutations/.keep +0 -0
  22. data/hoy/app/graphql/mutations/base/article/create_article.rb +30 -0
  23. data/hoy/app/graphql/mutations/base/article/delete_article.rb +17 -0
  24. data/hoy/app/graphql/mutations/base/article/destroy_delete_article.rb +17 -0
  25. data/hoy/app/graphql/mutations/base/article/update_article.rb +30 -0
  26. data/hoy/app/graphql/mutations/base/article_category/create_article_category.rb +21 -0
  27. data/hoy/app/graphql/mutations/base/article_category/delete_article_category.rb +17 -0
  28. data/hoy/app/graphql/mutations/base/article_category/destroy_delete_article_category.rb +17 -0
  29. data/hoy/app/graphql/mutations/base/article_category/update_article_category.rb +21 -0
  30. data/hoy/app/graphql/mutations/base/user/create_user.rb +31 -0
  31. data/hoy/app/graphql/mutations/base/user/delete_user.rb +17 -0
  32. data/hoy/app/graphql/mutations/base/user/destroy_delete_user.rb +17 -0
  33. data/hoy/app/graphql/mutations/base/user/update_user.rb +31 -0
  34. data/hoy/app/graphql/mutations/base_mutation.rb +33 -0
  35. data/hoy/app/graphql/mutations/user_manager/add_user_role.rb +22 -0
  36. data/hoy/app/graphql/mutations/user_manager/remove_user_role.rb +22 -0
  37. data/hoy/app/graphql/mutations/user_manager/sign_in_user.rb +45 -0
  38. data/hoy/app/graphql/queries/article.rb +13 -0
  39. data/hoy/app/graphql/queries/article_categories.rb +11 -0
  40. data/hoy/app/graphql/queries/article_category.rb +13 -0
  41. data/hoy/app/graphql/queries/articles.rb +11 -0
  42. data/hoy/app/graphql/queries/base_query.rb +9 -0
  43. data/hoy/app/graphql/queries/me.rb +11 -0
  44. data/hoy/app/graphql/queries/user.rb +13 -0
  45. data/hoy/app/graphql/queries/users.rb +11 -0
  46. data/hoy/app/graphql/resolvers/article_category_search.rb +41 -0
  47. data/hoy/app/graphql/resolvers/article_search.rb +57 -0
  48. data/hoy/app/graphql/resolvers/base.rb +17 -0
  49. data/hoy/app/graphql/resolvers/user_search.rb +63 -0
  50. data/hoy/app/graphql/souls_api_schema.rb +43 -0
  51. data/hoy/app/graphql/types/.keep +0 -0
  52. data/hoy/app/graphql/types/article_category_type.rb +12 -0
  53. data/hoy/app/graphql/types/article_type.rb +30 -0
  54. data/hoy/app/graphql/types/base/base_argument.rb +4 -0
  55. data/hoy/app/graphql/types/base/base_enum.rb +4 -0
  56. data/hoy/app/graphql/types/base/base_field.rb +5 -0
  57. data/hoy/app/graphql/types/base/base_input_object.rb +5 -0
  58. data/hoy/app/graphql/types/base/base_interface.rb +7 -0
  59. data/hoy/app/graphql/types/base/base_object.rb +6 -0
  60. data/hoy/app/graphql/types/base/base_scalar.rb +4 -0
  61. data/hoy/app/graphql/types/base/base_union.rb +4 -0
  62. data/hoy/app/graphql/types/base/mutation_type.rb +16 -0
  63. data/hoy/app/graphql/types/base/query_type.rb +18 -0
  64. data/hoy/app/graphql/types/connections/article_category_connection.rb +3 -0
  65. data/hoy/app/graphql/types/connections/article_connection.rb +3 -0
  66. data/hoy/app/graphql/types/connections/base_connection.rb +14 -0
  67. data/hoy/app/graphql/types/connections/user_connection.rb +3 -0
  68. data/hoy/app/graphql/types/edges/article_category_edge.rb +5 -0
  69. data/hoy/app/graphql/types/edges/article_edge.rb +5 -0
  70. data/hoy/app/graphql/types/edges/base_edge.rb +4 -0
  71. data/hoy/app/graphql/types/edges/user_edge.rb +5 -0
  72. data/hoy/app/graphql/types/user_type.rb +22 -0
  73. data/hoy/app/models/article.rb +4 -0
  74. data/hoy/app/models/article_category.rb +3 -0
  75. data/hoy/app/models/user.rb +19 -0
  76. data/hoy/app/policies/application_policy.rb +40 -0
  77. data/hoy/app/policies/article_category_policy.rb +31 -0
  78. data/hoy/app/policies/article_policy.rb +31 -0
  79. data/hoy/app/policies/user_policy.rb +35 -0
  80. data/hoy/app/utils/association_loader.rb +50 -0
  81. data/hoy/app/utils/firebase_id_token.rb +4 -0
  82. data/hoy/app/utils/json_web_token.rb +13 -0
  83. data/hoy/app/utils/record_loader.rb +10 -0
  84. data/hoy/app/utils/souls_helper.rb +96 -0
  85. data/hoy/cloudbuild.yml +32 -0
  86. data/hoy/config.ru +17 -0
  87. data/hoy/config/database.yml +33 -0
  88. data/hoy/config/souls.rb +4 -0
  89. data/hoy/constants/areas.rb +71 -0
  90. data/hoy/constants/column_name_ja.rb +27 -0
  91. data/hoy/db/migrate/20200006095538_create_users.rb +30 -0
  92. data/hoy/db/migrate/20200712180236_create_article_categories.rb +12 -0
  93. data/hoy/db/migrate/20200714215521_create_articles.rb +22 -0
  94. data/hoy/db/schema.rb +78 -0
  95. data/hoy/db/seeds.rb +44 -0
  96. data/hoy/github/workflows/delivery.yml +81 -0
  97. data/hoy/log/.keep +0 -0
  98. data/hoy/spec/factories/article_categories.rb +9 -0
  99. data/hoy/spec/factories/articles.rb +17 -0
  100. data/hoy/spec/factories/users.rb +23 -0
  101. data/hoy/spec/models/article_category_spec.rb +7 -0
  102. data/hoy/spec/models/article_spec.rb +7 -0
  103. data/hoy/spec/models/user_spec.rb +7 -0
  104. data/hoy/spec/mutations/base/article_category_spec.rb +46 -0
  105. data/hoy/spec/mutations/base/article_spec.rb +70 -0
  106. data/hoy/spec/mutations/base/user_spec.rb +76 -0
  107. data/hoy/spec/policies/article_category_policy_spec.rb +25 -0
  108. data/hoy/spec/policies/article_policy_spec.rb +25 -0
  109. data/hoy/spec/policies/user_policy_spec.rb +5 -0
  110. data/hoy/spec/queries/article_category_spec.rb +39 -0
  111. data/hoy/spec/queries/article_spec.rb +53 -0
  112. data/hoy/spec/queries/user_spec.rb +59 -0
  113. data/hoy/spec/resolvers/article_category_search_spec.rb +54 -0
  114. data/hoy/spec/resolvers/article_search_spec.rb +68 -0
  115. data/hoy/spec/resolvers/user_search_spec.rb +74 -0
  116. data/hoy/spec/spec_helper.rb +110 -0
  117. data/hoy/tmp/.keep +0 -0
  118. data/lib/souls/init.rb +16 -9
  119. data/lib/souls/version.rb +1 -1
  120. metadata +115 -1
@@ -0,0 +1,35 @@
1
+ class UserPolicy < ApplicationPolicy
2
+ def show?
3
+ true
4
+ end
5
+
6
+ def index?
7
+ true
8
+ end
9
+
10
+ def create?
11
+ true
12
+ end
13
+
14
+ def update?
15
+ true
16
+ end
17
+
18
+ def delete?
19
+ admin_permissions?
20
+ end
21
+
22
+ private
23
+
24
+ def user_permissions?
25
+ @user.user? or @user.admin? or @user.master?
26
+ end
27
+
28
+ def admin_permissions?
29
+ @user.master? or @user.admin?
30
+ end
31
+
32
+ def update_user_role?
33
+ @user.master?
34
+ end
35
+ end
@@ -0,0 +1,50 @@
1
+ class AssociationLoader < GraphQL::Batch::Loader
2
+ def self.validate(model, association_name)
3
+ new(model, association_name)
4
+ nil
5
+ end
6
+
7
+ def initialize(model, association_name)
8
+ super()
9
+ @model = model
10
+ @association_name = association_name
11
+ validate
12
+ end
13
+
14
+ def load(record)
15
+ raise(TypeError, "#{@model} loader can't load association for #{record.class}") unless record.is_a?(@model)
16
+ return Promise.resolve(read_association(record)) if association_loaded?(record)
17
+
18
+ super
19
+ end
20
+
21
+ # We want to load the associations on all records, even if they have the same id
22
+ def cache_key(record)
23
+ record.object_id
24
+ end
25
+
26
+ def perform(records)
27
+ preload_association(records)
28
+ records.each { |record| fulfill(record, read_association(record)) }
29
+ end
30
+
31
+ private
32
+
33
+ def validate
34
+ return if @model.reflect_on_association(@association_name)
35
+
36
+ raise(ArgumentError, "No association #{@association_name} on #{@model}")
37
+ end
38
+
39
+ def preload_association(records)
40
+ ::ActiveRecord::Associations::Preloader.new.preload(records, @association_name)
41
+ end
42
+
43
+ def read_association(record)
44
+ record.public_send(@association_name)
45
+ end
46
+
47
+ def association_loaded?(record)
48
+ record.association(@association_name).loaded?
49
+ end
50
+ end
@@ -0,0 +1,4 @@
1
+ FirebaseIdToken.configure do |config|
2
+ config.project_ids = ["souls"]
3
+ config.redis = Redis.new
4
+ end
@@ -0,0 +1,13 @@
1
+ module JsonWebToken
2
+ SECRET_KEY = ENV["SECRET_KEY_BASE"] || ""
3
+ private_constant :SECRET_KEY
4
+ def self.encode(payload, exp = 24.hours.from_now)
5
+ exp.to_i.zero? ? payload.delete(:exp) : payload[:exp] = exp.to_i
6
+ JWT.encode(payload, SECRET_KEY)
7
+ end
8
+
9
+ def self.decode(token)
10
+ decoded = JWT.decode(token, SECRET_KEY)[0]
11
+ HashWithIndifferentAccess.new(decoded)
12
+ end
13
+ end
@@ -0,0 +1,10 @@
1
+ class RecordLoader < GraphQL::Batch::Loader
2
+ def initialize(model)
3
+ @model = model
4
+ end
5
+
6
+ def perform(ids)
7
+ @model.where(id: ids).each { |record| fulfill(record.id, record) }
8
+ ids.each { |id| fulfill(id, nil) unless fulfilled?(id) }
9
+ end
10
+ end
@@ -0,0 +1,96 @@
1
+ module SoulsHelper
2
+ def check_user_permissions(user, obj, method)
3
+ raise(StandardError, "Invalid or Missing Token") unless user
4
+
5
+ policy_class = obj.class.name + "Policy"
6
+ policy_clazz = policy_class.constantize.new(user, obj)
7
+ permission = policy_clazz.public_send(method)
8
+ raise(Pundit::NotAuthorizedError, "permission error!") unless permission
9
+ end
10
+
11
+ def self.export_csv(model_name)
12
+ singularized_name = model_name.singularize.underscore
13
+ return "Please Set column names in Constants !" unless Constants.public_send("#{singularized_name}_columns").size
14
+ unless Constants.public_send("#{singularized_name}_columns").size ==
15
+ Object.const_get(singularized_name.camelize).column_names.size
16
+
17
+ return "Columns number doesn't match! Please check Constants!"
18
+ end
19
+
20
+ file_path = "./db/seed_csv/#{model_name.pluralize.underscore}.csv"
21
+ CSV.open(file_path, "w") do |csv|
22
+ csv << Object.const_get(singularized_name.camelize).column_names.map do |c|
23
+ Constants.public_send("#{singularized_name}_columns")[c.to_sym]
24
+ end
25
+ Object.const_get(singularized_name.camelize).all.reverse.each do |item|
26
+ csv << item.attributes.values
27
+ end
28
+ end
29
+ "export success!:#{file_path}"
30
+ rescue StandardError => e
31
+ e
32
+ end
33
+
34
+ def self.export_model_to_csv(model_name)
35
+ singularized_name = model_name.singularize.underscore
36
+ pluralized_name = model_name.pluralize.underscore
37
+ time = Time.now.utc.strftime("%F-%H-%M-%S")
38
+ file_name = "#{pluralized_name}-#{time}.csv"
39
+ upload_path = "csv/#{singularized_name}/#{file_name}"
40
+ file_path = "./tmp/#{pluralized_name}-#{time}.csv"
41
+ class_name = Object.const_get(singularized_name.camelize)
42
+ CSV.open(file_path, "w") do |csv|
43
+ if Constants.public_send("#{singularized_name}_columns").size.present?
44
+ unless Constants.public_send("#{singularized_name}_columns").size ==
45
+ Object.const_get(singularized_name.camelize).column_names.size
46
+
47
+ return "Columns number doesn't match! Please check Constants !"
48
+ end
49
+
50
+ csv << class_name.column_names.map { |c| Constants.public_send("#{singularized_name}_columns")[c.to_sym] }
51
+ else
52
+ csv << class_name.column_names
53
+ end
54
+ class_name.all.reverse.each do |item|
55
+ csv << item.attributes.values
56
+ end
57
+ end
58
+ upload_to_gcs(file_path, upload_path)
59
+ FileUtils.rm(file_path)
60
+ bucket = ENV["RACK_ENV"] == "production" ? ENV["GCS_NAME_PRODUCTION"] : ENV["GCS_NAME_DEV"]
61
+ "https://storage.cloud.google.com/#{bucket}/csv/#{singularized_name}/#{file_name}"
62
+ rescue StandardError => e
63
+ e.backtrace
64
+ end
65
+
66
+ def self.upload_to_gcs(file_path, upload_path)
67
+ storage = Google::Cloud::Storage.new
68
+ bucket =
69
+ if ENV["RACK_ENV"] == "production"
70
+ storage.bucket(ENV["GCS_NAME_PRODUCTION"])
71
+ else
72
+ storage.bucket(ENV["GCS_NAME_DEV"])
73
+ end
74
+ file = bucket.create_file(file_path, upload_path, acl: "authenticated_read")
75
+ file.public_url
76
+ rescue StandardError => e
77
+ raise(StandardError, e)
78
+ end
79
+
80
+ def self.pubsub_queue(topic_name: "seino-schedule-scraper", message: "text!")
81
+ pubsub = Google::Cloud::Pubsub.new(project: ENV["PROJECT_ID"])
82
+ topic = pubsub.topic(topic_name)
83
+ topic.publish(message)
84
+ end
85
+
86
+ def self.get_tables
87
+ path = "./db/schema.rb"
88
+ tables = []
89
+ File.open(path, "r") do |f|
90
+ f.each_line.with_index do |line, _i|
91
+ tables << line.split("\"")[1] if line.include?("create_table")
92
+ end
93
+ end
94
+ tables
95
+ end
96
+ end
@@ -0,0 +1,32 @@
1
+ steps:
2
+ - name: gcr.io/cloud-builders/docker
3
+ args:
4
+ - image
5
+ - build
6
+ - -t
7
+ - asia.gcr.io/$PROJECT_ID/$APP_NAME
8
+ - .
9
+
10
+ - name: gcr.io/cloud-builders/docker
11
+ args:
12
+ - image
13
+ - push
14
+ - asia.gcr.io/$PROJECT_ID/$APP_NAME
15
+
16
+ - name: gcr.io/cloud-builders/gcloud
17
+ args:
18
+ - run
19
+ - deploy
20
+ - $APP_NAME
21
+ - --image=asia.gcr.io/$PROJECT_ID/$APP_NAME
22
+ - --platform=managed
23
+ - --region=asia-northeast1
24
+ - --allow-unauthenticated
25
+ - --memory=2048Mi
26
+ - --concurrency=80
27
+ - --port=8080
28
+ - --set-cloudsql-instances=$APP_NAME:asia-northeast1:$APP_NAME-db
29
+
30
+ timeout: 1600s
31
+ options:
32
+ machineType: N1_HIGHCPU_8
data/hoy/config.ru ADDED
@@ -0,0 +1,17 @@
1
+ require "./app"
2
+ require "rack/cors"
3
+ require "graphql_playground"
4
+
5
+ map "/playground" do
6
+ use GraphQLPlayground, endpoint: "/endpoint"
7
+ end
8
+
9
+ run SoulsApi
10
+
11
+ use Rack::Cors do
12
+ allowed_headers = %i[get post put patch delete options head]
13
+ allow do
14
+ origins "*"
15
+ resource "*", headers: :any, methods: allowed_headers
16
+ end
17
+ end
@@ -0,0 +1,33 @@
1
+ default: &default
2
+ adapter: postgresql
3
+ encoding: utf8
4
+ username: <%= ENV.fetch("DB_USER") { "" } %>
5
+ port: 5432
6
+
7
+ development:
8
+ <<: *default
9
+ username: postgres
10
+ password: postgres
11
+ database: souls-api-dev
12
+ host: localhost
13
+ port: 5433
14
+
15
+ production:
16
+ <<: *default
17
+ database: souls_api_production
18
+ password: <%= ENV.fetch("DB_PW") { "" } %>
19
+ host: <%= ENV.fetch("DB_HOST") { "" } %>
20
+ pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
21
+
22
+
23
+ ## Use local docker postgresql13
24
+ ## `souls i run_psql` will create psql container
25
+
26
+ test:
27
+ <<: *default
28
+ username: postgres
29
+ password: postgres
30
+ database: souls-api-test
31
+ host: localhost
32
+ port: 5433
33
+
@@ -0,0 +1,4 @@
1
+ Souls.configure do |config|
2
+ config.app = "hoy"
3
+ config.strain = "api"
4
+ end
@@ -0,0 +1,71 @@
1
+ module Constants
2
+ def self.areas
3
+ # 参考URL 西濃運輸|カンガルー宅急便運賃表
4
+ # http://stc.deliveryseino.jp/unchin/unchin.20191001.pdf
5
+ {
6
+ "北海道": ["北海道"],
7
+ "北東北": %w[青森 岩手 秋田],
8
+ "南東北": %w[宮城 山形 福島],
9
+ "関東": %w[栃木 群馬 新潟 茨城 千葉 東京 神奈川 山梨],
10
+ "中部": %w[富山 石川 福井 長野 静岡 愛知 三重 岐阜],
11
+ "近畿": %w[滋賀 京都 大阪 奈良 和歌山 兵庫],
12
+ "中国": %w[鳥取 岡山 島根 広島 山口],
13
+ "四国": %w[香川 徳島 愛媛 高知],
14
+ "北九州": %w[福岡 大分 長崎 佐賀],
15
+ "南九州": %w[宮崎 熊本 鹿児島],
16
+ "沖縄": ["沖縄"]
17
+ }
18
+ end
19
+
20
+ def self.prefectures
21
+ %w[
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
+ 和歌山県
52
+ 鳥取県
53
+ 島根県
54
+ 岡山県
55
+ 広島県
56
+ 山口県
57
+ 徳島県
58
+ 香川県
59
+ 愛媛県
60
+ 高知県
61
+ 福岡県
62
+ 佐賀県
63
+ 長崎県
64
+ 熊本県
65
+ 大分県
66
+ 宮崎県
67
+ 鹿児島県
68
+ 沖縄県
69
+ ]
70
+ end
71
+ end
@@ -0,0 +1,27 @@
1
+ module Constants
2
+ def self.user_columns
3
+ {
4
+ id: "ID",
5
+ uid: "UID",
6
+ username: "ユーザー名",
7
+ screen_name: "表示名",
8
+ last_name: "苗字",
9
+ first_name: "名前",
10
+ last_name_kanji: "苗字(漢字)",
11
+ first_name_kanji: "名前(漢字)",
12
+ last_name_kana: "苗字(カナ)",
13
+ first_name_kana: "名前(カナ)",
14
+ email: "メール",
15
+ tel: "電話番号",
16
+ icon_url: "アイコンURL",
17
+ birthday: "誕生日",
18
+ gender: "性別",
19
+ lang: "言語",
20
+ category: "カテゴリー",
21
+ roles_mask: "ユーザー権限",
22
+ is_deleted: "削除フラグ",
23
+ created_at: "作成日時",
24
+ updated_at: "更新日時"
25
+ }
26
+ end
27
+ end
@@ -0,0 +1,30 @@
1
+ class CreateUsers < ActiveRecord::Migration[6.1]
2
+ def change
3
+ create_table :users do |t|
4
+ t.string :uid, null: false, unique: true
5
+ t.string :username, null: false, default: ""
6
+ t.string :screen_name, null: false, default: ""
7
+ t.string :last_name, null: false, default: ""
8
+ t.string :first_name, null: false, default: ""
9
+ t.string :last_name_kanji, null: false, default: ""
10
+ t.string :first_name_kanji, null: false, default: ""
11
+ t.string :last_name_kana, null: false, default: ""
12
+ t.string :first_name_kana, null: false, default: ""
13
+ t.string :email, null: false, unique: true
14
+ t.string :tel, null: false, default: ""
15
+ t.string :icon_url, null: false, default: ""
16
+ t.string :birthday, null: false, default: ""
17
+ t.string :gender, null: false, default: ""
18
+ t.string :lang, null: false, default: "ja"
19
+ t.string :category, null: false, default: "user"
20
+ t.integer :roles_mask, null: false, default: 1
21
+ t.boolean :is_deleted, null: false, default: false
22
+ t.timestamps
23
+ end
24
+ add_index :users, :uid
25
+ add_index :users, :screen_name
26
+ add_index :users, :email, unique: true
27
+ add_index :users, :username
28
+ add_index :users, :is_deleted
29
+ end
30
+ end
@@ -0,0 +1,12 @@
1
+ class CreateArticleCategories < ActiveRecord::Migration[6.1]
2
+ def change
3
+ create_table :article_categories do |t|
4
+ t.string :name, null: false
5
+ t.text :tags, array: true, default: []
6
+ t.boolean :is_deleted, null: false, default: false
7
+ t.timestamps
8
+ end
9
+ add_index :article_categories, :name
10
+ add_index :article_categories, :is_deleted
11
+ end
12
+ end