rails_dingtalk 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (46) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE +20 -0
  3. data/README.md +32 -0
  4. data/Rakefile +18 -0
  5. data/app/apis/dingtalk/api/base.rb +52 -0
  6. data/app/apis/dingtalk/api/inner/new.rb +10 -0
  7. data/app/apis/dingtalk/api/inner/user.rb +15 -0
  8. data/app/apis/dingtalk/api/new.rb +54 -0
  9. data/app/apis/dingtalk/api/normal.rb +6 -0
  10. data/app/apis/dingtalk/http_client.rb +84 -0
  11. data/app/apis/dingtalk/signature.rb +16 -0
  12. data/app/assets/javascripts/rails_dingtalk/index.js +2 -0
  13. data/app/controllers/admin_controller.rb +2 -0
  14. data/app/controllers/dingtalk/admin/apps_controller.rb +21 -0
  15. data/app/controllers/dingtalk/admin/base_controller.rb +10 -0
  16. data/app/controllers/dingtalk/apps_controller.rb +29 -0
  17. data/app/controllers/dingtalk/base_controller.rb +4 -0
  18. data/app/controllers/dingtalk/home_controller.rb +8 -0
  19. data/app/jobs/dingtalk/dingtalk_user_job.rb +9 -0
  20. data/app/models/app/dingtalk/new_app.rb +5 -0
  21. data/app/models/app/dingtalk/normal_app.rb +5 -0
  22. data/app/models/dingtalk/app.rb +5 -0
  23. data/app/models/dingtalk/dingtalk_user.rb +5 -0
  24. data/app/models/dingtalk/model/app/new_app.rb +52 -0
  25. data/app/models/dingtalk/model/app/normal_app.rb +15 -0
  26. data/app/models/dingtalk/model/app.rb +72 -0
  27. data/app/models/dingtalk/model/dingtalk_user.rb +23 -0
  28. data/app/models/dingtalk.rb +11 -0
  29. data/app/views/admin/_dingtalk_nav.html.erb +10 -0
  30. data/app/views/dingtalk/admin/apps/_index_tbody.html.erb +9 -0
  31. data/app/views/dingtalk/admin/apps/_index_thead.html.erb +10 -0
  32. data/app/views/dingtalk/admin/apps/_show_table.html.erb +16 -0
  33. data/app/views/dingtalk/admin/base/_nav.html.erb +3 -0
  34. data/app/views/dingtalk/apps/login.html.erb +0 -0
  35. data/app/views/dingtalk/apps/login.json.jbuilder +1 -0
  36. data/app/views/dingtalk/home/index-phone.js +1 -0
  37. data/app/views/dingtalk/home/index.html.erb +1 -0
  38. data/app/views/dingtalk/home/index.js +41 -0
  39. data/app/views/layouts/dingtalk/basex.html.erb +25 -0
  40. data/config/locales/zh.controller.yml +7 -0
  41. data/config/locales/zh.enum.yml +8 -0
  42. data/config/routes.rb +19 -0
  43. data/lib/rails_dingtalk/config.rb +12 -0
  44. data/lib/rails_dingtalk/engine.rb +24 -0
  45. data/lib/rails_dingtalk.rb +2 -0
  46. metadata +132 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 679903c2872c650e0f3b41572a87cad341c0b488192aa87df855d76fa314bdb2
4
+ data.tar.gz: d7c4c968bacaf8490ee4a156ae04404bbfd58df09cc94c8e3248ded58c88e48e
5
+ SHA512:
6
+ metadata.gz: 827139e76986da0425ccdd14e761680c392af9af2aa77dd6ef73cfa063df022b9166f3af46061f74e7f99365855fc2af63ce127d611993a629d7194551fb5721
7
+ data.tar.gz: 935efe4e6ee77077790817306849dbe61b31257bd6018673cd2f6de80f0ebe7644bfccdbbe15281b7e8ff2caa5b9cfb7b292f9b33600037268cad4d5316ead56
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2021-Present Mingyuan Qin <mingyuan0715@foxmail.com>
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.
data/README.md ADDED
@@ -0,0 +1,32 @@
1
+ # RailsDingtalk
2
+
3
+ [![测试](https://github.com/work-design/rails_dingtalk/actions/workflows/test.yml/badge.svg)](https://github.com/work-design/rails_dingtalk/actions/workflows/test.yml)
4
+ [![Docker构建](https://github.com/work-design/rails_dingtalk/actions/workflows/cd.yml/badge.svg)](https://github.com/work-design/rails_dingtalk/actions/workflows/cd.yml)
5
+
6
+ 钉钉开放平台。
7
+
8
+ ## Usage
9
+ How to use my plugin.
10
+
11
+ ## Installation
12
+ Add this line to your application's Gemfile:
13
+
14
+ ```ruby
15
+ gem 'rails_dingtalk'
16
+ ```
17
+
18
+ And then execute:
19
+ ```bash
20
+ $ bundle
21
+ ```
22
+
23
+ Or install it yourself as:
24
+ ```bash
25
+ $ gem install rails_dingtalk
26
+ ```
27
+
28
+ ## Contributing
29
+ Contribution directions go here.
30
+
31
+ ## License
32
+ The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
data/Rakefile ADDED
@@ -0,0 +1,18 @@
1
+ require "bundler/setup"
2
+
3
+ APP_RAKEFILE = File.expand_path("test/dummy/Rakefile", __dir__)
4
+ load "rails/tasks/engine.rake"
5
+
6
+ load "rails/tasks/statistics.rake"
7
+
8
+ require "bundler/gem_tasks"
9
+
10
+ require "rake/testtask"
11
+
12
+ Rake::TestTask.new(:test) do |t|
13
+ t.libs << 'test'
14
+ t.pattern = 'test/**/*_test.rb'
15
+ t.verbose = false
16
+ end
17
+
18
+ task default: :test
@@ -0,0 +1,52 @@
1
+ module Dingtalk::Api
2
+ class Base
3
+ BASE = 'https://oapi.dingtalk.com/'
4
+ attr_reader :app, :client
5
+
6
+ def initialize(app)
7
+ @app = app
8
+ @client = Dingtalk::HttpClient.new
9
+ end
10
+
11
+ def token
12
+ @client.get 'gettoken', params: { appkey: app.app_key, appsecret: app.app_secret }, base: BASE
13
+ end
14
+
15
+ def jsapi_ticket
16
+ get 'get_jsapi_ticket', base: BASE
17
+ end
18
+
19
+ def base_host
20
+ BASE
21
+ end
22
+
23
+ def get(path, params: {}, headers: {}, base: base_host, as: nil)
24
+ with_access_token(params) do |with_token_params|
25
+ @client.get path, headers: headers, params: with_token_params, base: base, as: as
26
+ end
27
+ end
28
+
29
+ def post(path, params: {}, headers: {}, base: base_host, **payload)
30
+ with_access_token(params) do |with_token_params|
31
+ @client.post path, payload.to_json, headers: headers, params: with_token_params, base: base
32
+ end
33
+ end
34
+
35
+ def post_file(path, file, params: {}, headers: {}, base: base_host)
36
+ with_access_token(params) do |with_token_params|
37
+ @client.post_file path, file, headers: headers, params: with_token_params, base: base
38
+ end
39
+ end
40
+
41
+ protected
42
+ def with_access_token(params = {}, tries = 2)
43
+ app.refresh_access_token unless app.access_token_valid?
44
+ yield params.merge!(access_token: app.access_token)
45
+ rescue => e
46
+ Rails.logger.debug e.full_message
47
+ app.refresh_access_token
48
+ retry unless (tries -= 1).zero?
49
+ end
50
+
51
+ end
52
+ end
@@ -0,0 +1,10 @@
1
+ module Dingtalk::Api
2
+ module Inner::New
3
+ BASE = 'https://api.dingtalk.com/'
4
+
5
+ def getuserinfo(union_id)
6
+ get "v1.0/contact/users/#{union_id}"
7
+ end
8
+
9
+ end
10
+ end
@@ -0,0 +1,15 @@
1
+ module Dingtalk::Api
2
+ module Inner::User
3
+ BASE = 'https://oapi.dingtalk.com/'
4
+
5
+ def getuserinfo(code)
6
+ r = post 'topapi/v2/user/getuserinfo', code: code
7
+ if r.is_a? Hash
8
+ r['result']
9
+ else
10
+ r
11
+ end
12
+ end
13
+
14
+ end
15
+ end
@@ -0,0 +1,54 @@
1
+ module Dingtalk::Api
2
+ class New < Base
3
+ BASE = 'https://api.dingtalk.com/'
4
+ include Inner::New
5
+
6
+ def token
7
+ payload = {
8
+ appKey: app.app_key,
9
+ appSecret: app.app_secret,
10
+ }
11
+ r = @client.post 'v1.0/oauth2/accessToken', payload.to_json, base: BASE
12
+ {
13
+ 'access_token' => r['accessToken'],
14
+ 'expires_in' => r['expireIn']
15
+ }
16
+ end
17
+
18
+ def base_host
19
+ BASE
20
+ end
21
+
22
+ def get(path, params: {}, headers: {}, base: base_host, as: nil)
23
+ with_access_token(headers) do |with_token_headers|
24
+ @client.get path, headers: with_token_headers, params: params, base: base, as: as
25
+ end
26
+ end
27
+
28
+ def post(path, params: {}, headers: {}, base: base_host, **payload)
29
+ with_access_token(headers) do |with_token_headers|
30
+ @client.post path, payload.to_json, headers: with_token_headers, params: params, base: base
31
+ end
32
+ end
33
+
34
+ def post_file(path, file, params: {}, headers: {}, base: base_host)
35
+ with_access_token(headers) do |with_token_headers|
36
+ @client.post_file path, file, headers: with_token_headers, params: params, base: base
37
+ end
38
+ end
39
+
40
+ protected
41
+ def with_access_token(headers = {}, tries = 2)
42
+ app.refresh_access_token unless app.access_token_valid?
43
+ yield headers.merge!(
44
+ Authorization: "Bearer #{app.access_token}",
45
+ 'x-acs-dingtalk-access-token': app.access_token
46
+ )
47
+ rescue => e
48
+ Rails.logger.debug e.full_message
49
+ app.refresh_access_token
50
+ retry unless (tries -= 1).zero?
51
+ end
52
+
53
+ end
54
+ end
@@ -0,0 +1,6 @@
1
+ module Dingtalk::Api
2
+ class Normal < Base
3
+ include Inner::User
4
+
5
+ end
6
+ end
@@ -0,0 +1,84 @@
1
+ require 'httpx'
2
+ require 'http/form_data'
3
+
4
+ module Dingtalk
5
+ class HttpClient
6
+ attr_reader :http
7
+
8
+ def initialize
9
+ @http = HTTPX.with(**RailsDingtalk.config.httpx)
10
+ end
11
+
12
+ def get(path, headers: {}, params: {}, base: nil, **options)
13
+ headers['Accept'] ||= 'application/json'
14
+ url = base + path
15
+
16
+ response = @http.with_headers(headers).get(url, params: params)
17
+ parse_response(response, options[:as])
18
+ end
19
+
20
+ def post(path, payload, headers: {}, params: {}, base: nil, **options)
21
+ headers['Accept'] ||= 'application/json'
22
+ headers['Content-Type'] ||= 'application/json'
23
+ url = base + path
24
+
25
+ response = @http.with_headers(headers).post(url, params: params, body: payload)
26
+ parse_response(response, options[:as])
27
+ end
28
+
29
+ def post_file(path, file, headers: {}, params: {}, base: nil, **options)
30
+ headers['Accept'] ||= 'application/json'
31
+ url = base + path
32
+
33
+ form_file = file.is_a?(HTTP::FormData::File) ? file : HTTP::FormData::File.new(file)
34
+ response = @http.plugin(:multipart).with_headers(headers).post(
35
+ url,
36
+ params: params,
37
+ form: { media: form_file }
38
+ )
39
+ parse_response(response, options[:as])
40
+ end
41
+
42
+ private
43
+ def parse_response(response, parse_as)
44
+ if response.status != 200
45
+ Rails.logger.debug response.body.to_s
46
+ raise "Request get fail, response status #{response.status}"
47
+ end
48
+
49
+ content_type = response.content_type.mime_type
50
+ body = response.body.to_s
51
+ Rails.logger.debug "body: #{body}"
52
+
53
+ if content_type =~ /image|audio|video/
54
+ data = Tempfile.new('tmp')
55
+ data.binmode
56
+ data.write(body)
57
+ data.rewind
58
+ return data
59
+ elsif content_type =~ /html|xml/
60
+ data = Hash.from_xml(body)
61
+ else
62
+ data = JSON.parse body.gsub(/[\u0000-\u001f]+/, '')
63
+ end
64
+
65
+ case data['errcode']
66
+ when 0 # for request didn't expect results
67
+ data
68
+ # 42001: access_token timeout
69
+ # 40014: invalid access_token
70
+ # 40001, invalid credential, access_token is invalid or not latest hint
71
+ # 48001, api unauthorized hint, should not handle here # GH-230
72
+ when 42001, 40014, 40001, 41001
73
+ raise Dingtalk::AccessTokenExpiredError
74
+ # 40029, invalid code for mp # GH-225
75
+ # 43004, require subscribe hint # GH-214
76
+ when 2
77
+ raise Dingtalk::ResponseError.new(data['errcode'], data['errmsg'])
78
+ else
79
+ data
80
+ end
81
+ end
82
+
83
+ end
84
+ end
@@ -0,0 +1,16 @@
1
+ module Dingtalk
2
+ module Signature
3
+ extend self
4
+
5
+ def signature(secret, timestamp = (Time.current.to_f * 1000).round)
6
+ raise ArgumentError, 'timestamp must in millis' if Math.log10(timestamp).ceil < 13
7
+
8
+ origin_str = [timestamp, secret].join("\n")
9
+ signature_str = OpenSSL::HMAC.digest('SHA256', secret, origin_str)
10
+ signature_str_base64 = Base64.strict_encode64(signature_str)
11
+
12
+ URI.encode_www_form_component(signature_str_base64)
13
+ end
14
+
15
+ end
16
+ end
@@ -0,0 +1,2 @@
1
+ import * as dd from 'dingtalk-jsapi'
2
+
@@ -0,0 +1,2 @@
1
+ class AdminController < ApplicationController
2
+ end
@@ -0,0 +1,21 @@
1
+ module Dingtalk
2
+ class Admin::AppsController < Admin::BaseController
3
+
4
+ def index
5
+ @apps = App.page(params[:page])
6
+ end
7
+
8
+ private
9
+ def app_permit_params
10
+ [
11
+ :type,
12
+ :name,
13
+ :corp_id,
14
+ :agent_id,
15
+ :app_key,
16
+ :app_secret
17
+ ]
18
+ end
19
+
20
+ end
21
+ end
@@ -0,0 +1,10 @@
1
+ module Dingtalk
2
+ class Admin::BaseController < AdminController
3
+
4
+ private
5
+ def set_app
6
+ @app = App.find(params[:app_id])
7
+ end
8
+
9
+ end
10
+ end
@@ -0,0 +1,29 @@
1
+ module Dingtalk
2
+ class AppsController < BaseController
3
+ before_action :set_new_app, only: [:login]
4
+ before_action :set_normal_app, only: [:info]
5
+
6
+ def info
7
+ result = @app.xx(params[:code])
8
+ render json: result
9
+ end
10
+
11
+ def login
12
+ @dingtalk_user = @app.generate_user(params[:authCode])
13
+ @dingtalk_user.save
14
+ end
15
+
16
+ def create
17
+ end
18
+
19
+ private
20
+ def set_new_app
21
+ @app = NewApp.find_by(app_key: params[:app_key])
22
+ end
23
+
24
+ def set_normal_app
25
+ @app = NormalApp.find_by(app_key: params[:app_key])
26
+ end
27
+
28
+ end
29
+ end
@@ -0,0 +1,4 @@
1
+ module Dingtalk
2
+ class BaseController < ApplicationController
3
+ end
4
+ end
@@ -0,0 +1,8 @@
1
+ module Dingtalk
2
+ class HomeController < ApplicationController
3
+
4
+ def index
5
+ end
6
+
7
+ end
8
+ end
@@ -0,0 +1,9 @@
1
+ module Dingtalk
2
+ class DingtalkUserJob < ApplicationJob
3
+
4
+ def perform(agency)
5
+ agency.store_info
6
+ end
7
+
8
+ end
9
+ end
@@ -0,0 +1,5 @@
1
+ module Dingtalk
2
+ class NewApp < App
3
+ include Model::App::NewApp
4
+ end
5
+ end
@@ -0,0 +1,5 @@
1
+ module Dingtalk
2
+ class NormalApp < App
3
+ include Model::App::NormalApp
4
+ end
5
+ end
@@ -0,0 +1,5 @@
1
+ module Dingtalk
2
+ class App < ApplicationRecord
3
+ include Model::App
4
+ end
5
+ end
@@ -0,0 +1,5 @@
1
+ module Dingtalk
2
+ class DingtalkUser < ApplicationRecord
3
+ include Model::DingtalkUser
4
+ end
5
+ end
@@ -0,0 +1,52 @@
1
+ module Dingtalk
2
+ module Model::App::NewApp
3
+
4
+ def api
5
+ return @api if defined? @api
6
+ @api = Api::New.new(self)
7
+ end
8
+
9
+ def oauth2_url(scope = 'openid corpid', state: SecureRandom.hex(16), **host_options)
10
+ h = {
11
+ client_id: app_key,
12
+ redirect_uri: Rails.application.routes.url_for(controller: 'dingtalk/apps', action: 'login', app_key: app_key, **host_options),
13
+ response_type: 'code',
14
+ scope: scope,
15
+ state: state,
16
+ nonce: SecureRandom.hex(4),
17
+ prompt: 'consent'
18
+ }
19
+
20
+ logger.debug "\e[35m Detail: #{h} \e[0m"
21
+ "https://login.dingtalk.com/oauth2/auth?#{h.to_query}"
22
+ end
23
+
24
+ def generate_user(code)
25
+ h = {
26
+ clientId: app_key,
27
+ clientSecret: app_secret,
28
+ code: code,
29
+ grantType: 'authorization_code'
30
+ }
31
+ r = HTTPX.post 'https://api.dingtalk.com/v1.0/oauth2/userAccessToken', json: h
32
+ token_info = JSON.parse(r.body.to_s)
33
+ logger.debug token_info
34
+
35
+ info = HTTPX.get 'https://api.dingtalk.com/v1.0/contact/users/me', headers: { 'x-acs-dingtalk-access-token': token_info['accessToken'] }
36
+ profile_info = JSON.parse(info.body.to_s)
37
+ logger.debug profile_info
38
+ #binding.break
39
+ dingtalk_user = dingtalk_users.find_or_initialize_by(uid: profile_info['openId'])
40
+ dingtalk_user.access_token = token_info['accessToken']
41
+ dingtalk_user.expires_at = Time.current + token_info['expireIn'].to_i
42
+ dingtalk_user.refresh_token = token_info['refreshToken']
43
+ dingtalk_user.unionid = profile_info['unionId']
44
+ dingtalk_user.name = profile_info['nick']
45
+ dingtalk_user.avatar_url = profile_info['avatarUrl']
46
+ dingtalk_user.identity = profile_info['mobile']
47
+ dingtalk_user.extra = profile_info.slice('email', 'stateCode')
48
+ dingtalk_user
49
+ end
50
+
51
+ end
52
+ end
@@ -0,0 +1,15 @@
1
+ module Dingtalk
2
+ module Model::App::NormalApp
3
+ extend ActiveSupport::Concern
4
+
5
+ included do
6
+ has_one :new_app, foreign_key: :app_key, primary_key: :app_key
7
+ end
8
+
9
+ def xx(code)
10
+ result = api.getuserinfo(code)
11
+ new_app.api.getuserinfo(result['unionid'])
12
+ end
13
+
14
+ end
15
+ end
@@ -0,0 +1,72 @@
1
+ module Dingtalk
2
+ module Model::App
3
+ extend ActiveSupport::Concern
4
+
5
+ included do
6
+ attribute :type, :string
7
+ attribute :name, :string
8
+ attribute :agent_id, :string
9
+ attribute :app_key, :string
10
+ attribute :app_secret, :string
11
+ attribute :corp_id, :string
12
+ attribute :access_token, :string
13
+ attribute :access_token_expires_at, :datetime
14
+ attribute :jsapi_ticket, :string
15
+ attribute :oauth2_state, :string
16
+ attribute :jsapi_ticket_expires_at, :datetime
17
+
18
+ has_many :dingtalk_users, foreign_key: :appid, primary_key: :app_key
19
+ end
20
+
21
+ def api
22
+ return @api if defined? @api
23
+ @api = Api::Normal.new(self)
24
+ end
25
+
26
+ def refresh_access_token
27
+ r = api.token
28
+ if r['access_token']
29
+ store_access_token(r)
30
+ else
31
+ logger.debug "\e[35m #{r['errmsg']} \e[0m"
32
+ end
33
+ end
34
+
35
+ def store_access_token(token_hash)
36
+ self.access_token = token_hash['access_token']
37
+ self.access_token_expires_at = Time.current + token_hash['expires_in'].to_i
38
+ self.save
39
+ end
40
+
41
+ def access_token_valid?
42
+ return false unless access_token_expires_at.acts_like?(:time)
43
+ access_token_expires_at > Time.current
44
+ end
45
+
46
+ def get_jsapi_ticket
47
+ if jsapi_ticket_valid?
48
+ jsapi_ticket
49
+ else
50
+ refresh_jsapi_ticket
51
+ end
52
+ end
53
+
54
+ def jsapi_ticket_valid?
55
+ return false unless jsapi_ticket_expires_at.acts_like?(:time)
56
+ jsapi_ticket_expires_at > Time.current
57
+ end
58
+
59
+ def refresh_jsapi_ticket
60
+ r = api.jsapi_ticket
61
+ store_jsapi_ticket(r)
62
+ jsapi_ticket
63
+ end
64
+
65
+ def store_jsapi_ticket(ticket_hash)
66
+ self.jsapi_ticket = ticket_hash['ticket']
67
+ self.jsapi_ticket_expires_at = Time.current + ticket_hash['expires_in'].to_i
68
+ self.save
69
+ end
70
+
71
+ end
72
+ end
@@ -0,0 +1,23 @@
1
+ module Dingtalk
2
+ module Model::DingtalkUser
3
+ extend ActiveSupport::Concern
4
+
5
+ included do
6
+ attribute :uid, :string
7
+ attribute :unionid, :string, index: true
8
+ attribute :appid, :string
9
+ attribute :name, :string
10
+ attribute :avatar_url, :string
11
+ attribute :state, :string
12
+ attribute :access_token, :string
13
+ attribute :expires_at, :datetime
14
+ attribute :refresh_token, :string
15
+ attribute :extra, :json, default: {}
16
+ attribute :identity, :string, index: true
17
+
18
+ belongs_to :new_app, foreign_key: :appid, primary_key: :app_key
19
+ end
20
+
21
+
22
+ end
23
+ end
@@ -0,0 +1,11 @@
1
+ module Dingtalk
2
+
3
+ def self.use_relative_model_naming?
4
+ true
5
+ end
6
+
7
+ def self.table_name_prefix
8
+ 'dingtalk_'
9
+ end
10
+
11
+ end
@@ -0,0 +1,10 @@
1
+ <div class="<%= active_helper(modules: 'com/panel', active: 'menu ex-accordion is-active', item: 'menu ex-accordion is-active') %>" data-controller="menu">
2
+ <%= content_tag :div, class: 'menu-list' do %>
3
+ <%= link_to t('dingtalk.admin.apps.index.title'), { controller: 'dingtalk/admin/apps' }, class: active_helper(controllers: 'apps', active: 'is-active') -%>
4
+ <% end %>
5
+ <a class="menu-label" data-action="menu#toggle">
6
+ <i class="fas fa-cogs fa-fw"></i>
7
+ <span><%= t('dingtalk.admin.title') %></span>
8
+ <i class="fas dropdown"></i>
9
+ </a>
10
+ </div>
@@ -0,0 +1,9 @@
1
+ <td><%= model.name %></td>
2
+ <td>
3
+ <p><%= model.corp_id %></p>
4
+ <p><%= model.agent_id %></p>
5
+ </td>
6
+ <td>
7
+ <p><%= model.app_key %></p>
8
+ <p><%= model.app_secret %></p>
9
+ </td>
@@ -0,0 +1,10 @@
1
+ <th><%= Dingtalk::App.human_attribute_name(:name) %></th>
2
+ <th>
3
+ <p><%= Dingtalk::App.human_attribute_name(:corp_id) %></p>
4
+ <p><%= Dingtalk::App.human_attribute_name(:agent_id) %></p>
5
+ </th>
6
+ <th>
7
+ <p><%= Dingtalk::App.human_attribute_name(:app_key) %></p>
8
+ <p><%= Dingtalk::App.human_attribute_name(:app_secret) %></p>
9
+ </th>
10
+ <th></th>
@@ -0,0 +1,16 @@
1
+ <tr>
2
+ <td class="has-text-right"><%= Dingtalk::App.human_attribute_name(:corp_id) %></td>
3
+ <td><%= @app.corp_id %></td>
4
+ </tr>
5
+ <tr>
6
+ <td class="has-text-right"><%= Dingtalk::App.human_attribute_name(:agent_id) %></td>
7
+ <td><%= @app.agent_id %></td>
8
+ </tr>
9
+ <tr>
10
+ <td class="has-text-right"><%= Dingtalk::App.human_attribute_name(:app_key) %></td>
11
+ <td><%= @app.app_key %></td>
12
+ </tr>
13
+ <tr>
14
+ <td class="has-text-right"><%= Dingtalk::App.human_attribute_name(:app_secret) %></td>
15
+ <td><%= @app.app_secret %></td>
16
+ </tr>
@@ -0,0 +1,3 @@
1
+ <aside class="menu is-light" style="height: 100%">
2
+ <%= render 'dingtalk_nav' %>
3
+ </aside>
File without changes
@@ -0,0 +1 @@
1
+ json.dingtalk_user @dingtalk_user.as_json
@@ -0,0 +1 @@
1
+ import './index.js'
@@ -0,0 +1 @@
1
+ <div id="dingding">test1</div>
@@ -0,0 +1,41 @@
1
+ import * as dd from 'dingtalk-jsapi'
2
+ const div = document.getElementById('dingding')
3
+ div.innerText = 'sssss'
4
+ dd.ready(() => {
5
+ dd.runtime.permission.requestAuthCode({
6
+ corpId: 'ding9f5ed2cec249700e35c2f4657eb6378f',
7
+ onSuccess(info) {
8
+ div.innerText = info.code
9
+ dd.device.notification.alert({
10
+ message: JSON.stringify(info),
11
+ buttonName: "收到"
12
+ })
13
+ fetch('https://soa-okr.tallty.com/dingtalk/apps/info', {
14
+ method: 'POST',
15
+ headers: {
16
+ Accept: 'application/json',
17
+ 'Content-Type': 'application/json'
18
+ },
19
+ body: JSON.stringify({
20
+ app_id: 'xxxx',
21
+ code: info.code
22
+ })
23
+ }).then(response => {
24
+ return response.text()
25
+ }).then(body => {
26
+ Turbo.renderStreamMessage(body)
27
+ })
28
+ },
29
+ onFail(res) {
30
+ div.innerText = JSON.stringify(res)
31
+ dd.device.notification.alert({
32
+ message: JSON.stringify(res),
33
+ buttonName: "报错"
34
+ })
35
+ }
36
+ })
37
+ dd.device.notification.alert({
38
+ message: '测试',
39
+ buttonName: "收到"
40
+ })
41
+ })
@@ -0,0 +1,25 @@
1
+ <!DOCTYPE html>
2
+ <html lang="<%= I18n.locale %>">
3
+ <head>
4
+ <% if content_for?(:title) %>
5
+ <title><%= yield(:title) %></title>
6
+ <% else %>
7
+ <title><%= current_title %></title>
8
+ <% end %>
9
+ <meta name="viewport" content="width=device-width,initial-scale=1.0,user-scalable=no">
10
+ <meta name="turbo-cache-control" content="no-preview">
11
+ <%= stylesheet_vite_tag 'phone', media: 'all', 'data-turbo-track': 'reload' %>
12
+ <%= css_load suffix: 'phone', media: 'all', 'data-turbo-track': 'reload' %>
13
+ <%= javascript_vite_tag 'phone', 'data-turbo-track': 'reload' %>
14
+ <%= js_load suffix: 'phone', 'data-turbo-track': 'reload' %>
15
+ <% if content_for?(:wechat_js) %>
16
+ <%= yield(:wechat_js) %>
17
+ <% end %>
18
+ <%= csrf_meta_tags %>
19
+ <%= action_cable_meta_tag %>
20
+ <%= csp_meta_tag %>
21
+ </head>
22
+ <body>
23
+ <%= yield %>
24
+ </body>
25
+ </html>
@@ -0,0 +1,7 @@
1
+ zh:
2
+ dingtalk:
3
+ admin:
4
+ title: 钉钉开放平台
5
+ apps:
6
+ index:
7
+ title: 应用管理
@@ -0,0 +1,8 @@
1
+ zh:
2
+ activerecord:
3
+ enum:
4
+ dingtalk/app:
5
+ type:
6
+ Dingtalk::NormalApp: 普通App
7
+ Dingtalk::NewApp: NewApp
8
+
data/config/routes.rb ADDED
@@ -0,0 +1,19 @@
1
+ Rails.application.routes.draw do
2
+
3
+ namespace :dingtalk, defaults: { business: 'dingtalk' } do
4
+ namespace :admin, defaults: { namespace: 'admin' } do
5
+ resources :apps
6
+ end
7
+
8
+ controller :home do
9
+ get :index
10
+ end
11
+ resources :apps do
12
+ collection do
13
+ post :info
14
+ get :login
15
+ end
16
+ end
17
+ end
18
+
19
+ end
@@ -0,0 +1,12 @@
1
+ module RailsDingtalk
2
+ include ActiveSupport::Configurable
3
+
4
+ configure do |config|
5
+ config.httpx = {
6
+ ssl: {
7
+ verify_mode: OpenSSL::SSL::VERIFY_NONE
8
+ }
9
+ }
10
+ end
11
+
12
+ end
@@ -0,0 +1,24 @@
1
+ module RailsDingtalk
2
+ class Engine < ::Rails::Engine
3
+
4
+ config.autoload_paths += Dir[
5
+ "#{config.root}/app/models/app"
6
+ ]
7
+ config.eager_load_paths += Dir[
8
+ "#{config.root}/app/models/app"
9
+ ]
10
+
11
+ config.generators do |g|
12
+ g.rails = {
13
+ assets: false,
14
+ stylesheets: false,
15
+ helper: false
16
+ }
17
+ g.test_unit = {
18
+ fixture: true
19
+ }
20
+ #g.templates.unshift File.expand_path('lib/templates', RailsCom::Engine.root)
21
+ end
22
+
23
+ end
24
+ end
@@ -0,0 +1,2 @@
1
+ require 'rails_dingtalk/engine'
2
+ require 'rails_dingtalk/config'
metadata ADDED
@@ -0,0 +1,132 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: rails_dingtalk
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - qinmingyuan
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2021-09-10 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rails
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '5.0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '5.0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: httpx
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '0.16'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '0.16'
41
+ - !ruby/object:Gem::Dependency
42
+ name: http-form_data
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '2.3'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '2.3'
55
+ description: 钉钉
56
+ email:
57
+ - mingyuan0715@foxmail.com
58
+ executables: []
59
+ extensions: []
60
+ extra_rdoc_files: []
61
+ files:
62
+ - LICENSE
63
+ - README.md
64
+ - Rakefile
65
+ - app/apis/dingtalk/api/base.rb
66
+ - app/apis/dingtalk/api/inner/new.rb
67
+ - app/apis/dingtalk/api/inner/user.rb
68
+ - app/apis/dingtalk/api/new.rb
69
+ - app/apis/dingtalk/api/normal.rb
70
+ - app/apis/dingtalk/http_client.rb
71
+ - app/apis/dingtalk/signature.rb
72
+ - app/assets/javascripts/rails_dingtalk/index.js
73
+ - app/controllers/admin_controller.rb
74
+ - app/controllers/dingtalk/admin/apps_controller.rb
75
+ - app/controllers/dingtalk/admin/base_controller.rb
76
+ - app/controllers/dingtalk/apps_controller.rb
77
+ - app/controllers/dingtalk/base_controller.rb
78
+ - app/controllers/dingtalk/home_controller.rb
79
+ - app/jobs/dingtalk/dingtalk_user_job.rb
80
+ - app/models/app/dingtalk/new_app.rb
81
+ - app/models/app/dingtalk/normal_app.rb
82
+ - app/models/dingtalk.rb
83
+ - app/models/dingtalk/app.rb
84
+ - app/models/dingtalk/dingtalk_user.rb
85
+ - app/models/dingtalk/model/app.rb
86
+ - app/models/dingtalk/model/app/new_app.rb
87
+ - app/models/dingtalk/model/app/normal_app.rb
88
+ - app/models/dingtalk/model/dingtalk_user.rb
89
+ - app/views/admin/_dingtalk_nav.html.erb
90
+ - app/views/dingtalk/admin/apps/_index_tbody.html.erb
91
+ - app/views/dingtalk/admin/apps/_index_thead.html.erb
92
+ - app/views/dingtalk/admin/apps/_show_table.html.erb
93
+ - app/views/dingtalk/admin/base/_nav.html.erb
94
+ - app/views/dingtalk/apps/login.html.erb
95
+ - app/views/dingtalk/apps/login.json.jbuilder
96
+ - app/views/dingtalk/home/index-phone.js
97
+ - app/views/dingtalk/home/index.html.erb
98
+ - app/views/dingtalk/home/index.js
99
+ - app/views/layouts/dingtalk/basex.html.erb
100
+ - config/locales/zh.controller.yml
101
+ - config/locales/zh.enum.yml
102
+ - config/routes.rb
103
+ - lib/rails_dingtalk.rb
104
+ - lib/rails_dingtalk/config.rb
105
+ - lib/rails_dingtalk/engine.rb
106
+ homepage: https://github.com/work-design/rails_dingtalk
107
+ licenses:
108
+ - MIT
109
+ metadata:
110
+ homepage_uri: https://github.com/work-design/rails_dingtalk
111
+ source_code_uri: https://github.com/work-design/rails_dingtalk
112
+ changelog_uri: https://github.com/work-design/rails_dingtalk
113
+ post_install_message:
114
+ rdoc_options: []
115
+ require_paths:
116
+ - lib
117
+ required_ruby_version: !ruby/object:Gem::Requirement
118
+ requirements:
119
+ - - ">="
120
+ - !ruby/object:Gem::Version
121
+ version: '0'
122
+ required_rubygems_version: !ruby/object:Gem::Requirement
123
+ requirements:
124
+ - - ">="
125
+ - !ruby/object:Gem::Version
126
+ version: '0'
127
+ requirements: []
128
+ rubygems_version: 3.2.22
129
+ signing_key:
130
+ specification_version: 4
131
+ summary: Summary of RailsDingtalk
132
+ test_files: []