Commit 4a7f41b5 by mingyuan

curd

parent e5f9d993
...@@ -8,4 +8,7 @@ gem 'puma' ...@@ -8,4 +8,7 @@ gem 'puma'
gem 'rails_ui', github: 'work-design/rails_ui' gem 'rails_ui', github: 'work-design/rails_ui'
gem 'rails_com', github: 'work-design/rails_com' gem 'rails_com', github: 'work-design/rails_com'
gem 'viter', github: 'qinmingyuan/viter'
gem 'default_form', github: 'qinmingyuan/default_form'
gem 'pry' gem 'pry'
GIT GIT
remote: https://github.com/qinmingyuan/default_form.git
revision: 476ba7231079b1071415ad4e953b55ce16ae1d0d
specs:
default_form (1.5.1)
rails_com (~> 1.2)
GIT
remote: https://github.com/qinmingyuan/viter.git
revision: 997cbc807babe4380f76ad0051518de12135702e
specs:
viter (0.1.0)
rails
GIT
remote: https://github.com/work-design/rails_com.git remote: https://github.com/work-design/rails_com.git
revision: 97e509876fd80ae76f1afc6c129ff817a96df0e9 revision: 97e509876fd80ae76f1afc6c129ff817a96df0e9
specs: specs:
...@@ -217,12 +231,14 @@ PLATFORMS ...@@ -217,12 +231,14 @@ PLATFORMS
x86_64-darwin-20 x86_64-darwin-20
DEPENDENCIES DEPENDENCIES
default_form!
pg pg
pry pry
puma puma
rails_com! rails_com!
rails_dingtalk! rails_dingtalk!
rails_ui! rails_ui!
viter!
BUNDLED WITH BUNDLED WITH
2.2.22 2.2.22
require 'dingtalk/http_client'
require 'dingtalk/api/base'
module Dingtalk::Api
module Base
BASE = 'https://oapi.dingtalk.com/'
attr_reader :app, :client
def initialize(app)
@app = app
@client = HttpClient.new
end
end
end
require 'httpx'
require 'http/form_data'
module Dingtalk
class HttpClient
attr_reader :http
def initialize
@http = HTTPX.with(**RailsWechat.config.httpx)
end
def get(path, headers: {}, params: {}, base: nil, **options)
headers['Accept'] ||= 'application/json'
url = base + path
response = @http.with_headers(headers).get(url, params: params)
parse_response(response, options[:as])
end
def post(path, payload, headers: {}, params: {}, base: nil, **options)
headers['Accept'] ||= 'application/json'
headers['Content-Type'] ||= 'application/json'
url = base + path
response = @http.with_headers(headers).post(url, params: params, body: payload)
parse_response(response, options[:as])
end
def post_file(path, file, headers: {}, params: {}, base: nil, **options)
headers['Accept'] ||= 'application/json'
url = base + path
form_file = file.is_a?(HTTP::FormData::File) ? file : HTTP::FormData::File.new(file)
response = @http.plugin(:multipart).with_headers(headers).post(
url,
params: params,
form: { media: form_file }
)
parse_response(response, options[:as])
end
private
def parse_response(response, parse_as)
raise "Request get fail, response status #{response.status}" if response.status != 200
content_type = response.content_type.mime_type
body = response.body.to_s
if content_type =~ /image|audio|video/
data = Tempfile.new('tmp')
data.binmode
data.write(body)
data.rewind
return data
elsif content_type =~ /html|xml/
data = Hash.from_xml(body)
else
data = JSON.parse body.gsub(/[\u0000-\u001f]+/, '')
end
case data['errcode']
when 0 # for request didn't expect results
data
# 42001: access_token timeout
# 40014: invalid access_token
# 40001, invalid credential, access_token is invalid or not latest hint
# 48001, api unauthorized hint, should not handle here # GH-230
when 42001, 40014, 40001, 41001
raise Wechat::AccessTokenExpiredError
# 40029, invalid code for mp # GH-225
# 43004, require subscribe hint # GH-214
when 2
raise Wechat::ResponseError.new(data['errcode'], data['errmsg'])
else
data
end
end
end
end
module Dingtalk
class Admin::AppsController < Admin::BaseController
before_action :set_new_app, only: [:new, :create]
before_action :set_app, only: [:show, :edit, :update, :destroy]
def index
@apps = App.page(params[:page])
end
private
def set_app
@app = App.find(params[:id])
end
def set_new_app
@app = App.new(app_params)
end
def app_params
params.fetch(:app, {}).permit(
:name,
:corp_id,
:agent_id,
:app_key,
:app_secret
)
end
end
end
module Dingtalk
class Admin::BaseController < AdminController
private
def set_app
@app = App.find(params[:app_id])
end
end
end
...@@ -3,9 +3,18 @@ module Dingtalk ...@@ -3,9 +3,18 @@ module Dingtalk
extend ActiveSupport::Concern extend ActiveSupport::Concern
included do included do
attribute :name, :string
attribute :agent_id, :string attribute :agent_id, :string
attribute :app_key, :string attribute :app_key, :string
attribute :app_secret, :string attribute :app_secret, :string
attribute :corp_id, :string
attribute :access_token, :string
attribute :access_token_expires_at, :datetime
end
def api
return @api if defined? @api
@api = Api::Base.new(self)
end end
end end
......
<%= form_with model: @app, url: { action: 'update' } do |f| %>
<%= render partial: 'form', locals: { f: f } %>
<%= f.submit %>
<% end %>
<%= form_with theme: 'search', model: Dingtalk::App.new, url: { action: params[:action] } do |f| %>
<div class="field-body">
<%= f.text_field :name %>
<div class="field is-narrow">
<%= f.submit %>
<%= link_to t('.clear'), filter_params(except: [:name]), class: 'button is-light' %>
</div>
</div>
<% end %>
<%= render 'error_messages', target: f.object %>
<%= f.text_field :name %>
<%= f.text_field :corp_id %>
<%= f.text_field :agent_id %>
<%= f.text_field :app_key %>
<%= f.text_field :app_secret %>
<td><%= model.name %></td>
<td>
<p><%= model.corp_id %></p>
<p><%= model.agent_id %></p>
</td>
<td>
<p><%= model.app_key %></p>
<p><%= model.app_secret %></p>
</td>
<th><%= Dingtalk::App.human_attribute_name(:name) %></th>
<th>
<p><%= Dingtalk::App.human_attribute_name(:corp_id) %></p>
<p><%= Dingtalk::App.human_attribute_name(:agent_id) %></p>
</th>
<th>
<p><%= Dingtalk::App.human_attribute_name(:app_key) %></p>
<p><%= Dingtalk::App.human_attribute_name(:app_secret) %></p>
</th>
<th></th>
<%= form_with model: @app, url: { action: 'create' } do |f| %>
<%= render partial: 'form', locals: { f: f } %>
<%= f.submit %>
<% end %>
<tr>
<td class="has-text-right"><%= Dingtalk::App.human_attribute_name(:corp_id) %></td>
<td><%= @app.corp_id %></td>
</tr>
<tr>
<td class="has-text-right"><%= Dingtalk::App.human_attribute_name(:agent_id) %></td>
<td><%= @app.agent_id %></td>
</tr>
<tr>
<td class="has-text-right"><%= Dingtalk::App.human_attribute_name(:app_key) %></td>
<td><%= @app.app_key %></td>
</tr>
<tr>
<td class="has-text-right"><%= Dingtalk::App.human_attribute_name(:app_secret) %></td>
<td><%= @app.app_secret %></td>
</tr>
<%= render layout: 'index_table', locals: { cache_key: Dingtalk::App.column_names.hash } do %>
<%= render partial: 'index_tbody', layout: 'index_tr', collection: @apps, as: :model %>
<% end %>
<%= paginate @apps %>
Rails.application.routes.draw do Rails.application.routes.draw do
namespace :dingtalk, defaults: { business: 'dingtalk' } do
namespace :admin, defaults: { namespace: 'admin' } do
resources :apps
end
end
end end
{
"name": "rails_dingtalk",
"version": "1.0.0",
"main": "index.js",
"repository": "git@github.com:work-design/rails_dingtalk.git",
"author": "qinmingyuan <mingyuan0715@foxmail.com>",
"license": "MIT",
"dependencies": {
"dingtalk-jsapi": "^2.13.51"
}
}
require 'test_helper'
class Dingtalk::Admin::AppsControllerTest < ActionDispatch::IntegrationTest
setup do
@app = apps(:one)
end
test 'index ok' do
get url_for(controller: 'dingtalk/admin/apps')
assert_response :success
end
test 'new ok' do
get url_for(controller: 'dingtalk/admin/apps')
assert_response :success
end
test 'create ok' do
assert_difference('App.count') do
post(
url_for(controller: 'dingtalk/admin/apps', action: 'create'),
params: { app: { agent_id: @dingtalk_admin_app.agent_id, app_key: @dingtalk_admin_app.app_key, app_secret: @dingtalk_admin_app.app_secret, corp_id: @dingtalk_admin_app.corp_id } },
as: :turbo_stream
)
end
assert_response :success
end
test 'show ok' do
get url_for(controller: 'dingtalk/admin/apps', action: 'show', id: @app.id)
assert_response :success
end
test 'edit ok' do
get url_for(controller: 'dingtalk/admin/apps', action: 'edit', id: @app.id)
assert_response :success
end
test 'update ok' do
patch(
url_for(controller: 'dingtalk/admin/apps', action: 'update', id: @app.id),
params: { app: { agent_id: @dingtalk_admin_app.agent_id, app_key: @dingtalk_admin_app.app_key, app_secret: @dingtalk_admin_app.app_secret, corp_id: @dingtalk_admin_app.corp_id } },
as: :turbo_stream
)
assert_response :success
end
test 'destroy ok' do
assert_difference('App.count', -1) do
delete url_for(controller: 'dingtalk/admin/apps', action: 'destroy', id: @app.id), as: :turbo_stream
end
assert_response :success
end
end
Subproject commit e63687fd7d8a8dd68a203674dc8b7f0855189df4 Subproject commit 0512a0cbcfb60a3736a50b80345bb3517b98c0b1
require "application_system_test_case"
class AppsTest < ApplicationSystemTestCase
setup do
@dingtalk_admin_app = dingtalk_admin_apps(:one)
end
test "visiting the index" do
visit dingtalk_admin_apps_url
assert_selector "h1", text: "Apps"
end
test "creating a App" do
visit dingtalk_admin_apps_url
click_on "New App"
fill_in "Agent", with: @dingtalk_admin_app.agent_id
fill_in "App key", with: @dingtalk_admin_app.app_key
fill_in "App secret", with: @dingtalk_admin_app.app_secret
fill_in "Corp", with: @dingtalk_admin_app.corp_id
click_on "Create App"
assert_text "App was successfully created"
click_on "Back"
end
test "updating a App" do
visit dingtalk_admin_apps_url
click_on "Edit", match: :first
fill_in "Agent", with: @dingtalk_admin_app.agent_id
fill_in "App key", with: @dingtalk_admin_app.app_key
fill_in "App secret", with: @dingtalk_admin_app.app_secret
fill_in "Corp", with: @dingtalk_admin_app.corp_id
click_on "Update App"
assert_text "App was successfully updated"
click_on "Back"
end
test "destroying a App" do
visit dingtalk_admin_apps_url
page.accept_confirm do
click_on "Destroy", match: :first
end
assert_text "App was successfully destroyed"
end
end
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
# yarn lockfile v1
dingtalk-jsapi@^2.13.51:
version "2.13.51"
resolved "https://registry.yarnpkg.com/dingtalk-jsapi/-/dingtalk-jsapi-2.13.51.tgz#8fdbd747899c1e03de5c1705ca7f1093de19e6e2"
integrity sha512-gm/9eLdNCUVZzOt0vLKJ2l2QoQK7CBNrYP7b86EMy9NKO6xg4QI7aYAObtde9+u6OTroF9dTsax6ngvx2fA5Gw==
dependencies:
promise-polyfill "^7.1.0"
promise-polyfill@^7.1.0:
version "7.1.2"
resolved "https://registry.yarnpkg.com/promise-polyfill/-/promise-polyfill-7.1.2.tgz#ab05301d8c28536301622d69227632269a70ca3b"
integrity sha512-FuEc12/eKqqoRYIGBrUptCBRhobL19PS2U31vMNTfyck1FxPyMfgsXyW4Mav85y/ZN1hop3hOwRlUDok23oYfQ==
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment