Skip to content

Commit

Permalink
Merge pull request #1 from froger-me/frogerme-menus-cli
Browse files Browse the repository at this point in the history
Frogerme menus cli
  • Loading branch information
overtrue authored Mar 31, 2018
2 parents 1970a47 + 92c97bc commit 6298cd4
Show file tree
Hide file tree
Showing 5 changed files with 344 additions and 0 deletions.
40 changes: 40 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,46 @@ $ ./vendor/bin/easywechat payment:rsa_public_key \
# Public key of mch_id:14339221228 saved as ./public-14339221228.pem
```

### List, Create, Delete Official Account menu structure.

https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421141013
https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421141014
https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421141015

```shell
$ ./vendor/bin/easywechat menus:list_menus \
--app_id=14339221228 \
--secret=36YTbDmLgyQ52noqdxgwGiYy \
--token=mytoken \
--aes_key=0xp26B0rqlKFZPWbr5lQs4SVaugBnFjE0H1xE9rfePX
--file_output=/Users/overtrue/www/demo/menus.json

# JSON menu structure of the Official Account output in /Users/overtrue/www/demo/menus.json
```

```shell
$ ./vendor/bin/easywechat menus:create_menus \
--app_id=14339221228 \
--secret=36YTbDmLgyQ52noqdxgwGiYy \
--token=mytoken \
--aes_key=0xp26B0rqlKFZPWbr5lQs4SVaugBnFjE0H1xE9rfePX
--file=/Users/overtrue/www/demo/menus.json

# Menu structure of the Official Account created/updated
```

```shell
$ ./vendor/bin/easywechat menus:delete_menus \
--app_id=14339221228 \
--secret=36YTbDmLgyQ52noqdxgwGiYy \
--token=mytoken \
--aes_key=0xp26B0rqlKFZPWbr5lQs4SVaugBnFjE0H1xE9rfePX
--save=/Users/overtrue/www/demo/menus.json

