slack 추가

This commit is contained in:
toki 2023-02-19 12:46:55 +09:00
parent 560e0535e1
commit f1559c7b07
5 changed files with 467 additions and 0 deletions

View file

@ -0,0 +1,132 @@
import 'dart:async';
import 'dart:convert';
import 'dart:io';
import 'package:json_annotation/json_annotation.dart';
import 'package:dart_framework/utils/system_util.dart';
import 'package:http/http.dart';
// ignore: depend_on_referenced_packages, implementation_imports
import 'package:http_parser/src/media_type.dart';
part 'slack_data.g.dart';
enum SlackActionType { button, select }
enum SlackActionStyle { danger, primary }
@JsonSerializable()
class DataSlack {
String? message;
late List<SlackAttachment> attachments;
String getAttachments() {
var list = [];
for (var item in attachments) {
list.add(item.toJson());
}
return jsonEncode(list);
}
DataSlack();
factory DataSlack.fromJson(Map<String, dynamic> json) =>
_$DataSlackFromJson(json);
Map<String, dynamic> toJson() => _$DataSlackToJson(this);
}
@JsonSerializable()
class SlackAttachment {
String? fallback;
String? color;
String? author_name;
String? author_link;
String? author_icon;
String? title;
String? title_link;
String? pretext;
String? text;
String? image_url;
String? thumb_url;
String? footer;
String? footer_icon;
String? ts;
List<SlackField>? fields;
List<SlackAction>? actions;
SlackAttachment();
factory SlackAttachment.fromJson(Map<String, dynamic> json) =>
_$SlackAttachmentFromJson(json);
Map<String, dynamic> toJson() => _$SlackAttachmentToJson(this);
}
@JsonSerializable()
class SlackField {
String? title;
String? value;
SlackField();
SlackField.withParam(this.title, this.value);
factory SlackField.fromJson(Map<String, dynamic> json) =>
_$SlackFieldFromJson(json);
Map<String, dynamic> toJson() => _$SlackFieldToJson(this);
}
@JsonSerializable()
class SlackAction {
SlackActionType? type;
String? name;
String? text;
String? url;
String? value;
SlackActionStyle? style;
/*SlackField options;
SlackConfirm confirm;*/
SlackAction();
SlackAction.withParam(
this.name, this.text, this.url, this.value, this.type, this.style);
factory SlackAction.fromJson(Map<String, dynamic> json) =>
_$SlackActionFromJson(json);
Map<String, dynamic> toJson() => _$SlackActionToJson(this);
}
@JsonSerializable()
class SlackConfirm {
String? title;
String? text;
String? ok_text;
String? dismiss_text;
}
// To-do: File upload test
@JsonSerializable()
class SlackFile {
String? title;
String? initial_comment;
String? filePath;
String? fileName;
String? mimeType;
Future<MultipartRequest> setFileData(MultipartRequest form) async {
// var bytes = await readFileByte(filePath!);
if (title != null) {
form.fields['title'] = title!;
}
if (initial_comment != null) {
form.fields['initial_comment'] = initial_comment!;
}
form.fields['filetype'] =
"auto"; // - https://api.slack.com/types/file#file_types
if (fileName != null && mimeType != null) {
form.files.add(MultipartFile.fromBytes(
'file', await File.fromUri(Uri.parse(filePath!)).readAsBytes(),
contentType: MediaType(HttpHeaders.contentTypeHeader, mimeType!)));
}
var c = Completer<MultipartRequest>();
c.complete(form);
return c.future;
}
}

View file

