Commit 5fc210aa authored by jiangkebao's avatar jiangkebao

初始化项目

parent c505d89a
/vendor/
composer.lock
.idea/
\ No newline at end of file
<?php
$header = <<<EOF
This file is part of the mingyoung/dingtalk.
(c) 张铭阳 <mingyoungcheung@gmail.com>
This source file is subject to the MIT license that is bundled
with this source code in the file LICENSE.
EOF;
return PhpCsFixer\Config::create()
->setRules([
'@Symfony' => true,
'phpdoc_summary' => false,
'header_comment' => ['header' => $header],
'ordered_imports' => true,
'phpdoc_no_empty_return' => false,
'no_empty_comment' => false,
])
->setFinder(
PhpCsFixer\Finder::create()
->exclude('vendor')
->in(__DIR__)
)
->setUsingCache(false)
;
language: php
env:
global:
- setup=stable
matrix:
fast_finish: true
include:
- php: 7.0
- php: 7.0
env: setup=lowest
- php: 7.1
- php: 7.1
env: setup=lowest
- php: 7.2
- php: 7.2
env: setup=lowest
- php: 7.3
- php: 7.3
env: setup=lowest
install:
- if [[ $setup = 'stable' ]]; then travis_retry composer update --prefer-dist --no-interaction --prefer-stable --no-suggest; fi
- if [[ $setup = 'lowest' ]]; then travis_retry composer update --prefer-dist --no-interaction --prefer-lowest --prefer-stable --no-suggest; fi
script: ./vendor/bin/phpunit
MIT License
Copyright (c) 2020 张铭阳
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
# dingtalk
<p align="center">
<h1 align="center">EasyDingTalk</h1>
</p>
<p align="center">
<a href="https://travis-ci.org/mingyoung/dingtalk"><img src="https://travis-ci.org/mingyoung/dingtalk.svg" alt="Build Status"></a>
<a href="https://scrutinizer-ci.com/g/mingyoung/dingtalk/?branch=master"><img src="https://scrutinizer-ci.com/g/mingyoung/dingtalk/badges/quality-score.png?b=master" alt="Scrutinizer Code Quality"></a>
<a href="https://packagist.org/packages/mingyoung/dingtalk"><img src="https://poser.pugx.org/mingyoung/dingtalk/v/stable.svg" alt="Latest Stable Version"></a>
<a href="https://packagist.org/packages/mingyoung/dingtalk"><img src="https://poser.pugx.org/mingyoung/dingtalk/d/total.svg" alt="Total Downloads"></a>
<a href="https://packagist.org/packages/mingyoung/dingtalk"><img src="https://poser.pugx.org/mingyoung/dingtalk/license.svg" alt="License"></a>
</p>
## 介绍
EasyDingTalk 封装了钉钉身份验证、通讯录管理、消息通知、审批、群机器人、业务事件回调管理等服务端接口,让开发者可以使用简单的配置,提供简洁的 API 以供方便快速地调用钉钉接口。
## 环境要求
- PHP 7.0+
- [Composer](https://getcomposer.org/)
## 安装
```bash
composer require mingyoung/dingtalk:^2.0
```
## 使用
```php
use EasyDingTalk\Application;
$config = [
'corp_id' => 'dingd3ir8195906jfo93',
'app_key' => 'dingwu33fo1fjc0fszad',
'app_secret' => 'RsuMFgEIY3jg5UMidkvwpzEobWjf9Fcu3oLqLyCUIgzULm54WcV7j9fi3fJlUshk',
];
$app = new Application($config);
```
## 文档
[https://docs.easydingtalk.org](https://docs.easydingtalk.org)
## License
MIT
## 支持作者
开源不易,如果你觉得 EasyDingTalk 节省了你的时间,方便了你的开发,不妨赞赏支持一下
<img width="280" height="280" src="https://user-images.githubusercontent.com/6228858/69937515-f957d180-1515-11ea-91bb-2b99684e8898.JPG">
{
"name": "meibuyu/dingtalk",
"description": "EasyDingTalk, Alibaba Dingtalk SDK for PHP",
"keywords": [
"dingtalk",
"dingding",
"easydingtalk",
"sdk",
"钉钉"
],
"license": "MIT",
"authors": [
{
"name": "张铭阳",
"email": "mingyoungcheung@gmail.com"
}
],
"require": {
"php": ">=7.0",
"overtrue/http": "^1.1.2",
"pimple/pimple": "^3.0",
"psr/simple-cache": "^1.0",
"monolog/monolog": "^1.23 || ^2.0",
"symfony/cache": "^3.3 || ^4.0 || ^5.0",
"symfony/http-foundation": "^3.2 || ^4.0 || ^5.0"
},
"require-dev": {
"mockery/mockery": "^1.0",
"phpunit/phpunit": "^6.5 || ^7.0"
},
"autoload": {
"psr-4": {
"EasyDingTalk\\": "src/"
},
"files": [
"src/helpers.php"
]
},
"autoload-dev": {
"psr-4": {
"EasyDingTalk\\Tests\\": "tests/"
}
}
}
<?xml version="1.0" encoding="UTF-8"?>
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/7.5/phpunit.xsd"
bootstrap="vendor/autoload.php"
colors="true"
forceCoversAnnotation="true"
beStrictAboutCoversAnnotation="true"
beStrictAboutOutputDuringTests="true"
beStrictAboutTodoAnnotatedTests="true"
verbose="true">
<testsuites>
<testsuite name="default">
<directory suffix="Test.php">tests</directory>
</testsuite>
</testsuites>
<filter>
<whitelist processUncoveredFilesFromWhitelist="true">
<directory suffix=".php">src</directory>
</whitelist>
</filter>
</phpunit>
<?php
/*
* This file is part of the mingyoung/dingtalk.
*
* (c) 张铭阳 <mingyoungcheung@gmail.com>
*
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/
namespace EasyDingTalk;
use Overtrue\Http\Support\Collection;
use Pimple\Container;
/**
* @property \EasyDingTalk\Auth\SsoClient $sso
* @property \EasyDingTalk\Auth\OAuthClient $oauth
* @property \EasyDingTalk\Chat\Client $chat
* @property \EasyDingTalk\Role\Client $role
* @property \EasyDingTalk\User\Client $user
* @property \EasyDingTalk\Media\Client $media
* @property \EasyDingTalk\H5app\Client $h5app
* @property \EasyDingTalk\Health\Client $health
* @property \EasyDingTalk\Report\Client $report
* @property \EasyDingTalk\Checkin\Client $checkin
* @property \EasyDingTalk\Contact\Client $contact
* @property \EasyDingTalk\Process\Client $process
* @property \EasyDingTalk\Calendar\Client $calendar
* @property \EasyDingTalk\Callback\Client $callback
* @property \EasyDingTalk\Microapp\Client $microapp
* @property \EasyDingTalk\Schedule\Client $schedule
* @property \EasyDingTalk\Blackboard\Client $blackboard
* @property \EasyDingTalk\Attendance\Client $attendance
* @property \EasyDingTalk\Department\Client $department
* @property \EasyDingTalk\Conversation\Client $conversation
* @property \EasyDingTalk\Kernel\Http\Client $client
* @property \Monolog\Logger $logger
* @property \EasyDingTalk\Kernel\Server $server
* @property \Symfony\Component\HttpFoundation\Request $request
* @property \EasyDingTalk\Kernel\Encryption\Encryptor $encryptor
* @property \EasyDingTalk\Kernel\AccessToken $access_token
*/
class Application extends Container
{
/**
* @var array
*/
protected $providers = [
Auth\ServiceProvider::class,
Chat\ServiceProvider::class,
Role\ServiceProvider::class,
User\ServiceProvider::class,
Media\ServiceProvider::class,
H5app\ServiceProvider::class,
Health\ServiceProvider::class,
Report\ServiceProvider::class,
Checkin\ServiceProvider::class,
Contact\ServiceProvider::class,
Process\ServiceProvider::class,
Calendar\ServiceProvider::class,
Callback\ServiceProvider::class,
Microapp\ServiceProvider::class,
Schedule\ServiceProvider::class,
Blackboard\ServiceProvider::class,
Attendance\ServiceProvider::class,
Department\ServiceProvider::class,
Conversation\ServiceProvider::class,
Kernel\Providers\ClientServiceProvider::class,
Kernel\Providers\LoggerServiceProvider::class,
Kernel\Providers\ServerServiceProvider::class,
Kernel\Providers\RequestServiceProvider::class,
Kernel\Providers\EncryptionServiceProvider::class,
Kernel\Providers\AccessTokenServiceProvider::class,
];
/**
* Application constructor.
*
* @param array $config
* @param array $values
*/
public function __construct($config = [], array $values = [])
{
parent::__construct($values);
$this['config'] = function () use ($config) {
return new Collection($config);
};
foreach ($this->providers as $provider) {
$this->register(new $provider());
}
}
/**
* @param $name
*
* @return mixed
*/
public function __get($name)
{
return $this[$name];
}
}
<?php
/*
* This file is part of the mingyoung/dingtalk.
*
* (c) 张铭阳 <mingyoungcheung@gmail.com>
*
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/
namespace EasyDingTalk\Attendance;
use EasyDingTalk\Kernel\BaseClient;
class Client extends BaseClient
{
/**
* 企业考勤排班详情
*
* @param string $date
* @param int|null $offset
* @param int|null $size
*
* @return mixed
*/
public function schedules($date, $offset = null, $size = null)
{
return $this->client->postJson('topapi/attendance/listschedule', [
'workDate' => $date, 'offset' => $offset, 'size' => $size,
]);
}
/**
* 企业考勤组详情
*
* @param int|null $offset
* @param int|null $size
*
* @return mixed
*/
public function groups($offset = null, $size = null)
{
return $this->client->postJson('topapi/attendance/getsimplegroups', compact('offset', 'size'));
}
/**
* 获取用户考勤组
*
* @param string $userId
*
* @return mixed
*/
public function userGroup($userId)
{
return $this->client->postJson('topapi/attendance/getusergroup', ['userid' => $userId]);
}
/**
* 获取打卡详情
*
* @param array $params
*
* @return mixed
*/
public function records($params)
{
return $this->client->postJson('attendance/listRecord', $params);
}
/**
* 获取打卡结果
*
* @param array $params
*
* @return mixed
*/
public function results($params)
{
return $this->client->postJson('attendance/list', $params);
}
/**
* 获取请假时长
*
* @param string $userId
* @param string $from
* @param string $to
*
* @return mixed
*/
public function duration($userId, $from, $to)
{
return $this->client->postJson('topapi/attendance/getleaveapproveduration', [
'userid' => $userId, 'from_date' => $from, 'to_date' => $to,
]);
}
/**
* 查询请假状态
*
* @param array $params
*
* @return mixed
*/
public function status($params)
{
return $this->client->postJson('topapi/attendance/getleavestatus', $params);
}
}
<?php
/*
* This file is part of the mingyoung/dingtalk.
*
* (c) 张铭阳 <mingyoungcheung@gmail.com>
*
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/
namespace EasyDingTalk\Attendance;
use Pimple\Container;
use Pimple\ServiceProviderInterface;
class ServiceProvider implements ServiceProviderInterface
{
/**
* Registers services on the given container.
* This method should only be used to configure services and parameters.
* It should not get services.
*
* @param \Pimple\Container $pimple A container instance
*/
public function register(Container $pimple)
{
$pimple['attendance'] = function ($app) {
return new Client($app);
};
}
}
<?php
/*
* This file is part of the mingyoung/dingtalk.
*
* (c) 张铭阳 <mingyoungcheung@gmail.com>
*
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/
namespace EasyDingTalk\Auth;
use function EasyDingTalk\str_random;
use function EasyDingTalk\tap;
trait HasStateParameter
{
/**
* @var bool
*/
protected $stateless = false;
/**
* @return $this
*/
public function stateless()
{
$this->stateless = true;
return $this;
}
/**
* Generate state.
*
* @return string
*/
protected function makeState()
{
return tap(str_random(64), function ($state) {
$this->app['request']->getSession()->set('state', $state);
});
}
/**
* @param string|null $state
*
* @return bool
*/
protected function hasValidState($state)
{
if ($this->stateless) {
return true;
}
return !is_null($state) && ($state === $this->app['request']->getSession()->get('state'));
}
}
<?php
/*
* This file is part of the mingyoung/dingtalk.
*
* (c) 张铭阳 <mingyoungcheung@gmail.com>
*
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/
namespace EasyDingTalk\Auth;
use EasyDingTalk\Kernel\Exceptions\Exception;
class InvalidStateException extends Exception
{
//
}
<?php
/*
* This file is part of the mingyoung/dingtalk.
*
* (c) 张铭阳 <mingyoungcheung@gmail.com>
*
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/
namespace EasyDingTalk\Auth;
use EasyDingTalk\Kernel\Http\Client;
use Symfony\Component\HttpFoundation\RedirectResponse;
class OAuthClient extends Client
{
use HasStateParameter;
/**
* @var array
*/
protected $credential;
/**
* @var bool
*/
protected $withQrConnect = false;
/**
* @var string|null
*/
protected $redirect;
/**
* @param string $name
*
* @return $this
*/
public function use($name)
{
$this->credential = $this->app['config']->get('oauth')[$name];
return $this;
}
/**
* @return string
*/
public function getRedirectUrl()
{
return $this->redirect ?: $this->credential['redirect'];
}
/**
* @param string $url
*
* @return $this
*/
public function setRedirectUrl($url)
{
$this->redirect = $url;
return $this;
}
/**
* @return $this
*/
public function withQrConnect()
{
$this->withQrConnect = true;
return $this;
}
/**
* Redirect to the authentication page.
*
* @param string|null $url
*
* @return \Symfony\Component\HttpFoundation\RedirectResponse
*/
public function redirect($url = null)
{
$query = [
'appid' => $this->credential['client_id'],
'response_type' => 'code',
'scope' => $this->credential['scope'],
'state' => $this->makeState(),
'redirect_uri' => $url ?: $this->getRedirectUrl(),
];
return new RedirectResponse(
sprintf('https://oapi.dingtalk.com/connect/%s?%s', $this->withQrConnect ? 'qrconnect' : 'oauth2/sns_authorize', http_build_query(array_filter($query)))
);
}
/**
* @return array
*
* @throws \EasyDingTalk\Auth\InvalidStateException
*/
public function user($code)
{
$data = [
'tmp_auth_code' => $code,
];
$query = [
'accessKey' => $this->credential['client_id'],
'timestamp' => $timestamp = (int) microtime(true) * 1000,
'signature' => $this->signature($timestamp),
];
return $this->postJson('sns/getuserinfo_bycode', $data, $query);
}
/**
* 计算签名
*
* @param int $timestamp
*
* @return string
*/
public function signature($timestamp)
{
return base64_encode(hash_hmac('sha256', $timestamp, $this->credential['client_secret'], true));
}
}
<?php
/*
* This file is part of the mingyoung/dingtalk.
*
* (c) 张铭阳 <mingyoungcheung@gmail.com>
*
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/
namespace EasyDingTalk\Auth;
use Pimple\Container;
use Pimple\ServiceProviderInterface;
use Symfony\Component\HttpFoundation\Session\Session;
class ServiceProvider implements ServiceProviderInterface
{
/**
* Registers services on the given container.
* This method should only be used to configure services and parameters.
* It should not get services.
*
* @param \Pimple\Container $pimple A container instance
*/
public function register(Container $pimple)
{
$pimple['sso'] = function ($app) {
return new SsoClient($app);
};
$pimple['oauth'] = function ($app) {
if (!$app['request']->hasSession()) {
$app['request']->setSession(new Session());
}
return new OAuthClient($app);
};
}
}
<?php
/*
* This file is part of the mingyoung/dingtalk.
*
* (c) 张铭阳 <mingyoungcheung@gmail.com>
*
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/
namespace EasyDingTalk\Auth;
use EasyDingTalk\Kernel\Http\Client;
class SsoClient extends Client
{
/**
* 获取应用后台免登 AccessToken
*
* @return mixed
*/
public function getToken()
{
return $this->get('sso/gettoken', [
'corpid' => $this->app['config']->get('corp_id'),
'corpsecret' => $this->app['config']->get('sso_secret'),
]);
}
/**
* 获取用户身份信息
*
* @return mixed
*/
public function user()
{
return $this->get('sso/getuserinfo', [
'access_token' => $this->getToken()['access_token'],
'code' => $this->app['request']->get('code'),
]);
}
}
<?php
/*
* This file is part of the mingyoung/dingtalk.
*
* (c) 张铭阳 <mingyoungcheung@gmail.com>
*
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/
namespace EasyDingTalk\Blackboard;
use EasyDingTalk\Kernel\BaseClient;
class Client extends BaseClient
{
/**
* 获取用户公告数据
*
* @param string $userid
*
* @return mixed
*/
public function list($userid)
{
return $this->client->postJson('topapi/blackboard/listtopten', compact('userid'));
}
}
<?php
/*
* This file is part of the mingyoung/dingtalk.
*
* (c) 张铭阳 <mingyoungcheung@gmail.com>
*
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/
namespace EasyDingTalk\Blackboard;
use Pimple\Container;
use Pimple\ServiceProviderInterface;
class ServiceProvider implements ServiceProviderInterface
{
/**
* Registers services on the given container.
* This method should only be used to configure services and parameters.
* It should not get services.
*
* @param \Pimple\Container $pimple A container instance
*/
public function register(Container $pimple)
{
$pimple['blackboard'] = function ($app) {
return new Client($app);
};
}
}
<?php
/*
* This file is part of the mingyoung/dingtalk.
*
* (c) 张铭阳 <mingyoungcheung@gmail.com>
*
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/
namespace EasyDingTalk\Calendar;
use EasyDingTalk\Kernel\BaseClient;
class Client extends BaseClient
{
/**
* 创建日程
*
* @param array $params
*
* @return mixed
*/
public function create($params)
{
return $this->client->postJson('topapi/calendar/create', $params);
}
}
<?php
/*
* This file is part of the mingyoung/dingtalk.
*
* (c) 张铭阳 <mingyoungcheung@gmail.com>
*
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/
namespace EasyDingTalk\Calendar;
use Pimple\Container;
use Pimple\ServiceProviderInterface;
class ServiceProvider implements ServiceProviderInterface
{
/**
* Registers services on the given container.
* This method should only be used to configure services and parameters.
* It should not get services.
*
* @param \Pimple\Container $pimple A container instance
*/
public function register(Container $pimple)
{
$pimple['calendar'] = function ($app) {
return new Client($app);
};
}
}
<?php
/*
* This file is part of the mingyoung/dingtalk.
*
* (c) 张铭阳 <mingyoungcheung@gmail.com>
*
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/
namespace EasyDingTalk\Callback;
use EasyDingTalk\Kernel\BaseClient;
class Client extends BaseClient
{
/**
* 注册业务事件回调接口
*
* @param array $params
*
* @return mixed
*/
public function register($params)
{
$params['token'] = $this->app['config']->get('token');
$params['aes_key'] = $this->app['config']->get('aes_key');
return $this->client->postJson('call_back/register_call_back', $params);
}
/**
* 查询事件回调接口
*
* @return mixed
*/
public function list()
{
return $this->client->get('call_back/get_call_back');
}
/**
* 更新事件回调接口
*
* @return mixed
*/
public function update($params)
{
$params['token'] = $this->app['config']->get('token');
$params['aes_key'] = $this->app['config']->get('aes_key');
return $this->client->postJson('call_back/update_call_back', $params);
}
/**
* 删除事件回调接口
*
* @return mixed
*/
public function delete()
{
return $this->client->get('call_back/delete_call_back');
}
/**
* 获取回调失败结果
*
* @return mixed
*/
public function failed()
{
return $this->client->get('call_back/get_call_back_failed_result');
}
}
<?php
/*
* This file is part of the mingyoung/dingtalk.
*
* (c) 张铭阳 <mingyoungcheung@gmail.com>
*
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/
namespace EasyDingTalk\Callback;
use Pimple\Container;
use Pimple\ServiceProviderInterface;
class ServiceProvider implements ServiceProviderInterface
{
/**
* Registers services on the given container.
* This method should only be used to configure services and parameters.
* It should not get services.
*
* @param \Pimple\Container $pimple A container instance
*/
public function register(Container $pimple)
{
$pimple['callback'] = function ($app) {
return new Client($app);
};
}
}
<?php
/*
* This file is part of the mingyoung/dingtalk.
*
* (c) 张铭阳 <mingyoungcheung@gmail.com>
*
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/
namespace EasyDingTalk\Chat;
use EasyDingTalk\Kernel\BaseClient;
class Client extends BaseClient
{
/**
* 发送群消息
*
* @param string $chatId
* @param string $message
*
* @return mixed
*/
public function send($chatId, $message)
{
return $this->client->postJson('chat/send', [
'chatid' => $chatId, 'msg' => $message,
]);
}
/**
* 查询群消息已读人员列表
*
* @param string $messageId
* @param int $cursor
* @param int $size
*
* @return mixed
*/
public function result($messageId, $cursor, $size)
{
return $this->client->get('chat/getReadList', [
'messageId' => $messageId, 'cursor' => $cursor, 'size' => $size,
]);
}
/**
* 创建会话
*
* @param array $params
*
* @return mixed
*/
public function create($params)
{
return $this->client->postJson('chat/create', $params);
}
/**
* 修改会话
*
* @param string $chatId
* @param array $params
*
* @return mixed
*/
public function update($chatId, $params)
{
return $this->client->postJson('chat/update', ['chatid' => $chatId] + $params);
}
/**
* 获取会话
*
* @param string $chatId
*
* @return mixed
*/
public function get($chatId)
{
return $this->client->get('chat/get', ['chatid' => $chatId]);
}
}
<?php
/*
* This file is part of the mingyoung/dingtalk.
*
* (c) 张铭阳 <mingyoungcheung@gmail.com>
*
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/
namespace EasyDingTalk\Chat;
use Pimple\Container;
use Pimple\ServiceProviderInterface;
class ServiceProvider implements ServiceProviderInterface
{
/**
* Registers services on the given container.
* This method should only be used to configure services and parameters.
* It should not get services.
*
* @param \Pimple\Container $pimple A container instance
*/
public function register(Container $pimple)
{
$pimple['chat'] = function ($app) {
return new Client($app);
};
}
}
<?php
/*
* This file is part of the mingyoung/dingtalk.
*
* (c) 张铭阳 <mingyoungcheung@gmail.com>
*
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/
namespace EasyDingTalk\Checkin;
use EasyDingTalk\Kernel\BaseClient;
class Client extends BaseClient
{
/**
* 获取部门用户签到记录
*
* @param array $params
*
* @return mixed
*/
public function records($params)
{
return $this->client->get('checkin/record', $params);
}
/**
* 获取用户签到记录
*
* @param array $params
*
* @return mixed
*/
public function get($params)
{
return $this->client->postJson('topapi/checkin/record/get', $params);
}
}
<?php
/*
* This file is part of the mingyoung/dingtalk.
*
* (c) 张铭阳 <mingyoungcheung@gmail.com>
*
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/
namespace EasyDingTalk\Checkin;
use Pimple\Container;
use Pimple\ServiceProviderInterface;
class ServiceProvider implements ServiceProviderInterface
{
/**
* Registers services on the given container.
* This method should only be used to configure services and parameters.
* It should not get services.
*
* @param \Pimple\Container $pimple A container instance
*/
public function register(Container $pimple)
{
$pimple['checkin'] = function ($app) {
return new Client($app);
};
}
}
<?php
/*
* This file is part of the mingyoung/dingtalk.
*
* (c) 张铭阳 <mingyoungcheung@gmail.com>
*
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/
namespace EasyDingTalk\Contact;
use EasyDingTalk\Kernel\BaseClient;
class Client extends BaseClient
{
/**
* 获取外部联系人标签列表
*
* @param int $offset
* @param int $size
*
* @return mixed
*/
public function labels($offset = 0, $size = 100)
{
return $this->client->postJson('topapi/extcontact/listlabelgroups', compact('offset', 'size'));
}
/**
* 获取外部联系人列表
*
* @param int $offset
* @param int $size
*
* @return mixed
*/
public function list($offset = 0, $size = 100)
{
return $this->client->postJson('topapi/extcontact/list', compact('offset', 'size'));
}
/**
* 获取企业外部联系人详情
*
* @param string $userId
*
* @return mixed
*/
public function get($userId)
{
return $this->client->postJson('topapi/extcontact/get', ['user_id' => $userId]);
}
/**
* 添加外部联系人
*
* @param array $contact
*
* @return mixed
*/
public function create($contact)
{
return $this->client->postJson('topapi/extcontact/create', compact('contact'));
}
/**
* 更新外部联系人
*
* @param string $userId
* @param array $contact
*
* @return mixed
*/
public function update($userId, $contact)
{
$contact = ['user_id' => $userId] + $contact;
return $this->client->postJson('topapi/extcontact/update', compact('contact'));
}
/**
* 删除外部联系人
*
* @param string $userId
*
* @return mixed
*/
public function delete($userId)
{
return $this->client->postJson('topapi/extcontact/delete', ['user_id' => $userId]);
}
/**
* 获取通讯录权限范围
*
* @return mixed
*/
public function scopes()
{
return $this->client->get('auth/scopes');
}
}
<?php
/*
* This file is part of the mingyoung/dingtalk.
*
* (c) 张铭阳 <mingyoungcheung@gmail.com>
*
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/
namespace EasyDingTalk\Contact;
use Pimple\Container;
use Pimple\ServiceProviderInterface;
class ServiceProvider implements ServiceProviderInterface
{
/**
* Registers services on the given container.
* This method should only be used to configure services and parameters.
* It should not get services.
*
* @param \Pimple\Container $pimple A container instance
*/
public function register(Container $pimple)
{
$pimple['contact'] = function ($app) {
return new Client($app);
};
}
}
<?php
/*
* This file is part of the mingyoung/dingtalk.
*
* (c) 张铭阳 <mingyoungcheung@gmail.com>
*
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/
namespace EasyDingTalk\Conversation;
use EasyDingTalk\Kernel\BaseClient;
use function EasyDingTalk\tap;
class Client extends BaseClient
{
/**
* 发送普通消息
*
* @param string $sender
* @param string $cid
* @param array $message
*
* @return mixed
*/
public function sendGeneralMessage($sender, $cid, $message)
{
return $this->client->postJson('message/send_to_conversation', [
'sender' => $sender, 'cid' => $cid, 'msg' => $message,
]);
}
/**
* 发送工作通知消息
*
* @param array $params
*
* @return mixed
*/
public function sendCorporationMessage($params)
{
return $this->client->post('topapi/message/corpconversation/asyncsend_v2', $params);
}
/**
* @param int $taskId
*
* @return mixed
*/
public function corporationMessage($taskId)
{
$client = new class($this->app) extends BaseClient {
/**
* 任务 ID
*
* @var int
*/
protected $taskId;
/**
* @param int
*/
public function setTaskId($taskId)
{
$this->taskId = $taskId;
return $this;
}
/**
* 查询工作通知消息的发送进度
*
* @return mixed
*/
public function progress()
{
return $this->client->postJson('topapi/message/corpconversation/getsendprogress', [
'agent_id' => $this->app['config']['agent_id'], 'task_id' => $this->taskId,
]);
}
/**
* 查询工作通知消息的发送结果
*
* @return mixed
*/
public function result()
{
return $this->client->postJson('topapi/message/corpconversation/getsendresult', [
'agent_id' => $this->app['config']['agent_id'], 'task_id' => $this->taskId,
]);
}
};
return tap($client, function ($client) use ($taskId) {
$client->setTaskId($taskId);
});
}
}
<?php
/*
* This file is part of the mingyoung/dingtalk.
*
* (c) 张铭阳 <mingyoungcheung@gmail.com>
*
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/
namespace EasyDingTalk\Conversation;
use Pimple\Container;
use Pimple\ServiceProviderInterface;
class ServiceProvider implements ServiceProviderInterface
{
/**
* Registers services on the given container.
* This method should only be used to configure services and parameters.
* It should not get services.
*
* @param \Pimple\Container $pimple A container instance
*/
public function register(Container $pimple)
{
$pimple['conversation'] = function ($app) {
return new Client($app);
};
}
}
<?php
/*
* This file is part of the mingyoung/dingtalk.
*
* (c) 张铭阳 <mingyoungcheung@gmail.com>
*
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/
namespace EasyDingTalk\Department;
use EasyDingTalk\Kernel\BaseClient;
class Client extends BaseClient
{
/**
* 获取子部门 ID 列表
*
* @param string $id 部门ID
*
* @return mixed
*/
public function getSubDepartmentIds($id)
{
return $this->client->get('department/list_ids', compact('id'));
}
/**
* 获取部门列表
*
* @param bool $isFetchChild
* @param string $id
* @param string $lang
*
* @return mixed
*/
public function list($id = null, bool $isFetchChild = false, $lang = null)
{
return $this->client->get('department/list', [
'id' => $id, 'lang' => $lang, 'fetch_child' => $isFetchChild ? 'true' : 'false',
]);
}
/**
* 获取部门详情
*
* @param string $id
* @param string $lang
*
* @return mixed
*/
public function get($id, $lang = null)
{
return $this->client->get('department/get', compact('id', 'lang'));
}
/**
* 查询部门的所有上级父部门路径
*
* @param string $id
*
* @return mixed
*/
public function getParentsById($id)
{
return $this->client->get('department/list_parent_depts_by_dept', compact('id'));
}
/**
* 查询指定用户的所有上级父部门路径
*
* @param string $userId
*
* @return mixed
*/
public function getParentsByUserId($userId)
{
return $this->client->get('department/list_parent_depts', compact('userId'));
}
/**
* 创建部门
*
* @param array $params
*
* @return mixed
*/
public function create(array $params)
{
return $this->client->postJson('department/create', $params);
}
/**
* 更新部门
*
* @param string $id
* @param array $params
*
* @return mixed
*/
public function update($id, array $params)
{
return $this->client->postJson('department/update', compact('id') + $params);
}
/**
* 删除部门
*
* @param string $id
*
* @return mixed
*/
public function delete($id)
{
return $this->client->get('department/delete', compact('id'));
}
}
<?php
/*
* This file is part of the mingyoung/dingtalk.
*
* (c) 张铭阳 <mingyoungcheung@gmail.com>
*
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/
namespace EasyDingTalk\Department;
use Pimple\Container;
use Pimple\ServiceProviderInterface;
class ServiceProvider implements ServiceProviderInterface
{
/**
* Registers services on the given container.
* This method should only be used to configure services and parameters.
* It should not get services.
*
* @param \Pimple\Container $pimple A container instance
*/
public function register(Container $pimple)
{
$pimple['department'] = function ($app) {
return new Client($app);
};
}
}
<?php
/*
* This file is part of the mingyoung/dingtalk.
*
* (c) 张铭阳 <mingyoungcheung@gmail.com>
*
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/
namespace EasyDingTalk\H5app;
use EasyDingTalk\Kernel\BaseClient;
use EasyDingTalk\Kernel\Concerns\InteractsWithCache;
use EasyDingTalk\Kernel\Exceptions\InvalidCredentialsException;
class Client extends BaseClient
{
use InteractsWithCache;
/**
* 获取 jsapi_ticket
*
* @return mixed
*/
public function get()
{
if ($value = $this->getCache()->get($this->cacheFor())) {
return $value;
}
$value = $this->client->get('get_jsapi_ticket');
if (0 !== $value['errcode']) {
throw new InvalidCredentialsException(json_encode($value));
}
$this->getCache()->set($this->cacheFor(), $value, $value['expires_in']);
return $value;
}
/**
* 获取 ticket
*
* @return string
*/
public function getTicket()
{
return $this->get()['ticket'];
}
/**
* 获取签名相关信息
*
* @param string $url
*
* @return mixed
*/
public function getSignature($url)
{
$nonceStr = $this->getNonceStr();
$timeStamp = time();
$plain = 'jsapi_ticket=' . $this->getTicket() . '&noncestr=' . $nonceStr . '&timestamp=' . $timeStamp . '&url=' . $url;
$signature = sha1($plain);
return [
'agentId' => $this->app['config']->get('agent_id'),
'corpId' => $this->app['config']->get('corp_id'),
'timeStamp' => $timeStamp,
'nonceStr' => $nonceStr,
'signature' => $signature,
'url' => $url
];
}
/**
* 缓存 Key
*
* @return string
*/
protected function cacheFor()
{
return sprintf('jsapi_ticket.%s', $this->app['config']->get('app_key'));
}
/**
* 生产 随机字符串
*
* @return string
*/
protected function getNonceStr($length=16)
{
$strs = "QWERTYUIOPASDFGHJKLZXCVBNM1234567890qwertyuiopasdfghjklzxcvbnm";
return substr(str_shuffle($strs), mt_rand(0, strlen($strs)-11), $length);
}
}
<?php
/*
* This file is part of the mingyoung/dingtalk.
*
* (c) 张铭阳 <mingyoungcheung@gmail.com>
*
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/
namespace EasyDingTalk\H5app;
use Pimple\Container;
use Pimple\ServiceProviderInterface;
class ServiceProvider implements ServiceProviderInterface
{
/**
* Registers services on the given container.
* This method should only be used to configure services and parameters.
* It should not get services.
*
* @param \Pimple\Container $pimple A container instance
*/
public function register(Container $pimple)
{
$pimple['h5app'] = function ($app) {
return new Client($app);
};
}
}
<?php
/*
* This file is part of the mingyoung/dingtalk.
*
* (c) 张铭阳 <mingyoungcheung@gmail.com>
*
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/
namespace EasyDingTalk\Health;
use EasyDingTalk\Kernel\BaseClient;
class Client extends BaseClient
{
/**
* 获取用户钉钉运动开启状态
*
* @param string $userId
*
* @return mixed
*/
public function status($userId)
{
return $this->client->postJson('topapi/health/stepinfo/getuserstatus', ['userid' => $userId]);
}
/**
* 获取个人钉钉运动数据
*
* @param string $id
* @param string $dates
*
* @return mixed
*/
public function byUser($id, $dates)
{
return $this->client->postJson('topapi/health/stepinfo/list', ['type' => 0, 'object_id' => $id, 'stat_dates' => $dates]);
}
/**
* 获取部门钉钉运动数据
*
* @param string $id
* @param string $dates
*
* @return mixed
*/
public function byDepartment($id, $dates)
{
return $this->client->postJson('topapi/health/stepinfo/list', ['type' => 1, 'object_id' => $id, 'stat_dates' => $dates]);
}
/**
* 批量获取钉钉运动数据
*
* @param array $userIds
* @param string $date
*
* @return mixed
*/
public function byUsers(array $userIds, $date)
{
$userIds = implode(',', $userIds);
return $this->client->postJson('topapi/health/stepinfo/listbyuserid', ['userids' => $userIds, 'stat_date' => $date]);
}
}
<?php
/*
* This file is part of the mingyoung/dingtalk.
*
* (c) 张铭阳 <mingyoungcheung@gmail.com>
*
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/
namespace EasyDingTalk\Health;
use Pimple\Container;
use Pimple\ServiceProviderInterface;
class ServiceProvider implements ServiceProviderInterface
{
/**
* Registers services on the given container.
* This method should only be used to configure services and parameters.
* It should not get services.
*
* @param \Pimple\Container $pimple A container instance
*/
public function register(Container $pimple)
{
$pimple['health'] = function ($app) {
return new Client($app);
};
}
}
<?php
/*
* This file is part of the mingyoung/dingtalk.
*
* (c) 张铭阳 <mingyoungcheung@gmail.com>
*
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/
namespace EasyDingTalk\Kernel;
use EasyDingTalk\Kernel\Exceptions\InvalidCredentialsException;
use EasyDingTalk\Kernel\Http\Client;
use function EasyDingTalk\tap;
use Overtrue\Http\Traits\ResponseCastable;
class AccessToken
{
use Concerns\InteractsWithCache, ResponseCastable;
/**
* @var \EasyDingTalk\Application
*/
protected $app;
/**
* AccessToken constructor.
*
* @param \EasyDingTalk\Application
*/
public function __construct($app)
{
$this->app = $app;
}
/**
* 获取钉钉 AccessToken
*
* @return array
*
* @throws \Psr\SimpleCache\InvalidArgumentException
*/
public function get()
{
if ($value = $this->getCache()->get($this->cacheFor())) {
return $value;
}
return $this->refresh();
}
/**
* 获取 AccessToken
*
* @return string
*
* @throws \Psr\SimpleCache\InvalidArgumentException
*/
public function getToken()
{
return $this->get()['access_token'];
}
/**
* 刷新钉钉 AccessToken
*
* @return array
*/
public function refresh()
{
$response = (new Client($this->app))->requestRaw('gettoken', 'GET', ['query' => [
'appkey' => $this->app['config']->get('app_key'),
'appsecret' => $this->app['config']->get('app_secret'),
]]);
return tap($this->castResponseToType($response, 'array'), function ($value) {
if (0 !== $value['errcode']) {
throw new InvalidCredentialsException(json_encode($value));
}
$this->getCache()->set($this->cacheFor(), $value, $value['expires_in']);
});
}
/**
* 缓存 Key
*
* @return string
*/
protected function cacheFor()
{
return sprintf('access_token.%s', $this->app['config']->get('app_key'));
}
}
<?php
/*
* This file is part of the mingyoung/dingtalk.
*
* (c) 张铭阳 <mingyoungcheung@gmail.com>
*
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/
namespace EasyDingTalk\Kernel;
class BaseClient
{
/**
* @var \EasyDingTalk\Application
*/
protected $app;
/**
* @var \EasyDingTalk\Kernel\Http\Client
*/
protected $client;
/**
* Client constructor.
*
* @param \EasyDingTalk\Application $app
*/
public function __construct($app)
{
$this->app = $app;
$this->client = $this->app['client']->withAccessTokenMiddleware()->withRetryMiddleware();
}
}
<?php
/*
* This file is part of the mingyoung/dingtalk.
*
* (c) 张铭阳 <mingyoungcheung@gmail.com>
*
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/
namespace EasyDingTalk\Kernel\Concerns;
use Psr\SimpleCache\CacheInterface;
use Symfony\Component\Cache\Adapter\FilesystemAdapter;
use Symfony\Component\Cache\Psr16Cache;
use Symfony\Component\Cache\Simple\FilesystemCache;
trait InteractsWithCache
{
/**
* @var \Psr\SimpleCache\CacheInterface
*/
protected $cache;
/**
* @return \Psr\SimpleCache\CacheInterface
*/
public function getCache()
{
if ($this->cache) {
return $this->cache;
}
if (property_exists($this, 'app') && $this->app->offsetExists('cache') && ($this->app['cache'] instanceof CacheInterface)) {
return $this->cache = $this->app['cache'];
}
return $this->cache = $this->createDefaultCache();
}
/**
* @return \Psr\SimpleCache\CacheInterface
*/
protected function createDefaultCache()
{
if (class_exists(Psr16Cache::class)) {
return new Psr16Cache(new FilesystemAdapter('easydingtalk'));
}
return new FilesystemCache('easydingtalk');
}
}
<?php
/*
* This file is part of the mingyoung/dingtalk.
*
* (c) 张铭阳 <mingyoungcheung@gmail.com>
*
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/
namespace EasyDingTalk\Kernel\Encryption;
use function EasyDingTalk\str_random;
class Encryptor
{
/**
* @var string
*/
protected $key;
/**
* @var string
*/
protected $token;
/**
* @var string
*/
protected $aesKey;
/**
* @var int
*/
protected $blockSize = 32;
/**
* Encryptor Constructor.
*
* @param string $key
* @param string $token
* @param string $aesKey
*/
public function __construct($key, $token, $aesKey)
{
$this->key = $key;
$this->token = $token;
$this->aesKey = base64_decode($aesKey.'=', true);
}
/**
* Encrypt the data.
*
* @param string $data
* @param string $nonce
* @param int $timestamp
*
* @return string
*/
public function encrypt($data, $nonce = null, $timestamp = null)
{
$string = str_random().pack('N', strlen($data)).$data.$this->key;
$result = base64_encode(
openssl_encrypt($this->pkcs7Pad($string), 'AES-256-CBC', $this->aesKey, OPENSSL_NO_PADDING, substr($this->aesKey, 0, 16))
);
!is_null($nonce) || $nonce = uniqid();
!is_null($timestamp) || $timestamp = time();
return json_encode([
'msg_signature' => $this->signature($this->token, $nonce, $timestamp, $result),
'timeStamp' => $timestamp,
'nonce' => $nonce,
'encrypt' => $result,
]);
}
/**
* Decrypt the data.
*
* @param string $data
* @param string $signature
* @param string $nonce
* @param int $timestamp
*
* @return string
*/
public function decrypt($data, $signature, $nonce, $timestamp)
{
if ($signature !== $this->signature($this->token, $nonce, $timestamp, $data)) {
throw new \RuntimeException('Invalid Signature.');
}
$decrypted = openssl_decrypt(
base64_decode($data, true), 'AES-256-CBC', $this->aesKey, OPENSSL_NO_PADDING, substr($this->aesKey, 0, 16)
);
$result = $this->pkcs7Unpad($decrypted);
$data = substr($result, 16, strlen($result));
$contentLen = unpack('N', substr($data, 0, 4))[1];
if (substr($data, $contentLen + 4) !== $this->key) {
throw new \RuntimeException('Invalid CorpId.');
}
return substr($data, 4, $contentLen);
}
/**
* Get SHA1.
*
* @return string
*/
public function signature()
{
$array = func_get_args();
sort($array, SORT_STRING);
return sha1(implode($array));
}
/**
* PKCS#7 pad.
*
* @param string $text
*
* @return string
*/
public function pkcs7Pad(string $text)
{
$padding = $this->blockSize - (strlen($text) % $this->blockSize);
$pattern = chr($padding);
return $text.str_repeat($pattern, $padding);
}
/**
* PKCS#7 unpad.
*
* @param string $text
*
* @return string
*/
public function pkcs7Unpad(string $text)
{
$pad = ord(substr($text, -1));
if ($pad < 1 || $pad > $this->blockSize) {
$pad = 0;
}
return substr($text, 0, (strlen($text) - $pad));
}
}
<?php
/*
* This file is part of the mingyoung/dingtalk.
*
* (c) 张铭阳 <mingyoungcheung@gmail.com>
*
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/
namespace EasyDingTalk\Kernel\Exceptions;
use Exception as BaseException;
class Exception extends BaseException
{
//
}
<?php
/*
* This file is part of the mingyoung/dingtalk.
*
* (c) 张铭阳 <mingyoungcheung@gmail.com>
*
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/
namespace EasyDingTalk\Kernel\Exceptions;
class InvalidArgumentException extends Exception
{
//
}
<?php
/*
* This file is part of the mingyoung/dingtalk.
*
* (c) 张铭阳 <mingyoungcheung@gmail.com>
*
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/
namespace EasyDingTalk\Kernel\Exceptions;
class InvalidCredentialsException extends Exception
{
//
}
<?php
/*
* This file is part of the mingyoung/dingtalk.
*
* (c) 张铭阳 <mingyoungcheung@gmail.com>
*
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/
namespace EasyDingTalk\Kernel\Exceptions;
class RuntimeException extends Exception
{
//
}
<?php
/*
* This file is part of the mingyoung/dingtalk.
*
* (c) 张铭阳 <mingyoungcheung@gmail.com>
*
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/
namespace EasyDingTalk\Kernel\Http;
use GuzzleHttp\Middleware;
use Overtrue\Http\Client as BaseClient;
use Psr\Http\Message\RequestInterface;
use Psr\Http\Message\ResponseInterface;
class Client extends BaseClient
{
/**
* @var \EasyDingTalk\Application
*/
protected $app;
/**
* @var array
*/
protected static $httpConfig = [
'base_uri' => 'https://oapi.dingtalk.com',
];
/**
* @param \EasyDingTalk\Application $app
*/
public function __construct($app)
{
$this->app = $app;
parent::__construct(array_merge(static::$httpConfig, $this->app['config']->get('http', [])));
}
/**
* @param array $config
*/
public function setHttpConfig(array $config)
{
static::$httpConfig = array_merge(static::$httpConfig, $config);
}
/**
* @return $this
*/
public function withAccessTokenMiddleware()
{
if (isset($this->getMiddlewares()['access_token'])) {
return $this;
}
$middleware = function (callable $handler) {
return function (RequestInterface $request, array $options) use ($handler) {
if ($this->app['access_token']) {
parse_str($request->getUri()->getQuery(), $query);
$request = $request->withUri(
$request->getUri()->withQuery(http_build_query(['access_token' => $this->app['access_token']->getToken()] + $query))
);
}
return $handler($request, $options);
};
};
$this->pushMiddleware($middleware, 'access_token');
return $this;
}
/**
* @return $this
*/
public function withRetryMiddleware()
{
if (isset($this->getMiddlewares()['retry'])) {
return $this;
}
$middleware = Middleware::retry(function ($retries, RequestInterface $request, ResponseInterface $response = null) {
if (is_null($response) || $retries < 1) {
return false;
}
if (in_array(json_decode($response->getBody(), true)['errcode'] ?? null, [40001])) {
$this->app['access_token']->refresh();
return true;
}
});
$this->pushMiddleware($middleware, 'retry');
return $this;
}
}
<?php
/*
* This file is part of the mingyoung/dingtalk.
*
* (c) 张铭阳 <mingyoungcheung@gmail.com>
*
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/
namespace EasyDingTalk\Kernel\Providers;
use EasyDingTalk\Kernel\AccessToken;
use Pimple\Container;
use Pimple\ServiceProviderInterface;
class AccessTokenServiceProvider implements ServiceProviderInterface
{
/**
* Registers services on the given container.
* This method should only be used to configure services and parameters.
* It should not get services.
*
* @param \Pimple\Container $pimple A container instance
*/
public function register(Container $pimple)
{
isset($pimple['access_token']) || $pimple['access_token'] = function ($app) {
return new AccessToken($app);
};
}
}
<?php
/*
* This file is part of the mingyoung/dingtalk.
*
* (c) 张铭阳 <mingyoungcheung@gmail.com>
*
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/
namespace EasyDingTalk\Kernel\Providers;
use EasyDingTalk\Kernel\Http\Client;
use Pimple\Container;
use Pimple\ServiceProviderInterface;
class ClientServiceProvider implements ServiceProviderInterface
{
/**
* Registers services on the given container.
* This method should only be used to configure services and parameters.
* It should not get services.
*
* @param \Pimple\Container $pimple A container instance
*/
public function register(Container $pimple)
{
isset($pimple['client']) || $pimple['client'] = function ($app) {
return new Client($app);
};
}
}
<?php
/*
* This file is part of the mingyoung/dingtalk.
*
* (c) 张铭阳 <mingyoungcheung@gmail.com>
*
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/
namespace EasyDingTalk\Kernel\Providers;
use EasyDingTalk\Kernel\Encryption\Encryptor;
use Pimple\Container;
use Pimple\ServiceProviderInterface;
class EncryptionServiceProvider implements ServiceProviderInterface
{
/**
* Registers services on the given container.
* This method should only be used to configure services and parameters.
* It should not get services.
*
* @param \Pimple\Container $pimple A container instance
*/
public function register(Container $pimple)
{
$pimple['encryptor'] = function ($app) {
return new Encryptor(
$app['config']->get('corp_id'),
$app['config']->get('token'),
$app['config']->get('aes_key')
);
};
}
}
<?php
/*
* This file is part of the mingyoung/dingtalk.
*
* (c) 张铭阳 <mingyoungcheung@gmail.com>
*
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/
namespace EasyDingTalk\Kernel\Providers;
use Monolog\Logger;
use Pimple\Container;
use Pimple\ServiceProviderInterface;
class LoggerServiceProvider implements ServiceProviderInterface
{
/**
* Registers services on the given container.
* This method should only be used to configure services and parameters.
* It should not get services.
*
* @param \Pimple\Container $pimple A container instance
*/
public function register(Container $pimple)
{
isset($pimple['logger']) || $pimple['logger'] = function ($app) {
return new Logger('EasyDingTalk');
};
}
}
<?php
/*
* This file is part of the mingyoung/dingtalk.
*
* (c) 张铭阳 <mingyoungcheung@gmail.com>
*
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/
namespace EasyDingTalk\Kernel\Providers;
use Pimple\Container;
use Pimple\ServiceProviderInterface;
use Symfony\Component\HttpFoundation\Request;
class RequestServiceProvider implements ServiceProviderInterface
{
/**
* Registers services on the given container.
* This method should only be used to configure services and parameters.
* It should not get services.
*
* @param \Pimple\Container $pimple A container instance
*/
public function register(Container $pimple)
{
$pimple['request'] = function ($app) {
return Request::createFromGlobals();
};
}
}
<?php
/*
* This file is part of the mingyoung/dingtalk.
*
* (c) 张铭阳 <mingyoungcheung@gmail.com>
*
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/
namespace EasyDingTalk\Kernel\Providers;
use EasyDingTalk\Kernel\Server;
use Pimple\Container;
use Pimple\ServiceProviderInterface;
class ServerServiceProvider implements ServiceProviderInterface
{
/**
* Registers services on the given container.
* This method should only be used to configure services and parameters.
* It should not get services.
*
* @param \Pimple\Container $pimple A container instance
*/
public function register(Container $pimple)
{
$pimple['server'] = function ($app) {
return new Server($app);
};
}
}
<?php
/*
* This file is part of the mingyoung/dingtalk.
*
* (c) 张铭阳 <mingyoungcheung@gmail.com>
*
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/
namespace EasyDingTalk\Kernel;
use EasyDingTalk\Kernel\Exceptions\InvalidArgumentException;
use EasyDingTalk\Kernel\Exceptions\RuntimeException;
use function EasyDingTalk\tap;
use Symfony\Component\HttpFoundation\Response;
class Server
{
/**
* @var \EasyDingTalk\Application
*/
protected $app;
/**
* @var array
*/
protected $handlers = [];
/**
* @param \EasyDingTalk\Application $app
*/
public function __construct($app)
{
$this->app = $app;
}
/**
* Handle the request.
*
* @return \Symfony\Component\HttpFoundation\Response
*/
public function serve()
{
foreach ($this->handlers as $handler) {
$handler->__invoke($this->getPayload());
}
$this->app['logger']->debug('Request received: ', [
'method' => $this->app['request']->getMethod(),
'uri' => $this->app['request']->getUri(),
'content' => $this->app['request']->getContent(),
]);
return tap(new Response(
$this->app['encryptor']->encrypt('success'), 200, ['Content-Type' => 'application/json']
), function ($response) {
$this->app['logger']->debug('Response created:', ['content' => $response->getContent()]);
});
}
/**
* Push handler.
*
* @param \Closure|string|object $handler
*
* @return void
*
* @throws \EasyDingTalk\Kernel\Exceptions\InvalidArgumentException
*/
public function push($handler)
{
if (is_string($handler)) {
$handler = function ($payload) use ($handler) {
return (new $handler($this->app))->__invoke($payload);
};
}
if (!is_callable($handler)) {
throw new InvalidArgumentException('Invalid handler');
}
array_push($this->handlers, $handler);
}
/**
* Get request payload.
*
* @return array
*/
public function getPayload()
{
$payload = json_decode($this->app['request']->getContent(), true);
if (JSON_ERROR_NONE !== json_last_error()) {
throw new RuntimeException('No payload received');
}
$result = $this->app['encryptor']->decrypt(
$payload['encrypt'], $this->app['request']->get('signature'), $this->app['request']->get('nonce'), $this->app['request']->get('timestamp')
);
return json_decode($result, true);
}
}
<?php
/*
* This file is part of the mingyoung/dingtalk.
*
* (c) 张铭阳 <mingyoungcheung@gmail.com>
*
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/
namespace EasyDingTalk\Media;
use EasyDingTalk\Kernel\BaseClient;
class Client extends BaseClient
{
/**
* 上传图片
*
* @param mixed $media
*
* @return mixed
*/
public function uploadImage($media)
{
return $this->upload('image', $media);
}
/**
* 上传语音
*
* @param mixed $media
*
* @return mixed
*/
public function uploadVoice($media)
{
return $this->upload('voice', $media);
}
/**
* 上传普通文件
*
* @param mixed $media
*
* @return mixed
*/
public function uploadFile($media)
{
return $this->upload('file', $media);
}
/**
* 上传媒体文件
*
* @param string $type
* @param mixed $media
*
* @return mixed
*/
public function upload($type, $media)
{
return $this->client->upload('media/upload', ['media' => $media], compact('type'));
}
}
<?php
/*
* This file is part of the mingyoung/dingtalk.
*
* (c) 张铭阳 <mingyoungcheung@gmail.com>
*
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/
namespace EasyDingTalk\Media;
use Pimple\Container;
use Pimple\ServiceProviderInterface;
class ServiceProvider implements ServiceProviderInterface
{
/**
* Registers services on the given container.
* This method should only be used to configure services and parameters.
* It should not get services.
*
* @param \Pimple\Container $pimple A container instance
*/
public function register(Container $pimple)
{
$pimple['media'] = function ($app) {
return new Client($app);
};
}
}
<?php
/*
* This file is part of the mingyoung/dingtalk.
*
* (c) 张铭阳 <mingyoungcheung@gmail.com>
*
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/
namespace EasyDingTalk\Messages;
class File extends Message
{
protected $type = 'file';
protected function transform($value)
{
list($mediaId) = $value;
return ['media_id' => $mediaId];
}
}
<?php
/*
* This file is part of the mingyoung/dingtalk.
*
* (c) 张铭阳 <mingyoungcheung@gmail.com>
*
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/
namespace EasyDingTalk\Messages;
class Image extends Message
{
protected $type = 'image';
protected function transform($value)
{
list($mediaId) = $value;
return ['media_id' => $mediaId];
}
}
<?php
/*
* This file is part of the mingyoung/dingtalk.
*
* (c) 张铭阳 <mingyoungcheung@gmail.com>
*
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/
namespace EasyDingTalk\Messages;
class Link extends Message
{
protected $type = 'link';
public function setPictureUrl($value)
{
return $this->setAttribute('picUrl', $value);
}
public function setTitle($value)
{
return $this->setAttribute('title', $value);
}
public function setText($value)
{
return $this->setAttribute('text', $value);
}
protected function transform($value)
{
list($url) = $value;
return ['messageUrl' => $url];
}
}
<?php
/*
* This file is part of the mingyoung/dingtalk.
*
* (c) 张铭阳 <mingyoungcheung@gmail.com>
*
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/
namespace EasyDingTalk\Messages;
class Message
{
protected $value;
protected $type;
protected $attributes = [];
public function __construct(...$value)
{
$this->value = $value;
}
public static function make()
{
return new static(...func_get_args());
}
public function type()
{
return $this->type;
}
protected function transform($value)
{
return $value;
}
public function setAttribute($key, $value)
{
$this->attributes[$key] = $value;
return $this;
}
public function toArray()
{
return [
'msgtype' => $this->type(),
$this->type() => array_merge($this->transform($this->value), $this->attributes),
];
}
public function toJson()
{
return json_encode($this->toArray());
}
}
<?php
/*
* This file is part of the mingyoung/dingtalk.
*
* (c) 张铭阳 <mingyoungcheung@gmail.com>
*
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/
namespace EasyDingTalk\Messages;
class Text extends Message
{
protected $type = 'text';
protected function transform($value)
{
list($content) = $value;
return ['content' => $content];
}
}
<?php
/*
* This file is part of the mingyoung/dingtalk.
*
* (c) 张铭阳 <mingyoungcheung@gmail.com>
*
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/
namespace EasyDingTalk\Messages;
class Voice extends Message
{
protected $type = 'voice';
protected function transform($value)
{
list($mediaId, $duration) = $value;
return ['media_id' => $mediaId, 'duration' => $duration];
}
}
<?php
/*
* This file is part of the mingyoung/dingtalk.
*
* (c) 张铭阳 <mingyoungcheung@gmail.com>
*
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/
namespace EasyDingTalk\Microapp;
use EasyDingTalk\Kernel\BaseClient;
class Client extends BaseClient
{
/**
* 获取应用列表
*
* @return mixed
*/
public function list()
{
return $this->client->postJson('microapp/list');
}
/**
* 获取员工可见的应用列表
*
* @param string $userId
*
* @return mixed
*/
public function listByUserId($userId)
{
return $this->client->get('microapp/list_by_userid', [
'userid' => $userId,
]);
}
/**
* 获取应用的可见范围
*
* @param int $agentId
*
* @return mixed
*/
public function getVisibility($agentId)
{
return $this->client->postJson('microapp/visible_scopes', compact('agentId'));
}
/**
* 设置应用的可见范围
*
* @param array $params
*
* @return mixed
*/
public function setVisibility($params)
{
return $this->client->postJson('microapp/set_visible_scopes', $params);
}
}
<?php
/*
* This file is part of the mingyoung/dingtalk.
*
* (c) 张铭阳 <mingyoungcheung@gmail.com>
*
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/
namespace EasyDingTalk\Microapp;
use Pimple\Container;
use Pimple\ServiceProviderInterface;
class ServiceProvider implements ServiceProviderInterface
{
/**
* Registers services on the given container.
* This method should only be used to configure services and parameters.
* It should not get services.
*
* @param \Pimple\Container $pimple A container instance
*/
public function register(Container $pimple)
{
$pimple['microapp'] = function ($app) {
return new Client($app);
};
}
}
<?php
/*
* This file is part of the mingyoung/dingtalk.
*
* (c) 张铭阳 <mingyoungcheung@gmail.com>
*
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/
namespace EasyDingTalk\Process;
use EasyDingTalk\Kernel\BaseClient;
class Client extends BaseClient
{
/**
* 发起审批实例
*
* @param array $params
*
* @return mixed
*/
public function create($params)
{
return $this->client->postJson('topapi/processinstance/create', $params);
}
/**
* 批量获取审批实例 ID
*
* @param array $params
*
* @return mixed
*/
public function getIds($params)
{
return $this->client->postJson('topapi/processinstance/listids', $params);
}
/**
* 获取单个审批实例
*
* @param string $id
*
* @return mixed
*/
public function get($id)
{
return $this->client->postJson('topapi/processinstance/get', ['process_instance_id' => $id]);
}
/**
* 获取用户待审批数量
*
* @param string $userId
*
* @return mixed
*/
public function count($userId)
{
return $this->client->postJson('topapi/process/gettodonum', ['userid' => $userId]);
}
/**
* 获取用户可见的审批模板
*
* @param string|null $userId
* @param int $offset
* @param int $size
*
* @return mixed
*/
public function listByUserId($userId = null, $offset = 0, $size = 100)
{
return $this->client->postJson('topapi/process/listbyuserid', ['userid' => $userId, 'offset' => $offset, 'size' => $size]);
}
}
<?php
/*
* This file is part of the mingyoung/dingtalk.
*
* (c) 张铭阳 <mingyoungcheung@gmail.com>
*
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/
namespace EasyDingTalk\Process;
use Pimple\Container;
use Pimple\ServiceProviderInterface;
class ServiceProvider implements ServiceProviderInterface
{
/**
* Registers services on the given container.
* This method should only be used to configure services and parameters.
* It should not get services.
*
* @param \Pimple\Container $pimple A container instance
*/
public function register(Container $pimple)
{
$pimple['process'] = function ($app) {
return new Client($app);
};
}
}
<?php
/*
* This file is part of the mingyoung/dingtalk.
*
* (c) 张铭阳 <mingyoungcheung@gmail.com>
*
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/
namespace EasyDingTalk\Report;
use EasyDingTalk\Kernel\BaseClient;
class Client extends BaseClient
{
/**
* 获取用户日志数据
*
* @param array $params
*
* @return mixed
*/
public function list($params)
{
return $this->client->postJson('topapi/report/list', $params);
}
/**
* 获取用户可见的日志模板
*
* @param string|null $userId
* @param int $offset
* @param int $size
*
* @return mixed
*/
public function templates($userId = null, $offset = 0, $size = 100)
{
return $this->client->postJson('topapi/report/template/listbyuserid', [
'userid' => $userId, 'offset' => $offset, 'size' => $size,
]);
}
/**
* 获取用户日志未读数
*
* @param string $userid
*
* @return mixed
*/
public function unreadCount($userid)
{
return $this->client->postJson('topapi/report/getunreadcount', compact('userid'));
}
/**
* 获取日志的已读人数、评论条数、评论人数、点赞人数。
*
* @param $report_id
*
* @return mixed
*/
public function statistics($report_id)
{
return $this->client->postJson('topapi/report/statistics', compact('report_id'));
}
/**
* 获取日志相关人员列表,包括已读人员列表、评论人员列表、点赞人员列表
*
* @param string $report_id
* @param int $type
* @param int $offset
* @param int $size
*
* @return mixed
*/
public function statisticsByType($report_id, $type, $offset = 0, $size = 100)
{
return $this->client->postJson('topapi/report/statistics/listbytype', [
'report_id' => $report_id, 'type' => $type, 'offset' => $offset, 'size' => $size
]);
}
/**
* 获取日志接收人员列表
*
* @param string $report_id
* @param int $offset
* @param int $size
*
* @return mixed
*/
public function getReceivers($report_id, $offset = 0, $size = 100)
{
return $this->client->postJson('topapi/report/receiver/list', [
'report_id' => $report_id, 'offset' => $offset, 'size' => $size
]);
}
/**
* 获取日志评论详情,包括评论人userid、评论内容、评论时间
*
* @param string $report_id
* @param int $offset
* @param int $size
*
* @return mixed
*/
public function getComments($report_id, $offset = 0, $size = 100)
{
return $this->client->postJson('topapi/report/comment/list', [
'report_id' => $report_id, 'offset' => $offset, 'size' => $size
]);
}
}
<?php
/*
* This file is part of the mingyoung/dingtalk.
*
* (c) 张铭阳 <mingyoungcheung@gmail.com>
*
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/
namespace EasyDingTalk\Report;
use Pimple\Container;
use Pimple\ServiceProviderInterface;
class ServiceProvider implements ServiceProviderInterface
{
/**
* Registers services on the given container.
* This method should only be used to configure services and parameters.
* It should not get services.
*
* @param \Pimple\Container $pimple A container instance
*/
public function register(Container $pimple)
{
$pimple['report'] = function ($app) {
return new Client($app);
};
}
}
<?php
/*
* This file is part of the mingyoung/dingtalk.
*
* (c) 张铭阳 <mingyoungcheung@gmail.com>
*
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/
namespace EasyDingTalk;
use Overtrue\Http\Traits\HasHttpRequests;
class Robot
{
use HasHttpRequests;
/**
* 机器人 AccessToken
*
* @var string
*/
protected $accessToken;
/**
* 加签 没有勾选,不用填写
*
* @var string
*/
protected $secret;
/**
* @param string $accessToken
* @param string|null $secret
*/
public function __construct($accessToken, $secret = null)
{
$this->accessToken = $accessToken;
$this->secret = $secret;
}
/**
* @param string $accessToken
* @param string|null $secret
*
* @return self
*/
public static function create($accessToken, $secret = null)
{
return new static($accessToken, $secret);
}
/**
* 发送消息
*
* @param array $message
*
* @return array
*
* @throws \GuzzleHttp\Exception\GuzzleException
*/
public function send($message)
{
$url = 'https://oapi.dingtalk.com/robot/send?access_token='.$this->accessToken;
if ($this->secret) {
$timestamp = time().'000';
$url .= sprintf(
'&sign=%s&timestamp=%s',
urlencode(base64_encode(hash_hmac('sha256', $timestamp."\n".$this->secret, $this->secret, true))), $timestamp
);
}
$response = $this->getHttpClient()->request(
'POST', $url, ['json' => $message]
);
return $this->castResponseToType($response);
}
}
<?php
/*
* This file is part of the mingyoung/dingtalk.
*
* (c) 张铭阳 <mingyoungcheung@gmail.com>
*
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/
namespace EasyDingTalk\Role;
use EasyDingTalk\Kernel\BaseClient;
class Client extends BaseClient
{
/**
* 获取角色列表
*
* @param int $offset
* @param int $size
*
* @return mixed
*/
public function list($offset = null, $size = null)
{
return $this->client->postJson('topapi/role/list', compact('offset', 'size'));
}
/**
* 获取角色下的员工列表
*
* @param int $roleId
* @param int $offset
* @param int $size
*
* @return mixed
*/
public function getUsers($roleId, $offset = null, $size = null)
{
return $this->client->postJson('topapi/role/simplelist', compact('offset', 'size') + ['role_id' => $roleId]);
}
/**
* 获取角色组
*
* @param int $groupId
*
* @return mixed
*/
public function getGroups($groupId)
{
return $this->client->postJson('topapi/role/getrolegroup', ['group_id' => $groupId]);
}
/**
* 获取角色详情
*
* @param int $roleId
*
* @return mixed
*/
public function get($roleId)
{
return $this->client->postJson('topapi/role/getrole', compact('roleId'));
}
/**
* 创建角色
*
* @param int $groupId
* @param string $roleName
*
* @return mixed
*/
public function create($groupId, $roleName)
{
return $this->client->postJson('role/add_role', compact('groupId', 'roleName'));
}
/**
* 更新角色
*
* @param int $roleId
* @param string $roleName
*
* @return mixed
*/
public function update($roleId, $roleName)
{
return $this->client->postJson('role/update_role', compact('roleId', 'roleName'));
}
/**
* 删除角色
*
* @param int $roleId
*
* @return mixed
*/
public function delete($roleId)
{
return $this->client->postJson('topapi/role/deleterole', ['role_id' => $roleId]);
}
/**
* 创建角色组
*
* @param string $name
*
* @return mixed
*/
public function createGroup($name)
{
return $this->client->postJson('role/add_role_group', compact('name'));
}
}
<?php
/*
* This file is part of the mingyoung/dingtalk.
*
* (c) 张铭阳 <mingyoungcheung@gmail.com>
*
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/
namespace EasyDingTalk\Role;
use Pimple\Container;
use Pimple\ServiceProviderInterface;
class ServiceProvider implements ServiceProviderInterface
{
/**
* Registers services on the given container.
* This method should only be used to configure services and parameters.
* It should not get services.
*
* @param \Pimple\Container $pimple A container instance
*/
public function register(Container $pimple)
{
$pimple['role'] = function ($app) {
return new Client($app);
};
}
}
<?php
/*
* This file is part of the mingyoung/dingtalk.
*
* (c) 张铭阳 <mingyoungcheung@gmail.com>
*
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/
namespace EasyDingTalk\Schedule;
use EasyDingTalk\Kernel\BaseClient;
class Client extends BaseClient
{
/**
* 发起待办
*
* @param array $params
*
* @return mixed
*/
public function add($params)
{
return $this->client->postJson('topapi/workrecord/add', $params);
}
/**
* 更新待办
*
* @param string $userId
* @param string $recordId
*
* @return mixed
*/
public function update($userId, $recordId)
{
return $this->client->postJson('topapi/workrecord/update', ['userid' => $userId, 'record_id' => $recordId]);
}
/**
* 获取用户待办事项
*
* @param string $userId
* @param bool $completed
* @param int $offset
* @param int $limit
*
* @return mixed
*/
public function list($userId, $completed, $offset, $limit)
{
return $this->client->postJson('topapi/workrecord/getbyuserid', [
'userid' => $userId,
'status' => (int) $completed,
'offset' => $offset,
'limit' => $limit,
]);
}
}
<?php
/*
* This file is part of the mingyoung/dingtalk.
*
* (c) 张铭阳 <mingyoungcheung@gmail.com>
*
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/
namespace EasyDingTalk\Schedule;
use Pimple\Container;
use Pimple\ServiceProviderInterface;
class ServiceProvider implements ServiceProviderInterface
{
/**
* Registers services on the given container.
* This method should only be used to configure services and parameters.
* It should not get services.
*
* @param \Pimple\Container $pimple A container instance
*/
public function register(Container $pimple)
{
$pimple['schedule'] = function ($app) {
return new Client($app);
};
}
}
<?php
/*
* This file is part of the mingyoung/dingtalk.
*
* (c) 张铭阳 <mingyoungcheung@gmail.com>
*
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/
namespace EasyDingTalk\User;
use EasyDingTalk\Kernel\BaseClient;
class Client extends BaseClient
{
/**
* 获取用户详情
*
* @param string $userid
* @param string|null $lang
*
* @return mixed
*/
public function get($userid, $lang = null)
{
return $this->client->get('user/get', compact('userid', 'lang'));
}
/**
* 获取部门用户 Userid 列表
*
* @param int $departmentId
*
* @return mixed
*/
public function getUserIds($departmentId)
{
return $this->client->get('user/getDeptMember', ['deptId' => $departmentId]);
}
/**
* 获取部门用户
*
* @param int $departmentId
* @param int $offset
* @param int $size
* @param string $order
* @param string $lang
*
* @return mixed
*/
public function getUsers($departmentId, $offset, $size, $order = null, $lang = null)
{
return $this->client->get('user/simplelist', [
'department_id' => $departmentId, 'offset' => $offset, 'size' => $size, 'order' => $order, 'lang' => $lang,
]);
}
/**
* 获取部门用户详情
*
* @param int $departmentId
* @param int $offset
* @param int $size
* @param string $order
* @param string $lang
*
* @return mixed
*/
public function getDetailedUsers($departmentId, $offset, $size, $order = null, $lang = null)
{
return $this->client->get('user/listbypage', [
'department_id' => $departmentId, 'offset' => $offset, 'size' => $size, 'order' => $order, 'lang' => $lang,
]);
}
/**
* 获取管理员列表
*
* @return mixed
*/
public function administrators()
{
return $this->client->get('user/get_admin');
}
/**
* 获取管理员通讯录权限范围
*
* @param string $userid
*
* @return mixed
*/
public function administratorScope($userid)
{
return $this->client->get('topapi/user/get_admin_scope', compact('userid'));
}
/**
* 根据 Unionid 获取 Userid
*
* @param string $unionid
*
* @return mixed
*/
public function getUseridByUnionid($unionid)
{
return $this->client->get('user/getUseridByUnionid', compact('unionid'));
}
/**
* 创建用户
*
* @param array $params
*
* @return mixed
*/
public function create(array $params)
{
return $this->client->postJson('user/create', $params);
}
/**
* 更新用户
*
* @param string $userid
* @param array $params
*
* @return mixed
*/
public function update($userid, array $params)
{
return $this->client->postJson('user/update', compact('userid') + $params);
}
/**
* 删除用户
*
* @param $userid
*
* @return mixed
*/
public function delete($userid)
{
return $this->client->get('user/delete', compact('userid'));
}
/**
* 企业内部应用免登获取用户 Userid
*
* @param string $code
*
* @return mixed
*/
public function getUserByCode($code)
{
return $this->client->get('user/getuserinfo', compact('code'));
}
/**
* 批量增加员工角色
*
* @param array|string $userIds
* @param array|string $roleIds
*
* @return mixed
*/
public function addRoles($userIds, $roleIds)
{
$userIds = is_array($userIds) ? implode(',', $userIds) : $userIds;
$roleIds = is_array($roleIds) ? implode(',', $roleIds) : $roleIds;
return $this->client->postJson('topapi/role/addrolesforemps', compact('userIds', 'roleIds'));
}
/**
* 批量删除员工角色
*
* @param array|string $userIds
* @param array|string $roleIds
*
* @return mixed
*/
public function removeRoles($userIds, $roleIds)
{
$userIds = is_array($userIds) ? implode(',', $userIds) : $userIds;
$roleIds = is_array($roleIds) ? implode(',', $roleIds) : $roleIds;
return $this->client->postJson('topapi/role/removerolesforemps', compact('userIds', 'roleIds'));
}
/**
* 获取企业员工人数
*
* @param int $onlyActive
*
* @return mixed
*/
public function getCount($onlyActive = 0)
{
return $this->client->get('user/get_org_user_count', compact('onlyActive'));
}
/**
* 获取企业已激活的员工人数
*
* @return mixed
*/
public function getActivatedCount()
{
return $this->getCount(1);
}
/**
* 根据员工手机号获取 Userid
*
* @param string $mobile
*
* @return mixed
*/
public function getUserIdByPhone($mobile = '')
{
return $this->client->get('user/get_by_mobile', compact('mobile'));
}
/**
* 未登录钉钉的员工列表
*
* @param string $query_date
* @param int $offset
* @param int $size
*
* @return mixed
*/
public function getInactiveUsers($query_date, $offset, $size)
{
return $this->client->postJson('topapi/inactive/user/get', [
'query_date' => $query_date, 'offset' => $offset, 'size' => $size
]);
}
}
<?php
/*
* This file is part of the mingyoung/dingtalk.
*
* (c) 张铭阳 <mingyoungcheung@gmail.com>
*
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/
namespace EasyDingTalk\User;
use Pimple\Container;
use Pimple\ServiceProviderInterface;
class ServiceProvider implements ServiceProviderInterface
{
/**
* Registers services on the given container.
* This method should only be used to configure services and parameters.
* It should not get services.
*
* @param \Pimple\Container $pimple A container instance
*/
public function register(Container $pimple)
{
$pimple['user'] = function ($app) {
return new Client($app);
};
}
}
<?php
/*
* This file is part of the mingyoung/dingtalk.
*
* (c) 张铭阳 <mingyoungcheung@gmail.com>
*
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/
namespace EasyDingTalk;
/**
* @param mixed $value
* @param callable $callback
*
* @return mixed
*/
function tap($value, $callback)
{
$callback($value);
return $value;
}
/**
* Generate a more truly "random" alpha-numeric string.
*
* @param int $length
*
* @return string
*/
function str_random($length = 16)
{
$string = '';
while (($len = strlen($string)) < $length) {
$size = $length - $len;
$bytes = random_bytes($size);
$string .= substr(str_replace(['/', '+', '='], '', base64_encode($bytes)), 0, $size);
}
return $string;
}
<?php
/*
* This file is part of the mingyoung/dingtalk.
*
* (c) 张铭阳 <mingyoungcheung@gmail.com>
*
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/
namespace EasyDingTalk\Tests;
use EasyDingTalk\Application;
class ApplicationTest extends TestCase
{
/** @test */
public function services()
{
$app = new Application();
$services = [
'logger' => \Monolog\Logger::class,
'chat' => \EasyDingTalk\Chat\Client::class,
'user' => \EasyDingTalk\User\Client::class,
'role' => \EasyDingTalk\Role\Client::class,
'media' => \EasyDingTalk\Media\Client::class,
'sso' => \EasyDingTalk\Auth\SsoClient::class,
'server' => \EasyDingTalk\Kernel\Server::class,
'report' => \EasyDingTalk\Report\Client::class,
'health' => \EasyDingTalk\Health\Client::class,
'checkin' => \EasyDingTalk\Checkin\Client::class,
'contact' => \EasyDingTalk\Contact\Client::class,
'oauth' => \EasyDingTalk\Auth\OAuthClient::class,
'process' => \EasyDingTalk\Process\Client::class,
'callback' => \EasyDingTalk\Callback\Client::class,
'calendar' => \EasyDingTalk\Calendar\Client::class,
'schedule' => \EasyDingTalk\Schedule\Client::class,
'microapp' => \EasyDingTalk\Microapp\Client::class,
'client' => \EasyDingTalk\Kernel\Http\Client::class,
'config' => \Overtrue\Http\Support\Collection::class,
'blackboard' => \EasyDingTalk\Blackboard\Client::class,
'attendance' => \EasyDingTalk\Attendance\Client::class,
'department' => \EasyDingTalk\Department\Client::class,
'access_token' => \EasyDingTalk\Kernel\AccessToken::class,
'conversation' => \EasyDingTalk\Conversation\Client::class,
'request' => \Symfony\Component\HttpFoundation\Request::class,
'encryptor' => \EasyDingTalk\Kernel\Encryption\Encryptor::class,
];
$this->assertCount(count($services), $app->keys());
foreach ($services as $name => $service) {
$this->assertInstanceof($service, $app->{$name});
$this->assertInstanceof($service, $app[$name]);
}
}
}
<?php
/*
* This file is part of the mingyoung/dingtalk.
*
* (c) 张铭阳 <mingyoungcheung@gmail.com>
*
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/
namespace EasyDingTalk\Tests\Blackboard;
use EasyDingTalk\Blackboard\Client;
use EasyDingTalk\Tests\TestCase;
class ClientTest extends TestCase
{
/** @test */
public function list()
{
$this->make(Client::class)->list('mingyoung')
->assertUri('topapi/blackboard/listtopten')->assertPostJson(['userid' => 'mingyoung']);
}
}
<?php
/*
* This file is part of the mingyoung/dingtalk.
*
* (c) 张铭阳 <mingyoungcheung@gmail.com>
*
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/
namespace EasyDingTalk\Tests\Calendar;
use EasyDingTalk\Calendar\Client;
use EasyDingTalk\Tests\TestCase;
class ClientTest extends TestCase
{
/** @test */
public function create()
{
$this->make(Client::class)->create($expected = ['foo' => 'bar'])
->assertUri('topapi/calendar/create')->assertPostJson($expected);
}
}
<?php
/*
* This file is part of the mingyoung/dingtalk.
*
* (c) 张铭阳 <mingyoungcheung@gmail.com>
*
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/
namespace EasyDingTalk\Tests\Callback;
use EasyDingTalk\Callback\Client;
use EasyDingTalk\Tests\TestCase;
class ClientTest extends TestCase
{
/** @test */
public function register()
{
$this->make(Client::class)->register($params = ['call_back_tag' => ['foo', 'bar']])
->assertPostUri('call_back/register_call_back')->assertPostJson(array_merge($params, ['token' => 'test-token', 'aes_key' => 'test-aes-key']));
}
/** @test */
public function list()
{
$this->make(Client::class)->list()
->assertGetUri('call_back/get_call_back');
}
/** @test */
public function update()
{
$this->make(Client::class)->update($params = ['call_back_tag' => ['foo', 'bar']])
->assertPostUri('call_back/update_call_back')->assertPostJson(array_merge($params, ['token' => 'test-token', 'aes_key' => 'test-aes-key']));
}
/** @test */
public function delete()
{
$this->make(Client::class)->delete()
->assertGetUri('call_back/delete_call_back');
}
/** @test */
public function failed()
{
$this->make(Client::class)->failed()
->assertGetUri('call_back/get_call_back_failed_result');
}
}
<?php
/*
* This file is part of the mingyoung/dingtalk.
*
* (c) 张铭阳 <mingyoungcheung@gmail.com>
*
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/
namespace EasyDingTalk\Tests\Chat;
use EasyDingTalk\Chat\Client;
use EasyDingTalk\Tests\TestCase;
class ClientTest extends TestCase
{
/** @test */
public function send()
{
$this->make(Client::class)->send('foobar', ['foo' => 'bar'])
->assertPostUri('chat/send')->assertPostJson([
'chatid' => 'foobar',
'msg' => ['foo' => 'bar'],
]);
}
/** @test */
public function result()
{
$this->make(Client::class)->result('message-id', 0, 100)
->assertGetUri('chat/getReadList')->assertQuery([
'messageId' => 'message-id',
'cursor' => 0,
'size' => 100,
]);
}
/** @test */
public function create()
{
$this->make(Client::class)->create($params = ['name' => 'EasyDingTalk', 'owner' => 'mingyoung', 'useridlist' => ['mingyoung', 'member']])
->assertPostUri('chat/create')->assertPostJson($params);
}
/** @test */
public function update()
{
$this->make(Client::class)->update('chat-id', $params = ['name' => 'EasyDingTalk', 'owner' => 'mingyoung', 'add_useridlist' => ['member']])
->assertPostUri('chat/update')->assertPostJson(array_merge(['chatid' => 'chat-id'], $params));
}
/** @test */
public function get()
{
$this->make(Client::class)->get('chat-id')
->assertGetUri('chat/get')->assertQuery(['chatid' => 'chat-id']);
}
}
<?php
/*
* This file is part of the mingyoung/dingtalk.
*
* (c) 张铭阳 <mingyoungcheung@gmail.com>
*
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/
namespace EasyDingTalk\Tests\Contact;
use EasyDingTalk\Contact\Client;
use EasyDingTalk\Tests\TestCase;
class ClientTest extends TestCase
{
/** @test */
public function labels()
{
$this->make(Client::class)->labels(0, 20)
->assertUri('topapi/extcontact/listlabelgroups')->assertPostJson(['offset' => 0, 'size' => 20]);
}
/** @test */
public function list()
{
$this->make(Client::class)->list(0, 20)
->assertUri('topapi/extcontact/list')->assertPostJson(['offset' => 0, 'size' => 20]);
}
/** @test */
public function get()
{
$this->make(Client::class)->get('mingyoung')
->assertUri('topapi/extcontact/get')->assertPostJson(['user_id' => 'mingyoung']);
}
/** @test */
public function create()
{
$this->make(Client::class)->create(['name' => 'MINGYOUNG'])
->assertUri('topapi/extcontact/create')->assertPostJson(['contact' => [
'name' => 'MINGYOUNG',
]]);
}
/** @test */
public function update()
{
$this->make(Client::class)->update(123, ['name' => 'MINGYOUNG'])
->assertUri('topapi/extcontact/update')->assertPostJson(['contact' => [
'user_id' => 123, 'name' => 'MINGYOUNG',
]]);
}
/** @test */
public function delete()
{
$this->make(Client::class)->delete('mingyoung')
->assertUri('topapi/extcontact/delete')->assertPostJson(['user_id' => 'mingyoung']);
}
/** @test */
public function scopes()
{
$this->make(Client::class)->scopes()
->assertUri('auth/scopes');
}
}
<?php
/*
* This file is part of the mingyoung/dingtalk.
*
* (c) 张铭阳 <mingyoungcheung@gmail.com>
*
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/
namespace EasyDingTalk\Tests\Conversation;
use EasyDingTalk\Conversation\Client;
use EasyDingTalk\Tests\TestCase;
class ClientTest extends TestCase
{
/** @test */
public function sendGeneralMessage()
{
$this->make(Client::class)->sendGeneralMessage('sender-foo', 'cid-bar', ['foo' => 'bar'])
->assertPostUri('message/send_to_conversation')
->assertPostJson([
'sender' => 'sender-foo', 'cid' => 'cid-bar',
'msg' => ['foo' => 'bar'],
]);
}
/** @test */
public function sendCorporationMessage()
{
$this->make(Client::class)->sendCorporationMessage($params = ['foo' => 'bar'])
->assertPostUri('topapi/message/corpconversation/asyncsend_v2')
->assertPostFormParams($params);
}
/** @test */
public function progress()
{
$this->make(Client::class)->corporationMessage('task-id')->progress()
->assertPostUri('topapi/message/corpconversation/getsendprogress')
->assertPostJson(['agent_id' => 'mock-agent', 'task_id' => 'task-id']);
}
/** @test */
public function result()
{
$this->make(Client::class)->corporationMessage('task-id')->result()
->assertPostUri('topapi/message/corpconversation/getsendresult')
->assertPostJson(['agent_id' => 'mock-agent', 'task_id' => 'task-id']);
}
}
<?php
/*
* This file is part of the mingyoung/dingtalk.
*
* (c) 张铭阳 <mingyoungcheung@gmail.com>
*
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/
namespace EasyDingTalk\Tests\Department;
use EasyDingTalk\Department\Client;
use EasyDingTalk\Tests\TestCase;
class ClientTest extends TestCase
{
/** @test */
public function getSubDepartmentIds()
{
$this->make(Client::class)->getSubDepartmentIds('test-id')
->assertUri('department/list_ids')->assertQuery(['id' => 'test-id']);
}
/** @test */
public function list()
{
$this->make(Client::class)->list()
->assertUri('department/list')->assertQuery(['id' => null, 'lang' => null, 'fetch_child' => 'false']);
}
/** @test */
public function get()
{
$this->make(Client::class)->get(1)
->assertUri('department/get')->assertQuery(['id' => 1, 'lang' => null]);
}
/** @test */
public function getParentsById()
{
$this->make(Client::class)->getParentsById(1)
->assertUri('department/list_parent_depts_by_dept')->assertQuery(['id' => 1]);
}
/** @test */
public function getParentsByUserId()
{
$this->make(Client::class)->getParentsByUserId('mingyoung')
->assertUri('department/list_parent_depts')->assertQuery(['userId' => 'mingyoung']);
}
/** @test */
public function create()
{
$this->make(Client::class)->create(['name' => 'EasyDingTalk'])
->assertUri('department/create')->assertPostJson(['name' => 'EasyDingTalk']);
}
/** @test */
public function update()
{
$this->make(Client::class)->update(1, ['name' => 'EasyDingTalk'])
->assertUri('department/update')->assertPostJson(['id' => 1, 'name' => 'EasyDingTalk']);
}
/** @test */
public function delete()
{
$this->make(Client::class)->delete(1)
->assertUri('department/delete')->assertQuery(['id' => 1]);
}
}
<?php
/*
* This file is part of the mingyoung/dingtalk.
*
* (c) 张铭阳 <mingyoungcheung@gmail.com>
*
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/
namespace EasyDingTalk\Tests\Health;
use EasyDingTalk\Health\Client;
use EasyDingTalk\Tests\TestCase;
class ClientTest extends TestCase
{
/** @test */
public function status()
{
$this->make(Client::class)->status('mingyoung')
->assertPostUri('topapi/health/stepinfo/getuserstatus')
->assertPostJson(['userid' => 'mingyoung']);
}
/** @test */
public function byUser()
{
$this->make(Client::class)->byUser('mingyoung', '20180101,20180102')
->assertPostUri('topapi/health/stepinfo/list')
->assertPostJson(['type' => 0, 'object_id' => 'mingyoung', 'stat_dates' => '20180101,20180102']);
}
/** @test */
public function byDepartment()
{
$this->make(Client::class)->byDepartment('mingyoung', '20180101,20180102')
->assertPostUri('topapi/health/stepinfo/list')
->assertPostJson(['type' => 1, 'object_id' => 'mingyoung', 'stat_dates' => '20180101,20180102']);
}
/** @test */
public function byUsers()
{
$this->make(Client::class)->byUsers(['mingyoung', 'cc'], '20180101')
->assertPostUri('topapi/health/stepinfo/listbyuserid')
->assertPostJson(['userids' => 'mingyoung,cc', 'stat_date' => '20180101']);
}
}
<?php
/*
* This file is part of the mingyoung/dingtalk.
*
* (c) 张铭阳 <mingyoungcheung@gmail.com>
*
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/
namespace EasyDingTalk\Tests\Kernel\Concerns;
use EasyDingTalk\Kernel\Concerns\InteractsWithCache;
use EasyDingTalk\Tests\TestCase;
use Mockery;
use Psr\SimpleCache\CacheInterface;
class InteractsWithCacheTest extends TestCase
{
/** @test */
public function getCache()
{
$cache = Mockery::mock(InteractsWithCache::class);
$this->assertInstanceof(CacheInterface::class, $cache->getCache());
}
}
<?php
/*
* This file is part of the mingyoung/dingtalk.
*
* (c) 张铭阳 <mingyoungcheung@gmail.com>
*
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/
namespace EasyDingTalk\Tests\Kernel\Encryption;
use EasyDingTalk\Kernel\Encryption\Encryptor;
use EasyDingTalk\Tests\TestCase;
class EncryptorTest extends TestCase
{
/**
* @return \EasyDingTalk\Kernel\Encryption\Encryptor
*/
public function makeEncryptor()
{
return new Encryptor('suite4xxxxxxxxxxxxxxx', '123456', '4g5j64qlyl3zvetqxz5jiocdr586fn2zvjpa8zls3ij');
}
/** @test */
public function encrypt()
{
$encryptor = $this->makeEncryptor();
$result = json_decode($encryptor->encrypt('{"EventType":"check_create_suite_url","Random":"LPIdSnlF","TestSuiteKey":"suite4xxxxxxxxxxxxxxx"}'), true);
$result = $encryptor->decrypt(
$result['encrypt'], $result['msg_signature'], $result['nonce'], $result['timeStamp']
);
$this->assertSameDecryptedData($result);
}
/** @test */
public function decrypt()
{
$encryptor = $this->makeEncryptor();
$result = $encryptor->decrypt(
'1a3NBxmCFwkCJvfoQ7WhJHB+iX3qHPsc9JbaDznE1i03peOk1LaOQoRz3+nlyGNhwmwJ3vDMG+OzrHMeiZI7gTRWVdUBmfxjZ8Ej23JVYa9VrYeJ5as7XM/ZpulX8NEQis44w53h1qAgnC3PRzM7Zc/D6Ibr0rgUathB6zRHP8PYrfgnNOS9PhSBdHlegK+AGGanfwjXuQ9+0pZcy0w9lQ==',
'5a65ceeef9aab2d149439f82dc191dd6c5cbe2c0',
'nEXhMP4r',
'1445827045067'
);
$this->assertSameDecryptedData($result);
}
protected function assertSameDecryptedData($result)
{
$this->assertSame('{"EventType":"check_create_suite_url","Random":"LPIdSnlF","TestSuiteKey":"suite4xxxxxxxxxxxxxxx"}', $result);
}
}
<?php
/*
* This file is part of the mingyoung/dingtalk.
*
* (c) 张铭阳 <mingyoungcheung@gmail.com>
*
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/
namespace EasyDingTalk\Tests\Media;
use EasyDingTalk\Media\Client;
use EasyDingTalk\Tests\TestCase;
class ClientTest extends TestCase
{
/** @test */
public function uploadImage()
{
$this->make(Client::class)->uploadImage(__DIR__.'/__fixtures__/foo.stub')
->assertPostUri('media/upload');
}
/** @test */
public function uploadVoice()
{
$this->make(Client::class)->uploadVoice(__DIR__.'/__fixtures__/foo.stub')
->assertPostUri('media/upload');
}
/** @test */
public function uploadFile()
{
$this->make(Client::class)->uploadFile(__DIR__.'/__fixtures__/foo.stub')
->assertPostUri('media/upload');
}
}
<?php
/*
* This file is part of the mingyoung/dingtalk.
*
* (c) 张铭阳 <mingyoungcheung@gmail.com>
*
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/
namespace EasyDingTalk\Tests\Messages;
use EasyDingTalk\Messages\File;
use EasyDingTalk\Tests\TestCase;
class FileTest extends TestCase
{
/** @test */
public function staticMake()
{
$message = File::make('media-id');
$expected = [
'msgtype' => 'file',
'file' => [
'media_id' => 'media-id',
],
];
$this->assertSame($expected, $message->toArray());
$this->assertSame(json_encode($expected), $message->toJson());
}
/** @test */
public function new()
{
$message = new File('media-id');
$expected = [
'msgtype' => 'file',
'file' => [
'media_id' => 'media-id',
],
];
$this->assertSame($expected, $message->toArray());
$this->assertSame(json_encode($expected), $message->toJson());
}
}
<?php
/*
* This file is part of the mingyoung/dingtalk.
*
* (c) 张铭阳 <mingyoungcheung@gmail.com>
*
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/
namespace EasyDingTalk\Tests\Messages;
use EasyDingTalk\Messages\Image;
use EasyDingTalk\Tests\TestCase;
class ImageTest extends TestCase
{
/** @test */
public function staticMake()
{
$message = Image::make('media-id');
$expected = [
'msgtype' => 'image',
'image' => [
'media_id' => 'media-id',
],
];
$this->assertSame($expected, $message->toArray());
$this->assertSame(json_encode($expected), $message->toJson());
}
/** @test */
public function new()
{
$message = new Image('media-id');
$expected = [
'msgtype' => 'image',
'image' => [
'media_id' => 'media-id',
],
];
$this->assertSame($expected, $message->toArray());
$this->assertSame(json_encode($expected), $message->toJson());
}
}
<?php
/*
* This file is part of the mingyoung/dingtalk.
*
* (c) 张铭阳 <mingyoungcheung@gmail.com>
*
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/
namespace EasyDingTalk\Tests\Messages;
use EasyDingTalk\Messages\Link;
use EasyDingTalk\Tests\TestCase;
class LinkTest extends TestCase
{
/** @test */
public function staticMake()
{
$message = Link::make('https://example.com')->setPictureUrl('@lALOACZwe2Rk')->setTitle('测试')->setText('测试');
$expected = [
'msgtype' => 'link',
'link' => [
'messageUrl' => 'https://example.com',
'picUrl' => '@lALOACZwe2Rk',
'title' => '测试',
'text' => '测试',
],
];
$this->assertSame($expected, $message->toArray());
$this->assertSame(json_encode($expected), $message->toJson());
}
/** @test */
public function new()
{
$message = (new Link('https://example.com'))->setPictureUrl('@lALOACZwe2Rk')->setTitle('测试')->setText('测试');
$expected = [
'msgtype' => 'link',
'link' => [
'messageUrl' => 'https://example.com',
'picUrl' => '@lALOACZwe2Rk',
'title' => '测试',
'text' => '测试',
],
];
$this->assertSame($expected, $message->toArray());
$this->assertSame(json_encode($expected), $message->toJson());
}
}
<?php
/*
* This file is part of the mingyoung/dingtalk.
*
* (c) 张铭阳 <mingyoungcheung@gmail.com>
*
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/
namespace EasyDingTalk\Tests\Messages;
use EasyDingTalk\Messages\Text;
use EasyDingTalk\Tests\TestCase;
class TextTest extends TestCase
{
/** @test */
public function staticMake()
{
$message = Text::make('mock');
$expected = [
'msgtype' => 'text',
'text' => [
'content' => 'mock',
],
];
$this->assertSame($expected, $message->toArray());
$this->assertSame(json_encode($expected), $message->toJson());
}
/** @test */
public function new()
{
$message = new Text('mock');
$expected = [
'msgtype' => 'text',
'text' => [
'content' => 'mock',
],
];
$this->assertSame($expected, $message->toArray());
$this->assertSame(json_encode($expected), $message->toJson());
}
}
<?php
/*
* This file is part of the mingyoung/dingtalk.
*
* (c) 张铭阳 <mingyoungcheung@gmail.com>
*
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/
namespace EasyDingTalk\Tests\Messages;
use EasyDingTalk\Messages\Voice;
use EasyDingTalk\Tests\TestCase;
class VoiceTest extends TestCase
{
/** @test */
public function staticMake()
{
$message = Voice::make('media-id', 10);
$expected = [
'msgtype' => 'voice',
'voice' => [
'media_id' => 'media-id',
'duration' => 10,
],
];
$this->assertSame($expected, $message->toArray());
$this->assertSame(json_encode($expected), $message->toJson());
}
/** @test */
public function new()
{
$message = new Voice('media-id', 10);
$expected = [
'msgtype' => 'voice',
'voice' => [
'media_id' => 'media-id',
'duration' => 10,
],
];
$this->assertSame($expected, $message->toArray());
$this->assertSame(json_encode($expected), $message->toJson());
}
}
<?php
/*
* This file is part of the mingyoung/dingtalk.
*
* (c) 张铭阳 <mingyoungcheung@gmail.com>
*
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/
namespace EasyDingTalk\Tests\Microapp;
use EasyDingTalk\Microapp\Client;
use EasyDingTalk\Tests\TestCase;
class ClientTest extends TestCase
{
/** @test */
public function list()
{
$this->make(Client::class)->list()
->assertUri('microapp/list')->assertEmptyQuery();
}
/** @test */
public function listByUserId()
{
$this->make(Client::class)->listByUserId('mingyoung')
->assertUri('microapp/list_by_userid')->assertQuery(['userid' => 'mingyoung']);
}
/** @test */
public function getVisibility()
{
$this->make(Client::class)->getVisibility('123')
->assertUri('microapp/visible_scopes')->assertPostJson(['agentId' => '123']);
}
/** @test */
public function setVisibility()
{
$this->make(Client::class)->setVisibility([
'agentId' => 123456,
'isHidden' => false,
'deptVisibleScopes' => [1, 2],
'userVisibleScopes' => ['user1', 'user2'],
])->assertUri('microapp/set_visible_scopes')->assertPostJson([
'agentId' => 123456,
'isHidden' => false,
'deptVisibleScopes' => [1, 2],
'userVisibleScopes' => ['user1', 'user2'],
]);
}
}
<?php
/*
* This file is part of the mingyoung/dingtalk.
*
* (c) 张铭阳 <mingyoungcheung@gmail.com>
*
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/
namespace EasyDingTalk\Tests\Report;
use EasyDingTalk\Report\Client;
use EasyDingTalk\Tests\TestCase;
class ClientTest extends TestCase
{
/** @test */
public function list()
{
$expected = [
'start_time' => 1507564800000,
'end_time' => 1507564800000,
'userid' => 'mingyoung',
];
$this->make(Client::class)->list($expected)
->assertUri('topapi/report/list')->assertPostJson($expected);
}
/** @test */
public function templates()
{
$expected = [
'userid' => 'mingyoung',
'offset' => 100,
'size' => 50,
];
$this->make(Client::class)->templates('mingyoung', 100, 50)
->assertUri('topapi/report/template/listbyuserid')->assertPostJson($expected);
}
/** @test */
public function unreadCount()
{
$this->make(Client::class)->unreadCount('mingyoung')
->assertUri('topapi/report/getunreadcount')->assertPostJson(['userid' => 'mingyoung']);
}
/** @test */
public function statistics()
{
$this->make(Client::class)->statistics('xxxxxxx')
->assertUri('topapi/report/statistics')->assertPostJson(['report_id' => 'xxxxxxx']);
}
/** @test */
public function statisticsByType()
{
$this->make(Client::class)->unreadCount('xxxxxxx')
->assertUri('topapi/report/statistics/listbytype')->assertPostJson([
'report_id' => 'xxxxxxx', 'type' => 0, 'offset' => 0, 'size' => 100,
]);
}
/** @test */
public function getReceivers()
{
$this->make(Client::class)->getReceivers('xxxxxxx')
->assertUri('topapi/report/receiver/list')->assertPostJson([
'report_id' => 'xxxxxxx', 'offset' => 0, 'size' => 100,
]);
}
/** @test */
public function getComments()
{
$this->make(Client::class)->getComments('mingyoung')
->assertUri('topapi/report/comment/list')->assertPostJson([
'report_id' => 'xxxxxxx', 'offset' => 0, 'size' => 100,
]);
}
}
<?php
/*
* This file is part of the mingyoung/dingtalk.
*
* (c) 张铭阳 <mingyoungcheung@gmail.com>
*
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/
namespace EasyDingTalk\Tests\Role;
use EasyDingTalk\Role\Client;
use EasyDingTalk\Tests\TestCase;
class ClientTest extends TestCase
{
/** @test */
public function list()
{
$this->make(Client::class)->list()
->assertUri('topapi/role/list')->assertPostJson(['offset' => null, 'size' => null]);
}
/** @test */
public function getUsers()
{
$this->make(Client::class)->getUsers(123)
->assertUri('topapi/role/simplelist')->assertPostJson(['offset' => null, 'size' => null, 'role_id' => 123]);
}
/** @test */
public function getRoleGroups()
{
$this->make(Client::class)->getGroups(123)
->assertUri('topapi/role/getrolegroup')->assertPostJson(['group_id' => 123]);
}
/** @test */
public function get()
{
$this->make(Client::class)->get(123)
->assertUri('topapi/role/getrole')->assertPostJson(['roleId' => 123]);
}
/** @test */
public function create()
{
$this->make(Client::class)->create(123, 'Admin')
->assertUri('role/add_role')->assertPostJson(['groupId' => 123, 'roleName' => 'Admin']);
}
/** @test */
public function update()
{
$this->make(Client::class)->update(123, 'Admin')
->assertUri('role/update_role')->assertPostJson(['roleId' => 123, 'roleName' => 'Admin']);
}
/** @test */
public function delete()
{
$this->make(Client::class)->delete(123)
->assertUri('topapi/role/deleterole')->assertPostJson(['role_id' => 123]);
}
/** @test */
public function createGroup()
{
$this->make(Client::class)->createGroup('Group')
->assertUri('role/add_role_group')->assertPostJson(['name' => 'Group']);
}
}
<?php
/*
* This file is part of the mingyoung/dingtalk.
*
* (c) 张铭阳 <mingyoungcheung@gmail.com>
*
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/
namespace EasyDingTalk\Tests\Schedule;
use EasyDingTalk\Schedule\Client;
use EasyDingTalk\Tests\TestCase;
class ClientTest extends TestCase
{
/** @test */
public function add()
{
$this->make(Client::class)->add($params = [
'userid' => 'mingyoung',
'create_time' => 1496678400000,
'title' => '标题',
'url' => 'https://easydingtalk.org',
'formItemList' => [
[
'title' => '标题',
'content' => '内容',
],
],
])
->assertUri('topapi/workrecord/add')
->assertPostJson($params);
}
/** @test */
public function update()
{
$this->make(Client::class)->update('mingyoung', 'record123')
->assertUri('topapi/workrecord/update')
->assertPostJson(['userid' => 'mingyoung', 'record_id' => 'record123']);
}
/** @test */
public function completedList()
{
$this->make(Client::class)->list('mingyoung', true, 0, 50)
->assertUri('topapi/workrecord/getbyuserid')
->assertPostJson([
'userid' => 'mingyoung',
'status' => 1,
'offset' => 0,
'limit' => 50,
]);
}
/** @test */
public function incompletedList()
{
$this->make(Client::class)->list('mingyoung', false, 0, 50)
->assertUri('topapi/workrecord/getbyuserid')
->assertPostJson([
'userid' => 'mingyoung',
'status' => 0,
'offset' => 0,
'limit' => 50,
]);
}
}
<?php
/*
* This file is part of the mingyoung/dingtalk.
*
* (c) 张铭阳 <mingyoungcheung@gmail.com>
*
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/
namespace EasyDingTalk\Tests;
use EasyDingTalk\Application;
use GuzzleHttp\ClientInterface;
use Mockery;
use PHPUnit\Framework\TestCase as BaseTestCase;
class TestCase extends BaseTestCase
{
/**
* @param \EasyDingTalk\Kernel\BaseClient $client
*
* @return \EasyDingTalk\Kernel\BaseClient
*/
protected function make($client)
{
$app = $this->newApplication([
'token' => 'test-token',
'aes_key' => 'test-aes-key',
'http' => ['response_type' => 'raw'],
]);
$response = new TestResponse(200, [], '{"mock": "test"}');
$app['client']->setHttpClient(Mockery::mock(ClientInterface::class, function ($mock) use ($response) {
$mock->shouldReceive('request')->withArgs($response->setExpectedArguments())->andReturn($response);
}));
return new $client($app);
}
/**
* @param array $config
* @param array $overrides
*
* @return \EasyDingTalk\Application
*/
protected function newApplication(array $config = [], array $overrides = [])
{
return new Application(array_merge(['appkey' => 'mock-appkey', 'appsecret' => 'mock-appsecret', 'agent_id' => 'mock-agent'], $config), $overrides);
}
protected function tearDown()
{
Mockery::close();
}
}
<?php
/*
* This file is part of the mingyoung/dingtalk.
*
* (c) 张铭阳 <mingyoungcheung@gmail.com>
*
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/
namespace EasyDingTalk\Tests;
use GuzzleHttp\Psr7\Response;
use PHPUnit\Framework\Assert;
class TestResponse extends Response
{
/**
* @var string
*/
protected $method;
/**
* @var string
*/
protected $uri;
/**
* @var array
*/
protected $options;
/**
* Request arguments.
*
* @return \Closure
*/
public function setExpectedArguments()
{
return function () {
list($this->method, $this->uri, $this->options) = func_get_args();
return true;
};
}
/**
* @throws \PHPUnit\Framework\ExpectationFailedException
*
* @param string $method
*
* @return $this
*/
public function assertMethod($method)
{
Assert::assertSame($this->method, $method);
return $this;
}
/**
* @throws \PHPUnit\Framework\ExpectationFailedException
*
* @param string $uri
*
* @return $this
*/
public function assertUri($uri)
{
Assert::assertSame($this->uri, $uri);
return $this;
}
/**
* @throws \PHPUnit\Framework\ExpectationFailedException
*
* @param string $uri
*
* @return $this
*/
public function assertGetUri($uri)
{
return $this->assertMethod('GET')->assertUri($uri);
}
/**
* @throws \PHPUnit\Framework\ExpectationFailedException
*
* @param string $uri
*
* @return $this
*/
public function assertPostUri($uri)
{
return $this->assertMethod('POST')->assertUri($uri);
}
/**
* @throws \PHPUnit\Framework\ExpectationFailedException
*
* @param array $query
*
* @return $this
*/
public function assertQuery($query)
{
Assert::assertSame($this->options['query'], $query);
return $this;
}
/**
* @throws \PHPUnit\Framework\ExpectationFailedException
*
* @return $this
*/
public function assertEmptyQuery()
{
return $this->assertQuery([]);
}
/**
* @throws \PHPUnit\Framework\ExpectationFailedException
*
* @param array $json
*
* @return $this
*/
public function assertPostJson($json)
{
Assert::assertSame($this->options['json'], $json);
return $this;
}
/**
* @param array $params
*
* @return $this
*/
public function assertPostFormParams($params)
{
Assert::assertSame($this->options['form_params'], $params);
return $this;
}
}
<?php
/*
* This file is part of the mingyoung/dingtalk.
*
* (c) 张铭阳 <mingyoungcheung@gmail.com>
*
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/
namespace EasyDingTalk\Tests\User;
use EasyDingTalk\Tests\TestCase;
use EasyDingTalk\User\Client;
class ClientTest extends TestCase
{
/** @test */
public function get()
{
$this->make(Client::class)->get('mingyoung')
->assertUri('user/get')->assertQuery(['userid' => 'mingyoung', 'lang' => null]);
$this->make(Client::class)->get('mingyoung', 'zh-CN')
->assertUri('user/get')->assertQuery(['userid' => 'mingyoung', 'lang' => 'zh-CN']);
}
/** @test */
public function getUserIds()
{
$this->make(Client::class)->getUserIds('123')
->assertUri('user/getDeptMember')->assertQuery(['deptId' => '123']);
}
/** @test */
public function getUsers()
{
$this->make(Client::class)->getUsers('123', 10, 20)
->assertUri('user/simplelist')->assertQuery(['department_id' => '123', 'offset' => 10, 'size' => 20, 'order' => null, 'lang' => null]);
}
/** @test */
public function getDetailedUsers()
{
$this->make(Client::class)->getDetailedUsers('123', 10, 20)
->assertUri('user/listbypage')->assertQuery(['department_id' => '123', 'offset' => 10, 'size' => 20, 'order' => null, 'lang' => null]);
}
/** @test */
public function administrators()
{
$this->make(Client::class)->administrators()
->assertUri('user/get_admin');
}
/** @test */
public function administratorScope()
{
$this->make(Client::class)->administratorScope('mingyoung')
->assertUri('topapi/user/get_admin_scope')->assertQuery(['userid' => 'mingyoung']);
}
/** @test */
public function getUseridByUnionid()
{
$this->make(Client::class)->getUseridByUnionid('mingyoung')
->assertUri('user/getUseridByUnionid')->assertQuery(['unionid' => 'mingyoung']);
}
/** @test */
public function create()
{
$this->make(Client::class)->create(['userid' => 'mingyoung', 'name' => 'MINGYOUNG'])
->assertUri('user/create')->assertPostJson([
'userid' => 'mingyoung', 'name' => 'MINGYOUNG',
]);
}
/** @test */
public function update()
{
$this->make(Client::class)->update('mingyoung', ['name' => 'MINGYOUNG'])
->assertUri('user/update')->assertPostJson([
'userid' => 'mingyoung',
'name' => 'MINGYOUNG',
]);
}
/** @test */
public function delete()
{
$this->make(Client::class)->delete('mingyoung')
->assertUri('user/delete')->assertQuery(['userid' => 'mingyoung']);
}
/** @test */
public function getUserByCode()
{
$this->make(Client::class)->getUserByCode('code')
->assertUri('user/getuserinfo')->assertQuery(['code' => 'code']);
}
/** @test */
public function addRoles()
{
$this->make(Client::class)->addRoles('user1,user2', 'role1,role2')
->assertUri('topapi/role/addrolesforemps')->assertPostJson(['userIds' => 'user1,user2', 'roleIds' => 'role1,role2']);
$this->make(Client::class)->addRoles(['user1', 'user2'], ['role1', 'role2'])
->assertUri('topapi/role/addrolesforemps')->assertPostJson(['userIds' => 'user1,user2', 'roleIds' => 'role1,role2']);
}
/** @test */
public function removeRoles()
{
$this->make(Client::class)->removeRoles('user1,user2', 'role1,role2')
->assertUri('topapi/role/removerolesforemps')->assertPostJson(['userIds' => 'user1,user2', 'roleIds' => 'role1,role2']);
$this->make(Client::class)->removeRoles(['user1', 'user2'], ['role1', 'role2'])
->assertUri('topapi/role/removerolesforemps')->assertPostJson(['userIds' => 'user1,user2', 'roleIds' => 'role1,role2']);
}
/** @test */
public function getUserCount()
{
$this->make(Client::class)->getCount()
->assertUri('user/get_org_user_count')->assertQuery(['onlyActive' => 0]);
}
/** @test */
public function getActivatedCount()
{
$this->make(Client::class)->getActivatedCount()
->assertUri('user/get_org_user_count')->assertQuery(['onlyActive' => 1]);
}
/** @test */
public function getUserIdByPhone()
{
$this->make(Client::class)->getUserIdByPhone()
->assertUri('user/get_by_mobile')->assertQuery(['phone' => '18888888888']);
}
/** @test */
public function getInactiveUsers()
{
$this->make(Client::class)->getInactiveUsers()
->assertUri('topapi/inactive/user/get')->assertQuery(['query_date' => '20190808', 'offset' => 0, 'size' => 100]);
}
}
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