# Menu structure of the Official Account deleted
# JSON menu structure saved as /Users/overtrue/www/demo/menus.json
```

## License

MIT
6 changes: 6 additions & 0 deletions bin/easywechat
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,15 @@ if (!$loaded) {

use EasyWeChat\Console\Application;
use EasyWeChat\Console\Commands\Payment\RsaPublicKey;
use EasyWeChat\Console\Commands\Menus\ListMenus;
use EasyWeChat\Console\Commands\Menus\CreateMenus;
use EasyWeChat\Console\Commands\Menus\DeleteMenus;

$application = new Application();

$application->add(new RsaPublicKey());
$application->add(new ListMenus());
$application->add(new CreateMenus());
$application->add(new DeleteMenus());

$application->run();
129 changes: 129 additions & 0 deletions src/Commands/Menus/CreateMenus.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
<?php

namespace EasyWeChat\Console\Commands\Menus;

use EasyWeChat\Console\Commands\Command;
use EasyWeChat\Factory;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;

/**
* Class CreateMenus
*
* @author froger_me <alex@froger.me>
*/
class CreateMenus extends Command
{
protected $name = 'menus:create_menus';
protected $description = 'Create Official Account menus (all users)';
protected $help = 'This command allows you to set a Wechat Official Account\'s menus using a file containing a JSON structure.';
protected $options = [
['app_id', null, InputOption::VALUE_OPTIONAL, 'App ID of the Official Account.'],
['secret', null, InputOption::VALUE_OPTIONAL, 'The secret key of the Official Account'],
['token', null, InputOption::VALUE_OPTIONAL, 'The token of the Official Account'],
['aes_key', null, InputOption::VALUE_OPTIONAL, 'The AES key of the Official Account'],
['file', null, InputOption::VALUE_OPTIONAL, 'The file with the JSON structure of menus to create.'],
];

protected function execute(InputInterface $input, OutputInterface $output)
{
$appId = $this->option('app_id');
$secret = $this->option('secret');
$token = $this->option('token');
$aesKey = $this->option('aes_key');
$jsonPath = $this->option('file');

if (empty($appId)) {
$appId = $this->ask('appId');
}

if (empty($secret)) {
$secret = $this->ask('secret');
}

if (empty($token)) {
$token = $this->ask('token');
}

if (empty($aesKey)) {
$aesKey = $this->ask('aes_key');
}

if (empty($jsonPath)) {
$jsonPath = $this->ask('file');
}

$app = Factory::officialAccount([
'app_id' => $appId,
'secret' => $secret,
'token' => $token,
'aes_key' => $aesKey,
]);

try {
$content = file_get_contents($jsonPath);

if (false === $content) {
throw new \Exception("Cannot read file content.");
}

$menusStructure = json_decode($content, true);

if (JSON_ERROR_NONE !== json_last_error()) {
$message = '';

switch (json_last_error()) {
case JSON_ERROR_DEPTH:
$message = 'Maximum stack depth exceeded';
break;
case JSON_ERROR_STATE_MISMATCH:
$message = 'Underflow or the modes mismatch';
break;
case JSON_ERROR_CTRL_CHAR:
$message = 'Unexpected control character found';
break;
case JSON_ERROR_SYNTAX:
$message = 'Syntax error, malformed JSON';
break;
case JSON_ERROR_UTF8:
$message = 'Malformed UTF-8 characters, possibly incorrectly encoded';
break;
default:
$message = 'Unknown error';
break;
}

throw new \Exception("JSON error: " . $message);
}

if (isset($menusStructure['menu']) && isset($menusStructure['menu']['button']) && is_array($menusStructure['menu']['button'])) {
$buttons = array();

foreach ($menusStructure['menu']['button'] as $key => $buttonStructure) {
$button = array();

foreach ($buttonStructure as $buttonStructureKey => $value) {
if (!($buttonStructureKey === 'sub_button' && empty($value))) {
$button[$buttonStructureKey] = $value;
}
}
$buttons[] = $button;
}
$result = $app->menu->create($buttons);

if ($output->isDebug()) {
$this->line(print_r($buttons, true));
}

if ($output->isVerbose() || $output->isVeryVerbose() || $output->isDebug()) {
$this->line(print_r($result, true));
}
}

} catch (\Exception $e) {
$this->line('Error while attempting to create menus using ' . $jsonPath);
$this->line($e->getMessage());
}
}
}
84 changes: 84 additions & 0 deletions src/Commands/Menus/DeleteMenus.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
<?php

namespace EasyWeChat\Console\Commands\Menus;

use EasyWeChat\Console\Commands\Command;
use EasyWeChat\Factory;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;

/**
* Class DeleteMenus
*
* @author froger_me <alex@froger.me>
*/
class DeleteMenus extends Command
{
protected $name = 'menus:delete_menus';
protected $description = 'Delete all Official Account menus';
protected $help = 'This command allows you to delete all the Wechat Official Account\'s menus.';
protected $options = [
['app_id', null, InputOption::VALUE_OPTIONAL, 'App ID of the Official Account.'],
['secret', null, InputOption::VALUE_OPTIONAL, 'The secret key of the Official Account'],
['token', null, InputOption::VALUE_OPTIONAL, 'The token of the Official Account'],
['aes_key', null, InputOption::VALUE_OPTIONAL, 'The AES key of the Official Account'],
['save', null, InputOption::VALUE_OPTIONAL, 'The file where to save the JSON structure of menus before deleting (optional).'],
];

protected function execute(InputInterface $input, OutputInterface $output)
{
$appId = $this->option('app_id');
$secret = $this->option('secret');
$token = $this->option('token');
$aesKey = $this->option('aes_key');
$jsonPath = $this->option('save');

if (empty($appId)) {
$appId = $this->ask('appId');
}

if (empty($secret)) {
$secret = $this->ask('secret');
}

if (empty($token)) {
$token = $this->ask('token');
}

if (empty($aesKey)) {
$aesKey = $this->ask('aes_key');
}

$app = Factory::officialAccount([
'app_id' => $appId,
'secret' => $secret,
'token' => $token,
'aes_key' => $aesKey,
]);

$list = $app->menu->list();
$app->menu->delete();

if (!empty($jsonPath)) {
try {
if (file_exists($jsonPath) && !is_writable($jsonPath)) {
throw new \Exception("The provided path is not a writable file.");
}

$fp = fopen($jsonPath, 'w');
fwrite($fp, json_encode($list, JSON_PRETTY_PRINT));
fclose($fp);
$this->line("Menu structure saved in: " . $jsonPath);
} catch (\Exception $e) {
$this->line('Error while outputing result to ' . $jsonPath);
$this->line($e->getMessage());
$this->line('');
$this->line(json_encode($list, JSON_PRETTY_PRINT));
}
} else {
$this->line("The following menu structure was deleted:");
$this->line(json_encode($list, JSON_PRETTY_PRINT));
}
}
}
85 changes: 85 additions & 0 deletions src/Commands/Menus/ListMenus.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
<?php

namespace EasyWeChat\Console\Commands\Menus;

use EasyWeChat\Console\Commands\Command;
use EasyWeChat\Factory;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;

/**
* Class ListMenus
*
* @author froger_me <alex@froger.me>
*/
class ListMenus extends Command
{
protected $name = 'menus:list_menus';
protected $description = 'List Official Account menus (on screen or in a file)';
protected $help = 'This command allows you to list Wechat Official Account\'s menus in a JSON structure.';
protected $options = [
['app_id', null, InputOption::VALUE_OPTIONAL, 'App ID of the Official Account.'],
['secret', null, InputOption::VALUE_OPTIONAL, 'The secret key of the Official Account'],
['token', null, InputOption::VALUE_OPTIONAL, 'The token of the Official Account'],
['aes_key', null, InputOption::VALUE_OPTIONAL, 'The AES key of the Official Account'],
['file_output', null, InputOption::VALUE_OPTIONAL, 'The file where to save the JSON structure of menus (optional).'],
];

protected function execute(InputInterface $input, OutputInterface $output)
{
$appId = $this->option('app_id');
$secret = $this->option('secret');
$token = $this->option('token');
$aesKey = $this->option('aes_key');
$jsonPath = $this->option('file_output');

if (empty($appId)) {
$appId = $this->ask('appId');
}

if (empty($secret)) {
$secret = $this->ask('secret');
}

if (empty($token)) {
$token = $this->ask('token');
}

if (empty($aesKey)) {
$aesKey = $this->ask('aes_key');
}

$app = Factory::officialAccount([
'app_id' => $appId,
'secret' => $secret,
'token' => $token,
'aes_key' => $aesKey,
]);

$list = $app->menu->list();

if (isset($list['errcode']) && 46003 === $list['errcode']) {
$this->line('No menu found');
return;
}

if (!empty($jsonPath)) {
try {
if (file_exists($jsonPath) && !is_writable($jsonPath)) {
throw new \Exception('The provided path is not a writable file.');
}
$fp = fopen($jsonPath, 'w');
fwrite($fp, json_encode($list, JSON_PRETTY_PRINT));
fclose($fp);
} catch (\Exception $e) {
$this->line('Error while outputing result to ' . $jsonPath);
$this->line($e->getMessage());
$this->line('');
$this->line(json_encode($list, JSON_PRETTY_PRINT));
}
} else {
$this->line(json_encode($list, JSON_PRETTY_PRINT));
}
}
}

0 comments on commit 6298cd4

Please sign in to comment.