@ -0,0 +1,128 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'slack_data.dart';
// **************************************************************************
// JsonSerializableGenerator
// **************************************************************************
DataSlack _$DataSlackFromJson(Map<String, dynamic> json) => DataSlack()
..message = json['message'] as String?
..attachments = (json['attachments'] as List<dynamic>)
.map((e) => SlackAttachment.fromJson(e as Map<String, dynamic>))
.toList();
Map<String, dynamic> _$DataSlackToJson(DataSlack instance) => <String, dynamic>{
'message': instance.message,
'attachments': instance.attachments,
};
SlackAttachment _$SlackAttachmentFromJson(Map<String, dynamic> json) =>
SlackAttachment()
..fallback = json['fallback'] as String?
..color = json['color'] as String?
..author_name = json['author_name'] as String?
..author_link = json['author_link'] as String?
..author_icon = json['author_icon'] as String?
..title = json['title'] as String?
..title_link = json['title_link'] as String?
..pretext = json['pretext'] as String?
..text = json['text'] as String?
..image_url = json['image_url'] as String?
..thumb_url = json['thumb_url'] as String?
..footer = json['footer'] as String?
..footer_icon = json['footer_icon'] as String?
..ts = json['ts'] as String?
..fields = (json['fields'] as List<dynamic>?)
?.map((e) => SlackField.fromJson(e as Map<String, dynamic>))
.toList()
..actions = (json['actions'] as List<dynamic>?)
?.map((e) => SlackAction.fromJson(e as Map<String, dynamic>))
.toList();
Map<String, dynamic> _$SlackAttachmentToJson(SlackAttachment instance) =>
<String, dynamic>{
'fallback': instance.fallback,
'color': instance.color,
'author_name': instance.author_name,
'author_link': instance.author_link,
'author_icon': instance.author_icon,
'title': instance.title,
'title_link': instance.title_link,
'pretext': instance.pretext,
'text': instance.text,
'image_url': instance.image_url,
'thumb_url': instance.thumb_url,
'footer': instance.footer,
'footer_icon': instance.footer_icon,
'ts': instance.ts,
'fields': instance.fields,
'actions': instance.actions,
};
SlackField _$SlackFieldFromJson(Map<String, dynamic> json) => SlackField()
..title = json['title'] as String?
..value = json['value'] as String?;
Map<String, dynamic> _$SlackFieldToJson(SlackField instance) =>
<String, dynamic>{
'title': instance.title,
'value': instance.value,
};
SlackAction _$SlackActionFromJson(Map<String, dynamic> json) => SlackAction()
..type = $enumDecodeNullable(_$SlackActionTypeEnumMap, json['type'])
..name = json['name'] as String?
..text = json['text'] as String?
..url = json['url'] as String?
..value = json['value'] as String?
..style = $enumDecodeNullable(_$SlackActionStyleEnumMap, json['style']);
Map<String, dynamic> _$SlackActionToJson(SlackAction instance) =>
<String, dynamic>{
'type': _$SlackActionTypeEnumMap[instance.type],
'name': instance.name,
'text': instance.text,
'url': instance.url,
'value': instance.value,
'style': _$SlackActionStyleEnumMap[instance.style],
};
const _$SlackActionTypeEnumMap = {
SlackActionType.button: 'button',
SlackActionType.select: 'select',
};
const _$SlackActionStyleEnumMap = {
SlackActionStyle.danger: 'danger',
SlackActionStyle.primary: 'primary',
};
SlackConfirm _$SlackConfirmFromJson(Map<String, dynamic> json) => SlackConfirm()
..title = json['title'] as String?
..text = json['text'] as String?
..ok_text = json['ok_text'] as String?
..dismiss_text = json['dismiss_text'] as String?;
Map<String, dynamic> _$SlackConfirmToJson(SlackConfirm instance) =>
<String, dynamic>{
'title': instance.title,
'text': instance.text,
'ok_text': instance.ok_text,
'dismiss_text': instance.dismiss_text,
};
SlackFile _$SlackFileFromJson(Map<String, dynamic> json) => SlackFile()
..title = json['title'] as String?
..initial_comment = json['initial_comment'] as String?
..filePath = json['filePath'] as String?
..fileName = json['fileName'] as String?
..mimeType = json['mimeType'] as String?;
Map<String, dynamic> _$SlackFileToJson(SlackFile instance) => <String, dynamic>{
'title': instance.title,
'initial_comment': instance.initial_comment,
'filePath': instance.filePath,
'fileName': instance.fileName,
'mimeType': instance.mimeType,
};

View file

