rails_dingtalk 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
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: []