@ -0,0 +1,188 @@
import 'dart:async';
import 'package:color/color.dart';
import 'package:http/http.dart' as http;
import 'slack_data.dart';
enum SlackBuildType { android, ios, windows, mac, web }
class SlackSender {
//Bot TOKEN
final token = "xoxb-291006091297-QT2K1PCpwyX4b5wKk3AQew2G";
//API - https://api.slack.com/methods/chat.postMessage
final urlMessagePost = "https://slack.com/api/chat.postMessage";
//API - https://api.slack.com/methods/files.upload
final urlFileUplaod = "https://slack.com/api/files.upload";
Function(String)? _completeListener;
Function(Exception)? _errorListener;
String getValidatedUser(String? targetUser) {
targetUser ??= "@channel";
if (targetUser.indexOf("@") != 0) targetUser = "@$targetUser";
return targetUser;
}
String getURL(String channel, DataSlack message, String? targetUser,
{bool includeURL = true}) {
targetUser = getValidatedUser(targetUser);
var buffer = StringBuffer();
if (includeURL) {
buffer.write(urlMessagePost);
buffer.write('?');
}
buffer.write('token=$token');
buffer.write('&channel=$channel');
var sendMessage = message.message == null
? ''
: Uri.encodeComponent(' ${message.message!}');
buffer.write('&text=$targetUser$sendMessage');
buffer
.write('&attachments=${Uri.encodeComponent(message.getAttachments())}');
buffer.write('&link_names=true');
print(buffer.toString());
return buffer.toString();
}
void onComplete(String result) {
print(result);
if (_completeListener != null) _completeListener!(result);
}
void onError(Exception exception) {
if (_errorListener != null) _errorListener!(exception);
}
void initializeListener() {
_completeListener = null;
_errorListener = null;
}
// Attachment로
Future send(String channel, SlackAttachment attachment,
{String? targetUser,
Function(String)? completeListener,
Function(Exception)? errorListener}) async {
var data = DataSlack();
data.attachments = [attachment];
return await sends(channel, data, targetUser: targetUser);
}
// Attachment로
Future sends(String channel, DataSlack message,
{String? targetUser,
Function(String)? completeListener,
Function(Exception)? errorListener}) async {
var c = Completer();
String url = getURL(channel, message, targetUser);
var response = await http.get(Uri.parse(url));
print(response.body);
if (_completeListener != null) _completeListener!(response.body);
c.complete();
return c.future;
}
String getParameters(String channel, DataSlack message,
{String? targetUser}) {
return getURL(channel, message, targetUser, includeURL: false);
}
/// ****************** File Send *******************
http.MultipartRequest getPostForm(
String url, String channel, String? targetUser) {
var form = http.MultipartRequest('POST', Uri.parse(url));
targetUser = getValidatedUser(targetUser);
form.fields['token'] = token;
form.fields['channels'] = channel;
return form;
}
void sendFile(String channel, SlackFile file,
{String? targetUser,
Function(String)? completeListener,
Function(Exception)? errorListener}) async {
_completeListener = completeListener;
_errorListener = errorListener;
var form = getPostForm(urlFileUplaod, channel, targetUser);
form = await file.setFileData(form);
//To-do: send http
}
/// ****************** Send template *******************
void sendTest() async {
DataSlack message = DataSlack();
message.attachments = [];
var attachment = SlackAttachment();
attachment.author_name = 'toki';
attachment.text = 'This is Test!!';
attachment.color = '#ff2f00';
attachment.fields = [
SlackField.withParam('Test1', 'Value1'),
SlackField.withParam('Test2', 'Value2'),
];
message.attachments.add(attachment);
attachment = SlackAttachment();
attachment.author_name = 'toki';
attachment.text = 'This is Test!!2';
attachment.color = '#0084ff';
attachment.fields = [
SlackField.withParam('Test3', 'Value3'),
SlackField.withParam('Test4', 'Value4'),
];
message.attachments.add(attachment);
sends('app_notifier', message, targetUser: 'toki');
}
Future sendBuild(String appName, SlackBuildType buildType, Color color,
String version, String downloadURL,
{String channel = 'build'}) async {
final buildURL = 'http://toki-labs.com/build/';
String thumUrl = buildType == SlackBuildType.android
? '${buildURL}android.png'
: '${buildURL}appstore.png';
String projectIcon = "$buildURL$appName/icon.png";
String emoji =
buildType == SlackBuildType.android ? ":android1: " : ":ios0: ";
String osColor = buildType == SlackBuildType.ios ? "#ED145B" : "#81CA3F";
var message = DataSlack();
message.attachments = [];
var attachments = message.attachments;
var attachment = SlackAttachment();
attachment.color = color.toHexColor().toCssString();
attachment.fields = [SlackField.withParam(toPascal(appName), null)];
attachments.add(attachment);
var buildTypeStr = buildTypeToString(buildType);
attachment = SlackAttachment();
attachment.color = osColor;
attachment.author_name = /*emoji +*/ buildTypeStr;
attachment.author_icon = thumUrl;
attachment.thumb_url = projectIcon;
attachment.fields = [
SlackField.withParam(null,
"Successfully build $buildTypeStr binary file.\nBuild version: *$version*")
];
attachment.actions = [
SlackAction.withParam(
'build', 'Download', downloadURL, null, SlackActionType.button, null)
];
attachments.add(attachment);
return await sends(channel, message);
}
String buildTypeToString(SlackBuildType type) {
var typeStr = type.toString().replaceAll('SlackBuildType.', '');
return toPascal(typeStr);
}
String toPascal(String raw) {
return '${raw[0].toUpperCase()}${raw.substring(1).toLowerCase()}';
}
}

View file

@ -1,6 +1,7 @@
import 'dart:async';
import 'dart:convert';
import 'dart:io';
import 'dart:typed_data';
import 'package:yaml/yaml.dart';
@ -87,3 +88,19 @@ Future get simpleFuture {
c.complete();
return c.future;
}
Future<Uint8List?> readFileByte(String filePath) async {
var c = Completer<Uint8List>();
Uri myUri = Uri.parse(filePath);
File audioFile = File.fromUri(myUri);
Uint8List? bytes;
await audioFile.readAsBytes().then((value) {
bytes = Uint8List.fromList(value);
print('reading of bytes is completed');
}).catchError((onError) {
print(
'Exception Error while reading audio from path:' + onError.toString());
});
c.complete(bytes);
return c.future;
}

View file

@ -14,6 +14,8 @@ dependencies:
archive: ^3.3.5
ftpconnect: ^2.0.5
yaml: ^3.1.1
http: ^0.13.5
color: ^3.0.0
dev_dependencies:
lints: ^2.0.0