Initial commit
This commit is contained in:
@@ -0,0 +1,54 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace LineMessaging
|
||||
{
|
||||
public partial class LineMessagingClient
|
||||
{
|
||||
private const string GroupMemberApiPath = "/v2/bot/group/{0}/member/{1}";
|
||||
private const string GroupMembersApiPath = "/v2/bot/group/{0}/members/ids";
|
||||
private const string LeaveGroupApiPath = "/v2/bot/group/{0}/leave";
|
||||
|
||||
public async Task<LineProfile> GetGroupMember(string groupId, string userId)
|
||||
{
|
||||
if (string.IsNullOrEmpty(groupId))
|
||||
{
|
||||
throw new ArgumentException($"{nameof(groupId)} is null or empty.");
|
||||
}
|
||||
|
||||
if (string.IsNullOrEmpty(userId))
|
||||
{
|
||||
throw new ArgumentException($"{nameof(userId)} is null or empty.");
|
||||
}
|
||||
|
||||
return await Get<LineProfile>(string.Format(GroupMemberApiPath, groupId, userId));
|
||||
}
|
||||
|
||||
public async Task<LineMembers> GetGroupMembers(string groupId, string start = null)
|
||||
{
|
||||
if (string.IsNullOrEmpty(groupId))
|
||||
{
|
||||
throw new ArgumentException($"{nameof(groupId)} is null or empty.");
|
||||
}
|
||||
|
||||
var query = new Dictionary<string, object>();
|
||||
if (start != null)
|
||||
{
|
||||
query["start"] = start;
|
||||
}
|
||||
|
||||
return await Get<LineMembers>(string.Format(GroupMembersApiPath, groupId), query);
|
||||
}
|
||||
|
||||
public async Task LeaveGroup(string groupId)
|
||||
{
|
||||
if (string.IsNullOrEmpty(groupId))
|
||||
{
|
||||
throw new ArgumentException($"{nameof(groupId)} is null or empty.");
|
||||
}
|
||||
|
||||
await Post(string.Format(LeaveGroupApiPath, groupId));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace LineMessaging
|
||||
{
|
||||
public partial class LineMessagingClient
|
||||
{
|
||||
private const string MessageContentApiPath = "/v2/bot/message/{0}/content";
|
||||
|
||||
public Task<byte[]> GetMessageContent(string messageId)
|
||||
{
|
||||
if (string.IsNullOrEmpty(messageId))
|
||||
{
|
||||
throw new ArgumentException($"{nameof(messageId)} is null or empty.");
|
||||
}
|
||||
|
||||
return GetAsByteArray(string.Format(MessageContentApiPath, messageId));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,255 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace LineMessaging
|
||||
{
|
||||
public partial class LineMessagingClient
|
||||
{
|
||||
private const string LineMessagePushApiPath = "/v2/bot/message/push";
|
||||
private const string LineMessageMulticastApiPath = "/v2/bot/message/multicast";
|
||||
|
||||
public async Task PushMessage(LinePushMessage pushMessage)
|
||||
{
|
||||
if (pushMessage == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(pushMessage));
|
||||
}
|
||||
|
||||
if (string.IsNullOrEmpty(pushMessage.To))
|
||||
{
|
||||
throw new ArgumentException($"{nameof(pushMessage.To)} is null or empty.");
|
||||
}
|
||||
|
||||
var messageCount = pushMessage.Messages.Count();
|
||||
if (pushMessage.Messages == null || messageCount == 0 || messageCount > 5)
|
||||
{
|
||||
throw new ArgumentException($"{nameof(pushMessage.Messages)} is required and max length is 5.");
|
||||
}
|
||||
|
||||
await Post(LineMessagePushApiPath, pushMessage);
|
||||
}
|
||||
|
||||
public async Task PushMessage(string to, ILineMessage message)
|
||||
{
|
||||
if (to == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(to));
|
||||
}
|
||||
|
||||
if (message == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(message));
|
||||
}
|
||||
|
||||
await Post(LineMessagePushApiPath, new LinePushMessage
|
||||
{
|
||||
To = to,
|
||||
Messages = new List<ILineMessage> { message }
|
||||
});
|
||||
}
|
||||
|
||||
public async Task PushMessage(string to, IEnumerable<ILineMessage> messages)
|
||||
{
|
||||
if (to == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(to));
|
||||
}
|
||||
|
||||
if (messages == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(messages));
|
||||
}
|
||||
|
||||
var messageCount = messages.Count();
|
||||
if (messageCount == 0 || messageCount > 5)
|
||||
{
|
||||
throw new ArgumentException($"{nameof(messages)} is required and max length is 5.");
|
||||
}
|
||||
|
||||
await Post(LineMessagePushApiPath, new LinePushMessage
|
||||
{
|
||||
To = to,
|
||||
Messages = messages
|
||||
});
|
||||
}
|
||||
|
||||
public async Task PushMessage(string to, string message)
|
||||
{
|
||||
if (to == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(to));
|
||||
}
|
||||
|
||||
if (string.IsNullOrEmpty(message))
|
||||
{
|
||||
throw new ArgumentException($"{nameof(message)} is null or empty.");
|
||||
}
|
||||
|
||||
await Post(LineMessagePushApiPath, new LinePushMessage
|
||||
{
|
||||
To = to,
|
||||
Messages = new List<ILineMessage> { new LineTextMessage { Text = message } }
|
||||
});
|
||||
}
|
||||
|
||||
public async Task PushMessage(string to, params string[] messages)
|
||||
{
|
||||
if (to == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(to));
|
||||
}
|
||||
|
||||
if (messages == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(messages));
|
||||
}
|
||||
|
||||
if (messages.Length == 0 || messages.Length > 5)
|
||||
{
|
||||
throw new ArgumentException($"{nameof(messages)} is required and max length is 5.");
|
||||
}
|
||||
|
||||
await Post(LineMessagePushApiPath, new LinePushMessage
|
||||
{
|
||||
To = to,
|
||||
Messages = messages.Select(x => (ILineMessage)new LineTextMessage { Text = x }).ToList()
|
||||
});
|
||||
}
|
||||
|
||||
public async Task MulticastMessage(LineMulticastMessage multicastMessage)
|
||||
{
|
||||
if (multicastMessage == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(multicastMessage));
|
||||
}
|
||||
|
||||
var toCount = multicastMessage.To.Count();
|
||||
if (multicastMessage.To == null || toCount == 0 || toCount > 150)
|
||||
{
|
||||
throw new ArgumentException($"{nameof(multicastMessage.To)} is required and max length is 150.");
|
||||
}
|
||||
|
||||
var messageCount = multicastMessage.Messages.Count();
|
||||
if (multicastMessage.Messages == null || messageCount == 0 || messageCount > 5)
|
||||
{
|
||||
throw new ArgumentException($"{nameof(multicastMessage.Messages)} is required and max length is 5.");
|
||||
}
|
||||
|
||||
await Post(LineMessageMulticastApiPath, multicastMessage);
|
||||
}
|
||||
|
||||
public async Task MulticastMessage(IEnumerable<string> to, ILineMessage message)
|
||||
{
|
||||
if (to == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(to));
|
||||
}
|
||||
|
||||
if (message == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(message));
|
||||
}
|
||||
|
||||
var toCount = to.Count();
|
||||
if (toCount == 0 || toCount > 150)
|
||||
{
|
||||
throw new ArgumentException($"{nameof(to)} is required and max length is 150.");
|
||||
}
|
||||
|
||||
await Post(LineMessageMulticastApiPath, new LineMulticastMessage
|
||||
{
|
||||
To = to,
|
||||
Messages = new List<ILineMessage> { message }
|
||||
});
|
||||
}
|
||||
|
||||
public async Task MulticastMessage(IEnumerable<string> to, IEnumerable<ILineMessage> messages)
|
||||
{
|
||||
if (to == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(to));
|
||||
}
|
||||
|
||||
if (messages == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(messages));
|
||||
}
|
||||
|
||||
var toCount = to.Count();
|
||||
if (toCount == 0 || toCount > 150)
|
||||
{
|
||||
throw new ArgumentException($"{nameof(to)} is required and max length is 150.");
|
||||
}
|
||||
|
||||
var messageCount = messages.Count();
|
||||
if (messageCount == 0 || messageCount > 5)
|
||||
{
|
||||
throw new ArgumentException($"{nameof(messages)} is required and max length is 5.");
|
||||
}
|
||||
|
||||
await Post(LineMessageMulticastApiPath, new LineMulticastMessage
|
||||
{
|
||||
To = to,
|
||||
Messages = messages
|
||||
});
|
||||
}
|
||||
|
||||
public async Task MulticastMessage(IEnumerable<string> to, string message)
|
||||
{
|
||||
if (to == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(to));
|
||||
}
|
||||
|
||||
if (string.IsNullOrEmpty(message))
|
||||
{
|
||||
throw new ArgumentException($"{nameof(message)} is null or empty.");
|
||||
}
|
||||
|
||||
var toCount = to.Count();
|
||||
if (toCount == 0 || toCount > 150)
|
||||
{
|
||||
throw new ArgumentException($"{nameof(to)} is required and max length is 150.");
|
||||
}
|
||||
|
||||
await Post(LineMessageMulticastApiPath, new LineMulticastMessage
|
||||
{
|
||||
To = to,
|
||||
Messages = new List<ILineMessage> { new LineTextMessage { Text = message } }
|
||||
});
|
||||
}
|
||||
|
||||
public async Task MulticastMessage(IEnumerable<string> to, params string[] messages)
|
||||
{
|
||||
if (to == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(to));
|
||||
}
|
||||
|
||||
if (messages == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(messages));
|
||||
}
|
||||
|
||||
var toCount = to.Count();
|
||||
if (toCount == 0 || toCount > 150)
|
||||
{
|
||||
throw new ArgumentException($"{nameof(to)} is required and max length is 150.");
|
||||
}
|
||||
|
||||
var messageCount = messages.Count();
|
||||
if (messageCount == 0 || messageCount > 5)
|
||||
{
|
||||
throw new ArgumentException($"{nameof(messages)} is required and max length is 5.");
|
||||
}
|
||||
|
||||
await Post(LineMessageMulticastApiPath, new LineMulticastMessage
|
||||
{
|
||||
To = to,
|
||||
Messages = messages.Select(x => (ILineMessage)new LineTextMessage { Text = x }).ToList()
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,101 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace LineMessaging
|
||||
{
|
||||
public partial class LineMessagingClient
|
||||
{
|
||||
private const string MessageReplyApiPath = "/v2/bot/message/reply";
|
||||
|
||||
public async Task ReplyMessage(LineReplyMessage replyMessage)
|
||||
{
|
||||
if (replyMessage == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(replyMessage));
|
||||
}
|
||||
|
||||
if (string.IsNullOrEmpty(replyMessage.ReplyToken))
|
||||
{
|
||||
throw new ArgumentException($"{nameof(replyMessage.ReplyToken)} is null or empty.");
|
||||
}
|
||||
|
||||
var messageCount = replyMessage.Messages.Count();
|
||||
if (replyMessage.Messages == null || messageCount == 0 || messageCount > 5)
|
||||
{
|
||||
throw new ArgumentException($"{nameof(replyMessage.Messages)} is required and max length is 5.");
|
||||
}
|
||||
|
||||
await Post(MessageReplyApiPath, replyMessage);
|
||||
}
|
||||
|
||||
public async Task ReplyMessage(string replyToken, IEnumerable<ILineMessage> messages)
|
||||
{
|
||||
if (string.IsNullOrEmpty(replyToken))
|
||||
{
|
||||
throw new ArgumentException($"{nameof(replyToken)} is null or empty.");
|
||||
}
|
||||
|
||||
if (messages == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(messages));
|
||||
}
|
||||
|
||||
var messageCount = messages.Count();
|
||||
if (messageCount == 0 || messageCount > 5)
|
||||
{
|
||||
throw new ArgumentException($"{nameof(messages)} is required and max length is 5.");
|
||||
}
|
||||
|
||||
await Post(MessageReplyApiPath, new LineReplyMessage
|
||||
{
|
||||
ReplyToken = replyToken,
|
||||
Messages = messages
|
||||
});
|
||||
}
|
||||
|
||||
public async Task ReplyMessage(string replyToken, string message)
|
||||
{
|
||||
if (string.IsNullOrEmpty(replyToken))
|
||||
{
|
||||
throw new ArgumentException($"{nameof(replyToken)} is null or empty.");
|
||||
}
|
||||
|
||||
if (string.IsNullOrEmpty(message))
|
||||
{
|
||||
throw new ArgumentException($"{nameof(message)} is null or empty.");
|
||||
}
|
||||
|
||||
await Post(MessageReplyApiPath, new LineReplyMessage
|
||||
{
|
||||
ReplyToken = replyToken,
|
||||
Messages = new List<ILineMessage> { new LineTextMessage { Text = message } }
|
||||
});
|
||||
}
|
||||
|
||||
public async Task ReplyMessage(string replyToken, params string[] messages)
|
||||
{
|
||||
if (string.IsNullOrEmpty(replyToken))
|
||||
{
|
||||
throw new ArgumentException($"{nameof(replyToken)} is null or empty.");
|
||||
}
|
||||
|
||||
if (messages == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(messages));
|
||||
}
|
||||
|
||||
if (messages.Length == 0 || messages.Length > 5)
|
||||
{
|
||||
throw new ArgumentException($"{nameof(messages)} is required and max length is 5.");
|
||||
}
|
||||
|
||||
await Post(MessageReplyApiPath, new LineReplyMessage
|
||||
{
|
||||
ReplyToken = replyToken,
|
||||
Messages = messages.Select(x => (ILineMessage)new LineTextMessage { Text = x }).ToList()
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace LineMessaging
|
||||
{
|
||||
public partial class LineMessagingClient
|
||||
{
|
||||
private const string ProfileApiPath = "/v2/bot/profile/{0}";
|
||||
|
||||
public async Task<LineProfile> GetProfile(string userId)
|
||||
{
|
||||
if (string.IsNullOrEmpty(userId))
|
||||
{
|
||||
throw new ArgumentException($"{nameof(userId)} is null or empty.");
|
||||
}
|
||||
|
||||
return await Get<LineProfile>(string.Format(ProfileApiPath, userId));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,98 @@
|
||||
using System;
|
||||
using Newtonsoft.Json;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace LineMessaging
|
||||
{
|
||||
public partial class LineMessagingClient
|
||||
{
|
||||
private const string RichMenuApiPath = "/v2/bot/richmenu/{0}";
|
||||
private const string RichMenusApiPath = "/v2/bot/richmenu";
|
||||
private const string UsersRichMenuApiPath = "/v2/bot/user/{0}/richmenu";
|
||||
private const string LinkUsersRichMenuApiPath = "/v2/bot/user/{0}/richmenu/{1}";
|
||||
private const string RichMenuContentApiPath = "/v2/bot/richmenu/{0}/content";
|
||||
|
||||
public async Task<LineRichMenuResponse> GetRichMenu(string richMenuId)
|
||||
{
|
||||
if (string.IsNullOrEmpty(richMenuId))
|
||||
{
|
||||
throw new ArgumentException($"{nameof(richMenuId)} is null or empty.");
|
||||
}
|
||||
|
||||
return await Get<LineRichMenuResponse>(string.Format(RichMenuApiPath, richMenuId));
|
||||
}
|
||||
|
||||
public async Task<string> CreateRichMenu(LineRichMenu richMenu)
|
||||
{
|
||||
if (richMenu == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(richMenu));
|
||||
}
|
||||
|
||||
var response = await Post<RichMenuIdResponse>(RichMenusApiPath, richMenu);
|
||||
return response?.RichMenuId;
|
||||
}
|
||||
|
||||
public async Task DeleteRichMenu(string richMenuId)
|
||||
{
|
||||
if (string.IsNullOrEmpty(richMenuId))
|
||||
{
|
||||
throw new ArgumentException($"{nameof(richMenuId)} is null or empty.");
|
||||
}
|
||||
|
||||
await Delete(string.Format(RichMenuApiPath, richMenuId));
|
||||
}
|
||||
|
||||
public async Task<string> GetUsersRichMenuId(string userId)
|
||||
{
|
||||
if (string.IsNullOrEmpty(userId))
|
||||
{
|
||||
throw new ArgumentException($"{nameof(userId)} is null or empty.");
|
||||
}
|
||||
|
||||
var response = await Get<RichMenuIdResponse>(string.Format(UsersRichMenuApiPath, userId));
|
||||
return response?.RichMenuId;
|
||||
}
|
||||
|
||||
public async Task LinkUsersRichMenu(string userId, string richMenuId)
|
||||
{
|
||||
if (string.IsNullOrEmpty(userId))
|
||||
{
|
||||
throw new ArgumentException($"{nameof(userId)} is null or empty.");
|
||||
}
|
||||
|
||||
if (string.IsNullOrEmpty(richMenuId))
|
||||
{
|
||||
throw new ArgumentException($"{nameof(richMenuId)} is null or empty.");
|
||||
}
|
||||
|
||||
await Post(string.Format(LinkUsersRichMenuApiPath, userId, richMenuId));
|
||||
}
|
||||
|
||||
public async Task UnlinkUsersRichMenu(string userId)
|
||||
{
|
||||
if (string.IsNullOrEmpty(userId))
|
||||
{
|
||||
throw new ArgumentException($"{nameof(userId)} is null or empty.");
|
||||
}
|
||||
|
||||
await Delete(string.Format(UsersRichMenuApiPath, userId));
|
||||
}
|
||||
|
||||
public async Task<byte[]> GetRichMenuContent(string richMenuId)
|
||||
{
|
||||
if (string.IsNullOrEmpty(richMenuId))
|
||||
{
|
||||
throw new ArgumentException($"{nameof(richMenuId)} is null or empty.");
|
||||
}
|
||||
|
||||
return await GetAsByteArray(string.Format(RichMenuContentApiPath, richMenuId));
|
||||
}
|
||||
|
||||
internal class RichMenuIdResponse
|
||||
{
|
||||
[JsonProperty("richMenuId")]
|
||||
internal string RichMenuId { get; set; }
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace LineMessaging
|
||||
{
|
||||
public partial class LineMessagingClient
|
||||
{
|
||||
private const string RoomMemberApiPath = "/v2/bot/room/{0}/member/{1}";
|
||||
private const string RoomMembersApiPath = "/v2/bot/room/{0}/members/ids";
|
||||
private const string LeaveRoomApiPath = "/v2/bot/room/{0}/leave";
|
||||
|
||||
public async Task<LineProfile> GetRoomMember(string roomId, string userId)
|
||||
{
|
||||
if (string.IsNullOrEmpty(roomId))
|
||||
{
|
||||
throw new ArgumentException($"{nameof(roomId)} is null or empty.");
|
||||
}
|
||||
|
||||
if (string.IsNullOrEmpty(userId))
|
||||
{
|
||||
throw new ArgumentException($"{nameof(userId)} is null or empty.");
|
||||
}
|
||||
|
||||
return await Get<LineProfile>(string.Format(RoomMemberApiPath, roomId, userId));
|
||||
}
|
||||
|
||||
public async Task<LineMembers> GetRoomMembers(string roomId, string start = null)
|
||||
{
|
||||
if (string.IsNullOrEmpty(roomId))
|
||||
{
|
||||
throw new ArgumentException($"{nameof(roomId)} is null or empty.");
|
||||
}
|
||||
|
||||
var query = new Dictionary<string, object>();
|
||||
if (start != null)
|
||||
{
|
||||
query["start"] = start;
|
||||
}
|
||||
|
||||
return await Get<LineMembers>(string.Format(RoomMembersApiPath, roomId), query);
|
||||
}
|
||||
|
||||
public async Task LeaveRoom(string roomId)
|
||||
{
|
||||
if (string.IsNullOrEmpty(roomId))
|
||||
{
|
||||
throw new ArgumentException($"{nameof(roomId)} is null or empty.");
|
||||
}
|
||||
|
||||
await Post(string.Format(LeaveRoomApiPath, roomId));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
using System.Linq;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace LineMessaging
|
||||
{
|
||||
public class LineErrorResponse
|
||||
{
|
||||
[JsonProperty("message")]
|
||||
public string Message { get; set; }
|
||||
|
||||
[JsonProperty("details")]
|
||||
public DetailObject[] Details { get; set; }
|
||||
|
||||
public class DetailObject
|
||||
{
|
||||
[JsonProperty("message")]
|
||||
public string Message { get; set; }
|
||||
|
||||
[JsonProperty("property")]
|
||||
public string Property { get; set; }
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
if (Details != null && Details.Any())
|
||||
{
|
||||
var details = string.Join(", ", Details.Select(x => $"Property {x.Property} {x.Message}"));
|
||||
return $"{Message}. details: {details}";
|
||||
}
|
||||
|
||||
return Message;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace LineMessaging
|
||||
{
|
||||
public class LineMembers
|
||||
{
|
||||
[JsonProperty("memberIds")]
|
||||
public string[] MemberIds { get; set; }
|
||||
|
||||
[JsonProperty("next")]
|
||||
public string Next { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace LineMessaging
|
||||
{
|
||||
public class LineProfile
|
||||
{
|
||||
[JsonProperty("displayName")]
|
||||
public string DisplayName { get; set; }
|
||||
|
||||
[JsonProperty("userId")]
|
||||
public string UserId { get; set; }
|
||||
|
||||
[JsonProperty("pictureUrl")]
|
||||
public string PictureUrl { get; set; }
|
||||
|
||||
[JsonProperty("statusMessage")]
|
||||
public string StatusMessage { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
using System;
|
||||
|
||||
namespace LineMessaging
|
||||
{
|
||||
internal static class DateTimeExtensions
|
||||
{
|
||||
private static readonly DateTimeOffset UnixEpochDateTimeOffset = new DateTimeOffset(1970, 1, 1, 0, 0, 0, TimeSpan.Zero);
|
||||
private static readonly DateTime UnixEpochDateTime = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
|
||||
|
||||
internal static DateTime FromUnixTime(this long unixTime)
|
||||
{
|
||||
return UnixEpochDateTime.AddMilliseconds(unixTime).ToLocalTime();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace LineMessaging
|
||||
{
|
||||
internal static class DictionaryExtensions
|
||||
{
|
||||
internal static string ToQueryString(this Dictionary<string, object> source)
|
||||
{
|
||||
if (source == null) throw new ArgumentNullException();
|
||||
if (source.Count == 0) return string.Empty;
|
||||
return "?" + string.Join("&", source.Select(x => $"{x.Key}={x.Value}"));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
using System;
|
||||
|
||||
namespace LineMessaging
|
||||
{
|
||||
internal static class LineConstants
|
||||
{
|
||||
internal static readonly Uri BaseUri = new Uri("https://api.line.me/");
|
||||
internal static readonly Uri BaseDataUri = new Uri("https://api-data.line.me/");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
|
||||
<Version>1.4.0</Version>
|
||||
<Authors>Kiyoaki Tsurutani</Authors>
|
||||
<Company></Company>
|
||||
<Product />
|
||||
<Description>LINE Messaging API Client Library for .NET (C#)</Description>
|
||||
<Copyright>Kiyoaki Tsurutani</Copyright>
|
||||
<PackageLicenseExpression>MIT</PackageLicenseExpression>
|
||||
<PackageProjectUrl>https://github.com/kiyoaki/LineMessagingApi</PackageProjectUrl>
|
||||
<RepositoryUrl>https://github.com/kiyoaki/LineMessagingApi</RepositoryUrl>
|
||||
<RepositoryType>git</RepositoryType>
|
||||
<PackageTags>LINE, BOT</PackageTags>
|
||||
<PackageReleaseNotes>Support .NET 6</PackageReleaseNotes>
|
||||
<SignAssembly>false</SignAssembly>
|
||||
<AssemblyOriginatorKeyFile>opensource.pfx</AssemblyOriginatorKeyFile>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
@@ -0,0 +1,185 @@
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Serialization;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Net.Http;
|
||||
using System.Net.Http.Headers;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace LineMessaging
|
||||
{
|
||||
public partial class LineMessagingClient
|
||||
{
|
||||
private const string ACCESS_TOKEN = "WFAyMvMEZ86cfMJIAzE+yklUZGpeS/jFYTeL9a9O35QR83oNMmwaUJfyEe48Kegadz0BArDdBoySxs479U1pwTHtlyH+Sm4jqlz8BwukX/Hsa4D1fX03Qn4zFu7TwPFKWFXnZbWq89Yg0iNzjpfTNwdB04t89/1O/w1cDnyilFU=";
|
||||
private static readonly MediaTypeHeaderValue MediaTypeJson = MediaTypeHeaderValue.Parse("application/json; charset=utf-8");
|
||||
private static readonly MediaTypeHeaderValue MediaTypeJpeg = MediaTypeHeaderValue.Parse("image/jpeg");
|
||||
private static readonly MediaTypeHeaderValue MediaTypePng = MediaTypeHeaderValue.Parse("image/png");
|
||||
private static readonly HttpClient HttpClient = new HttpClient
|
||||
{
|
||||
BaseAddress = LineConstants.BaseUri,
|
||||
Timeout = TimeSpan.FromSeconds(10)
|
||||
};
|
||||
private static readonly HttpClient HttpDataClient = new HttpClient
|
||||
{
|
||||
BaseAddress = LineConstants.BaseDataUri,
|
||||
Timeout = TimeSpan.FromSeconds(10)
|
||||
};
|
||||
|
||||
private readonly AuthenticationHeaderValue accessTokenHeaderValue;
|
||||
private JsonSerializerSettings serializerSettings;
|
||||
public LineMessagingClient()
|
||||
{
|
||||
string accessToken = ACCESS_TOKEN;
|
||||
if (string.IsNullOrEmpty(accessToken))
|
||||
{
|
||||
throw new ArgumentException($"{nameof(accessToken)} is null or empty.");
|
||||
}
|
||||
this.serializerSettings = new JsonSerializerSettings()
|
||||
{
|
||||
ContractResolver = new CamelCasePropertyNamesContractResolver(),
|
||||
NullValueHandling = NullValueHandling.Ignore,
|
||||
Formatting=Formatting.Indented
|
||||
};
|
||||
accessTokenHeaderValue = new AuthenticationHeaderValue("Bearer", accessToken);
|
||||
}
|
||||
|
||||
private async Task<T> Get<T>(string path, Dictionary<string, object> query = null)
|
||||
{
|
||||
return await SendRequest<T>(HttpMethod.Get, path, query);
|
||||
}
|
||||
|
||||
private async Task<T> Post<T>(string path, object body)
|
||||
{
|
||||
return await SendRequest<T>(HttpMethod.Post, path, null, body);
|
||||
}
|
||||
|
||||
private async Task Post(string path, object body = null)
|
||||
{
|
||||
await SendRequest(HttpMethod.Post, path, null, body);
|
||||
}
|
||||
|
||||
private async Task PostJpeg(string path, byte[] image)
|
||||
{
|
||||
await PostImage(path, "jpeg", image);
|
||||
}
|
||||
|
||||
private async Task PostPng(string path, byte[] image)
|
||||
{
|
||||
await PostImage(path, "png", image);
|
||||
}
|
||||
|
||||
private async Task Delete(string path)
|
||||
{
|
||||
await SendRequest(HttpMethod.Delete, path);
|
||||
}
|
||||
|
||||
private async Task<byte[]> GetAsByteArray(string path)
|
||||
{
|
||||
using (var message = new HttpRequestMessage(HttpMethod.Get, path))
|
||||
{
|
||||
message.Headers.Authorization = accessTokenHeaderValue;
|
||||
HttpResponseMessage response;
|
||||
try
|
||||
{
|
||||
response = await HttpDataClient.SendAsync(message);
|
||||
}
|
||||
catch (TaskCanceledException)
|
||||
{
|
||||
throw new LineMessagingException(path, "Request Timeout");
|
||||
}
|
||||
|
||||
await CheckStatusCode(path, response);
|
||||
return await response.Content.ReadAsByteArrayAsync();
|
||||
}
|
||||
}
|
||||
|
||||
private async Task<T> SendRequest<T>(HttpMethod method, string path,
|
||||
Dictionary<string, object> query = null, object body = null)
|
||||
{
|
||||
var responseJson = await SendRequest(method, path, query, body);
|
||||
return JsonConvert.DeserializeObject<T>(responseJson);
|
||||
}
|
||||
|
||||
private async Task PostImage(string path, string imageFormat, byte[] image)
|
||||
{
|
||||
using (var message = new HttpRequestMessage(HttpMethod.Post, path))
|
||||
{
|
||||
message.Content = new ByteArrayContent(image);
|
||||
switch (imageFormat)
|
||||
{
|
||||
case "jpeg":
|
||||
message.Content.Headers.ContentType = MediaTypeJpeg;
|
||||
break;
|
||||
|
||||
case "png":
|
||||
message.Content.Headers.ContentType = MediaTypePng;
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new LineMessagingException(path, $"{imageFormat} is not supported.");
|
||||
}
|
||||
message.Headers.Authorization = accessTokenHeaderValue;
|
||||
|
||||
HttpResponseMessage response;
|
||||
try
|
||||
{
|
||||
response = await HttpClient.SendAsync(message);
|
||||
}
|
||||
catch (TaskCanceledException)
|
||||
{
|
||||
throw new LineMessagingException(path, "Request Timeout");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private async Task<string> SendRequest(HttpMethod method, string path,
|
||||
Dictionary<string, object> query = null, object body = null)
|
||||
{
|
||||
string queryString = null;
|
||||
if (query != null)
|
||||
{
|
||||
queryString = query.ToQueryString();
|
||||
}
|
||||
|
||||
using (var message = new HttpRequestMessage(method, path + queryString))
|
||||
{
|
||||
if (body != null)
|
||||
{
|
||||
string jsonContent = JsonConvert.SerializeObject(body, serializerSettings);
|
||||
|
||||
message.Content = new StringContent(jsonContent);
|
||||
message.Content.Headers.ContentType = MediaTypeJson;
|
||||
}
|
||||
message.Headers.Authorization = accessTokenHeaderValue;
|
||||
|
||||
HttpResponseMessage response;
|
||||
try
|
||||
{
|
||||
response = await HttpClient.SendAsync(message);
|
||||
}
|
||||
catch (TaskCanceledException)
|
||||
{
|
||||
throw new LineMessagingException(path, "Request Timeout");
|
||||
}
|
||||
|
||||
await CheckStatusCode(path, response);
|
||||
return await response.Content.ReadAsStringAsync();
|
||||
}
|
||||
}
|
||||
|
||||
private static async Task CheckStatusCode(string path, HttpResponseMessage response)
|
||||
{
|
||||
if (!response.IsSuccessStatusCode)
|
||||
{
|
||||
var responseJson = await response.Content.ReadAsStringAsync();
|
||||
var error = JsonConvert.DeserializeObject<LineErrorResponse>(responseJson);
|
||||
if (error != null)
|
||||
{
|
||||
throw new LineMessagingException(path, error);
|
||||
}
|
||||
throw new LineMessagingException(path,
|
||||
$"Error has occurred. Response StatusCode:{response.StatusCode} ReasonPhrase:{response.ReasonPhrase}.");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
using System;
|
||||
|
||||
namespace LineMessaging
|
||||
{
|
||||
public class LineMessagingException : Exception
|
||||
{
|
||||
public string Path { get; }
|
||||
|
||||
public LineOAuthErrorResponse OAuthErrorResponse { get; }
|
||||
|
||||
public LineErrorResponse ErrorResponse { get; }
|
||||
|
||||
public LineMessagingException(string path, LineErrorResponse errorResponse)
|
||||
: base(errorResponse.ToString())
|
||||
{
|
||||
Path = path ?? throw new ArgumentNullException(nameof(path));
|
||||
ErrorResponse = errorResponse;
|
||||
}
|
||||
|
||||
public LineMessagingException(string path, LineOAuthErrorResponse oAuthErrorResponse)
|
||||
: base(oAuthErrorResponse.ToString())
|
||||
{
|
||||
Path = path ?? throw new ArgumentNullException(nameof(path));
|
||||
OAuthErrorResponse = oAuthErrorResponse;
|
||||
}
|
||||
|
||||
public LineMessagingException(string path, string message)
|
||||
: base(message)
|
||||
{
|
||||
Path = path ?? throw new ArgumentNullException(nameof(path));
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return $"The request to {Path} has thrown an exception: {base.ToString()}";
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,99 @@
|
||||
using Newtonsoft.Json;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Net.Http;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace LineMessaging
|
||||
{
|
||||
public class LineOAuthClient
|
||||
{
|
||||
private const string OAuthAccessTokenApiPath = "/v2/oauth/accessToken";
|
||||
private const string OAuthRevokeTokenApiPath = "/v2/oauth/revoke";
|
||||
private static readonly HttpClient HttpClient = new HttpClient
|
||||
{
|
||||
BaseAddress = LineConstants.BaseUri,
|
||||
Timeout = TimeSpan.FromSeconds(10)
|
||||
};
|
||||
|
||||
private readonly string channelId;
|
||||
private readonly string channelSecret;
|
||||
|
||||
public LineOAuthClient(string channelId, string channelSecret)
|
||||
{
|
||||
if (string.IsNullOrEmpty(channelId))
|
||||
{
|
||||
throw new ArgumentException($"{nameof(channelId)} is null or empty.");
|
||||
}
|
||||
if (string.IsNullOrEmpty(channelSecret))
|
||||
{
|
||||
throw new ArgumentException($"{nameof(channelSecret)} is null or empty.");
|
||||
}
|
||||
|
||||
this.channelId = channelId;
|
||||
this.channelSecret = channelSecret;
|
||||
}
|
||||
|
||||
public async Task<LineOAuthTokenResponse> GetAccessToken()
|
||||
{
|
||||
using (var content = new FormUrlEncodedContent(new Dictionary<string, string>
|
||||
{
|
||||
{ "grant_type", "client_credentials" },
|
||||
{ "client_id", channelId },
|
||||
{ "client_secret", channelSecret }
|
||||
}))
|
||||
{
|
||||
try
|
||||
{
|
||||
var response = await HttpClient.PostAsync(OAuthAccessTokenApiPath, content);
|
||||
var responseJson = await response.Content.ReadAsStringAsync();
|
||||
if (!response.IsSuccessStatusCode)
|
||||
{
|
||||
var error = JsonConvert.DeserializeObject<LineOAuthErrorResponse>(responseJson);
|
||||
if (error != null)
|
||||
{
|
||||
throw new LineMessagingException(OAuthAccessTokenApiPath, error);
|
||||
}
|
||||
throw new LineMessagingException(OAuthAccessTokenApiPath,
|
||||
$"Error has occurred. Response StatusCode:{response.StatusCode} ReasonPhrase:{response.ReasonPhrase}.");
|
||||
}
|
||||
|
||||
return JsonConvert.DeserializeObject<LineOAuthTokenResponse>(responseJson);
|
||||
}
|
||||
catch (TaskCanceledException)
|
||||
{
|
||||
throw new LineMessagingException(OAuthAccessTokenApiPath, "Request Timeout");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public async Task RevokeAccessToken(string accessToken)
|
||||
{
|
||||
using (var content = new FormUrlEncodedContent(new Dictionary<string, string>
|
||||
{
|
||||
{ "access_token", accessToken }
|
||||
}))
|
||||
{
|
||||
try
|
||||
{
|
||||
var response = await HttpClient.PostAsync(OAuthRevokeTokenApiPath, content);
|
||||
if (!response.IsSuccessStatusCode)
|
||||
{
|
||||
var responseJson = await response.Content.ReadAsStringAsync();
|
||||
var error = JsonConvert.DeserializeObject<LineOAuthErrorResponse>(responseJson);
|
||||
if (error != null)
|
||||
{
|
||||
throw new LineMessagingException(OAuthAccessTokenApiPath, error);
|
||||
}
|
||||
throw new LineMessagingException(OAuthAccessTokenApiPath,
|
||||
$"Error has occurred. Response StatusCode:{response.StatusCode} ReasonPhrase:{response.ReasonPhrase}.");
|
||||
}
|
||||
}
|
||||
catch (TaskCanceledException)
|
||||
{
|
||||
throw new LineMessagingException(OAuthAccessTokenApiPath, "Request Timeout");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,85 @@
|
||||
using Newtonsoft.Json;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Net.Http;
|
||||
using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace LineMessaging
|
||||
{
|
||||
public class LineWebhookRequest
|
||||
{
|
||||
private readonly byte[] secret;
|
||||
private readonly HttpRequestMessage request;
|
||||
private string contentJson;
|
||||
private LineWebhookContent content;
|
||||
|
||||
public LineWebhookRequest(string channelSecret, HttpRequestMessage request)
|
||||
{
|
||||
if (string.IsNullOrEmpty(channelSecret))
|
||||
{
|
||||
throw new ArgumentException($"{nameof(channelSecret)} is null or empty.");
|
||||
}
|
||||
|
||||
secret = Encoding.UTF8.GetBytes(channelSecret);
|
||||
this.request = request;
|
||||
}
|
||||
|
||||
public async Task<bool> IsValid()
|
||||
{
|
||||
if (!request.Headers.TryGetValues("X-Line-Signature", out IEnumerable<string> headers))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
var signature = headers.FirstOrDefault();
|
||||
if (signature == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
contentJson = await request.Content.ReadAsStringAsync();
|
||||
var body = await request.Content.ReadAsByteArrayAsync();
|
||||
|
||||
using (var hmacsha256 = new HMACSHA256(secret))
|
||||
{
|
||||
if (signature != Convert.ToBase64String(hmacsha256.ComputeHash(body)))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public async Task<string> GetContentJson()
|
||||
{
|
||||
if (contentJson != null)
|
||||
{
|
||||
return contentJson;
|
||||
}
|
||||
|
||||
contentJson = await request.Content.ReadAsStringAsync();
|
||||
return contentJson;
|
||||
}
|
||||
|
||||
public async Task<LineWebhookContent> GetContent()
|
||||
{
|
||||
if (content != null)
|
||||
{
|
||||
return content;
|
||||
}
|
||||
|
||||
contentJson = await GetContentJson();
|
||||
if (contentJson == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
content = JsonConvert.DeserializeObject<LineWebhookContent>(contentJson);
|
||||
return content;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace LineMessaging
|
||||
{
|
||||
public interface ILineAction
|
||||
{
|
||||
[JsonProperty("type")]
|
||||
ActionType Type { get; }
|
||||
}
|
||||
|
||||
public class PostbackAction : ILineAction
|
||||
{
|
||||
[JsonProperty("type")]
|
||||
public ActionType Type => ActionType.Postback;
|
||||
[JsonProperty("label")]
|
||||
public string Label { get; set; }
|
||||
|
||||
[JsonProperty("data")]
|
||||
public string Data { get; set; }
|
||||
|
||||
[JsonProperty("displayText")]
|
||||
public string DisplayText { get; set; }
|
||||
|
||||
[JsonProperty("inputOption")]
|
||||
public string InputOption { get; set; }
|
||||
|
||||
[JsonProperty("fillInText")]
|
||||
public string FillInText { get; set; }
|
||||
}
|
||||
|
||||
public class MessageAction : ILineAction
|
||||
{
|
||||
[JsonProperty("type")]
|
||||
public ActionType Type => ActionType.Message;
|
||||
|
||||
[JsonProperty("label")]
|
||||
public string Label { get; set; }
|
||||
|
||||
[JsonProperty("text")]
|
||||
public string Text { get; set; }
|
||||
}
|
||||
|
||||
public class UriAction : ILineAction
|
||||
{
|
||||
[JsonProperty("type")]
|
||||
public ActionType Type => ActionType.Uri;
|
||||
[JsonProperty("label")]
|
||||
public string Label { get; set; }
|
||||
[JsonProperty("uri")]
|
||||
public string Uri { get; set; }
|
||||
}
|
||||
|
||||
public class DatetimepickerAction : ILineAction
|
||||
{
|
||||
[JsonProperty("type")]
|
||||
public ActionType Type => ActionType.Datetimepicker;
|
||||
|
||||
[JsonProperty("label")]
|
||||
public string Label { get; set; }
|
||||
|
||||
[JsonProperty("data")]
|
||||
public string Data { get; set; }
|
||||
|
||||
[JsonProperty("mode")]
|
||||
public string Mode { get; set; }
|
||||
|
||||
[JsonProperty("initial")]
|
||||
public string Initial { get; set; }
|
||||
|
||||
[JsonProperty("max")]
|
||||
public string Max { get; set; }
|
||||
|
||||
[JsonProperty("min")]
|
||||
public string Min { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace LineMessaging
|
||||
{
|
||||
public class LineAreaBounds
|
||||
{
|
||||
[JsonProperty("x")]
|
||||
public int X { get; set; }
|
||||
|
||||
[JsonProperty("y")]
|
||||
public int Y { get; set; }
|
||||
|
||||
[JsonProperty("width")]
|
||||
public int Width { get; set; }
|
||||
|
||||
[JsonProperty("height")]
|
||||
public int Height { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace LineMessaging
|
||||
{
|
||||
public class LineAudioMessage : ILineMessage
|
||||
{
|
||||
[JsonProperty("type")]
|
||||
public MessageType Type => MessageType.Audio;
|
||||
|
||||
[JsonProperty("originalContentUrl")]
|
||||
public string OriginalContentUrl { get; set; }
|
||||
|
||||
[JsonProperty("duration")]
|
||||
public long Duration { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Converters;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.Serialization;
|
||||
|
||||
namespace LineMessaging
|
||||
{
|
||||
[JsonConverter(typeof(StringEnumConverter))]
|
||||
public enum FlexContentType
|
||||
{
|
||||
[EnumMember(Value = "bubble")]
|
||||
Bubble,
|
||||
}
|
||||
public class LineFlexMessage : ILineMessage
|
||||
{
|
||||
public LineFlexMessage()
|
||||
{
|
||||
Contents = new LineFlexContent();
|
||||
//Contents.Body = new LineFlexBox();
|
||||
}
|
||||
[JsonProperty("type")]
|
||||
public MessageType Type => MessageType.Flex;
|
||||
|
||||
[JsonProperty("altText")]
|
||||
public string AltText { get; set; }
|
||||
[JsonProperty("contents")]
|
||||
public LineFlexContent Contents { get; set; }
|
||||
|
||||
|
||||
}
|
||||
public class LineFlexContent
|
||||
{
|
||||
[JsonProperty("type")]
|
||||
public FlexContentType Type => FlexContentType.Bubble;
|
||||
[JsonProperty("header")]
|
||||
public ILineFlexObject Header { get; set; }
|
||||
[JsonProperty("hero")]
|
||||
public ILineFlexObject Hero { get; set; }
|
||||
|
||||
[JsonProperty("body")]
|
||||
public ILineFlexObject Body { get; set; }
|
||||
|
||||
[JsonProperty("footer")]
|
||||
public ILineFlexObject Footer { get; set; }
|
||||
|
||||
public ICollection<ILineFlexObject> InitHeader()
|
||||
{
|
||||
var FlexBox = new LineFlexBox();
|
||||
this.Header = FlexBox;
|
||||
FlexBox.PaddingAll = "sm";
|
||||
return FlexBox.Contents;
|
||||
}
|
||||
|
||||
public ICollection<ILineFlexObject> InitHero()
|
||||
{
|
||||
var FlexBox = new LineFlexBox();
|
||||
this.Hero = FlexBox;
|
||||
return FlexBox.Contents;
|
||||
}
|
||||
public ICollection<ILineFlexObject> InitBody()
|
||||
{
|
||||
var FlexBox = new LineFlexBox();
|
||||
FlexBox.PaddingBottom = "none";
|
||||
this.Body = FlexBox;
|
||||
return FlexBox.Contents;
|
||||
}
|
||||
|
||||
public ICollection<ILineFlexObject> InitFooter()
|
||||
{
|
||||
var FlexBox = new LineFlexBox();
|
||||
this.Footer = FlexBox;
|
||||
FlexBox.PaddingAll = "none";
|
||||
return FlexBox.Contents;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,193 @@
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Converters;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Runtime.Serialization;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using static System.Net.Mime.MediaTypeNames;
|
||||
|
||||
namespace LineMessaging
|
||||
{
|
||||
public interface ILineFlexObject
|
||||
{
|
||||
FlexObjectType Type { get; }
|
||||
}
|
||||
|
||||
[JsonConverter(typeof(StringEnumConverter))]
|
||||
public enum FlexObjectType
|
||||
{
|
||||
[EnumMember(Value = "box")]
|
||||
Box,
|
||||
[EnumMember(Value = "button")]
|
||||
Button,
|
||||
[EnumMember(Value = "image")]
|
||||
Image,
|
||||
[EnumMember(Value = "video")]
|
||||
Video,
|
||||
[EnumMember(Value = "icon")]
|
||||
Icon,
|
||||
[EnumMember(Value = "text")]
|
||||
Text,
|
||||
[EnumMember(Value = "span")]
|
||||
Span,
|
||||
[EnumMember(Value = "separator")]
|
||||
Separator,
|
||||
[EnumMember(Value = "filler")]
|
||||
Filler,
|
||||
}
|
||||
[JsonConverter(typeof(StringEnumConverter))]
|
||||
public enum FlexObjectBoxLayout
|
||||
{
|
||||
[EnumMember(Value = "vertical")]
|
||||
Vertical,
|
||||
[EnumMember(Value = "horizontal")]
|
||||
Horizontal,
|
||||
[EnumMember(Value = "baseline")]
|
||||
Baseline,
|
||||
}
|
||||
[JsonConverter(typeof(StringEnumConverter))]
|
||||
public enum FlexObjectButtonStype
|
||||
{
|
||||
[EnumMember(Value = "link")]
|
||||
Link,
|
||||
[EnumMember(Value = "primary")]
|
||||
Primary,
|
||||
[EnumMember(Value = "secondary")]
|
||||
Secondary,
|
||||
}
|
||||
|
||||
[JsonConverter(typeof(StringEnumConverter))]
|
||||
public enum FlexObjectSize
|
||||
{
|
||||
xxs,
|
||||
xs,
|
||||
sm,
|
||||
md,
|
||||
lg,
|
||||
xl,
|
||||
xxl,
|
||||
[EnumMember(Value = "3xl")]
|
||||
xxxl,
|
||||
[EnumMember(Value = "4xl")]
|
||||
xxxxl,
|
||||
[EnumMember(Value = "5xl")]
|
||||
xxxxxl,
|
||||
full
|
||||
}
|
||||
|
||||
[JsonConverter(typeof(StringEnumConverter))]
|
||||
public enum FlexObjectTextWeidht
|
||||
{
|
||||
[EnumMember(Value = "regular")]
|
||||
Regular,
|
||||
[EnumMember(Value = "bold")]
|
||||
Bold,
|
||||
}
|
||||
public class LineFlexBox : ILineFlexObject
|
||||
{
|
||||
public LineFlexBox()
|
||||
{
|
||||
Layout = FlexObjectBoxLayout.Vertical;
|
||||
Contents = new List<ILineFlexObject>();
|
||||
}
|
||||
public FlexObjectType Type => FlexObjectType.Box;
|
||||
public FlexObjectBoxLayout Layout { get; set; }
|
||||
public ICollection<ILineFlexObject> Contents { get; set; }
|
||||
//public FlexObjectSize Height { get; set; }
|
||||
//public string JustifyContent => "space-evenly";
|
||||
//public string AlignItems => "center";
|
||||
public string PaddingAll { get; set; }
|
||||
public string PaddingTop { get; set; }
|
||||
public string PaddingBottom{ get; set; }
|
||||
public string PaddingStart { get; set; }
|
||||
public string PaddingEnd { get; set; }
|
||||
|
||||
}
|
||||
public class LineFlexButton : ILineFlexObject
|
||||
{
|
||||
public FlexObjectType Type => FlexObjectType.Button;
|
||||
[JsonRequired]
|
||||
public ILineAction Action { get; set; }
|
||||
public FlexObjectButtonStype Style { get; set; }
|
||||
//public FlexObjectSize Size { get; set; }
|
||||
}
|
||||
public class LineFlexImage : ILineFlexObject
|
||||
{
|
||||
public LineFlexImage(string url)
|
||||
{
|
||||
AspectRatio = "1.91:1";
|
||||
Url = url;
|
||||
Size = FlexObjectSize.md;
|
||||
}
|
||||
public FlexObjectType Type => FlexObjectType.Image;
|
||||
[JsonRequired]
|
||||
public string Url { get; set; }
|
||||
public FlexObjectSize Size { get; set; }
|
||||
public string AspectRatio { get; set; }
|
||||
public ILineAction Action { get; set; }
|
||||
|
||||
}
|
||||
public class LineFlexText : ILineFlexObject
|
||||
{
|
||||
public LineFlexText()
|
||||
{
|
||||
Size = FlexObjectSize.md;
|
||||
Weight = FlexObjectTextWeidht.Regular;
|
||||
}
|
||||
public LineFlexText(string text)
|
||||
{
|
||||
Text = text;
|
||||
Size = FlexObjectSize.md;
|
||||
Weight = FlexObjectTextWeidht.Regular;
|
||||
}
|
||||
public FlexObjectType Type => FlexObjectType.Text;
|
||||
[JsonRequired]
|
||||
public string Text { get; set; }
|
||||
public int Flex { get; set; }
|
||||
//public ILineAction Action { get; set; }
|
||||
//public FlexObjectButtonStype Style { get; set; }
|
||||
public FlexObjectSize Size { get; set; }
|
||||
public FlexObjectSize? OffsetTop { get; set; }
|
||||
public FlexObjectSize? OffsetBottom { get; set; }
|
||||
public FlexObjectSize? OffsetStart { get; set; }
|
||||
public FlexObjectSize? OffsetEnd { get; set; }
|
||||
|
||||
public FlexObjectTextWeidht Weight { get; set; }
|
||||
public string Color { get; set; }
|
||||
/// <summary>
|
||||
/// true to wrap text. The default value is false. If set to true, you can use a new line character (\n) to begin on a new line. For more information, see Wrapping text in the Messaging API documentation.
|
||||
/// </summary>
|
||||
public bool Wrap { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Style of the text. Specify one of these values: normal: Normal italic: Italic The default value is normal.
|
||||
/// </summary>
|
||||
public string Style { get; set; }
|
||||
/// <summary>
|
||||
/// Decoration of the text. Specify one of these values:
|
||||
// none: No decoration
|
||||
// underline: Underline
|
||||
// line-through: Strikethrough
|
||||
// The default value is none.
|
||||
/// </summary>
|
||||
public string Decoration { get; set; }
|
||||
/// <summary>
|
||||
/// start: Left-aligned, end: Right-aligned, center: Center-aligned(default value)
|
||||
/// </summary>
|
||||
public string Align { get; set; }
|
||||
}
|
||||
public class LineFlexSeparator : ILineFlexObject
|
||||
{
|
||||
public LineFlexSeparator()
|
||||
{
|
||||
Margin = FlexObjectSize.md;
|
||||
}
|
||||
public FlexObjectType Type => FlexObjectType.Separator;
|
||||
public FlexObjectSize Margin { get; set; }
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace LineMessaging
|
||||
{
|
||||
public class LineImageMessage : ILineMessage
|
||||
{
|
||||
[JsonProperty("type")]
|
||||
public MessageType Type => MessageType.Image;
|
||||
|
||||
[JsonProperty("originalContentUrl")]
|
||||
public string OriginalContentUrl { get; set; }
|
||||
|
||||
[JsonProperty("previewImageUrl")]
|
||||
public string PreviewImageUrl { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace LineMessaging
|
||||
{
|
||||
public class LineImagemapMessage : ILineMessage
|
||||
{
|
||||
[JsonProperty("type")]
|
||||
public MessageType Type => MessageType.Imagemap;
|
||||
|
||||
[JsonProperty("baseUrl")]
|
||||
public string BaseUrl { get; set; }
|
||||
|
||||
[JsonProperty("altText")]
|
||||
public string AltText { get; set; }
|
||||
|
||||
[JsonProperty("baseSize")]
|
||||
public LineSizeObject BaseSize { get; set; }
|
||||
|
||||
[JsonProperty("actions")]
|
||||
public IAction[] Actions { get; set; }
|
||||
|
||||
public interface IAction
|
||||
{
|
||||
[JsonProperty("type")]
|
||||
ActionType Type { get; }
|
||||
|
||||
[JsonProperty("area")]
|
||||
LineAreaBounds Area { get; set; }
|
||||
}
|
||||
|
||||
public class LinkActionObject : IAction
|
||||
{
|
||||
[JsonProperty("type")]
|
||||
public ActionType Type => ActionType.Uri;
|
||||
|
||||
[JsonProperty("linkUri")]
|
||||
public string LinkUri { get; set; }
|
||||
|
||||
[JsonProperty("area")]
|
||||
public LineAreaBounds Area { get; set; }
|
||||
}
|
||||
|
||||
public class MessageActionObject : IAction
|
||||
{
|
||||
[JsonProperty("type")]
|
||||
public ActionType Type => ActionType.Message;
|
||||
|
||||
[JsonProperty("text")]
|
||||
public string Text { get; set; }
|
||||
|
||||
[JsonProperty("area")]
|
||||
public LineAreaBounds Area { get; set; }
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace LineMessaging
|
||||
{
|
||||
public class LineLocationMessage : ILineMessage
|
||||
{
|
||||
[JsonProperty("type")]
|
||||
public MessageType Type => MessageType.Location;
|
||||
|
||||
[JsonProperty("title")]
|
||||
public string Title { get; set; }
|
||||
|
||||
[JsonProperty("address")]
|
||||
public string Address { get; set; }
|
||||
|
||||
[JsonProperty("latitude")]
|
||||
public double Latitude { get; set; }
|
||||
|
||||
[JsonProperty("longitude")]
|
||||
public double Longitude { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Converters;
|
||||
using System.Runtime.Serialization;
|
||||
|
||||
namespace LineMessaging
|
||||
{
|
||||
[JsonConverter(typeof(StringEnumConverter))]
|
||||
public enum MessageType
|
||||
{
|
||||
[EnumMember(Value = "text")]
|
||||
Text,
|
||||
|
||||
[EnumMember(Value = "image")]
|
||||
Image,
|
||||
|
||||
[EnumMember(Value = "video")]
|
||||
Video,
|
||||
|
||||
[EnumMember(Value = "audio")]
|
||||
Audio,
|
||||
|
||||
[EnumMember(Value = "file")]
|
||||
File,
|
||||
|
||||
[EnumMember(Value = "location")]
|
||||
Location,
|
||||
|
||||
[EnumMember(Value = "sticker")]
|
||||
Sticker,
|
||||
|
||||
[EnumMember(Value = "imagemap")]
|
||||
Imagemap,
|
||||
|
||||
[EnumMember(Value = "template")]
|
||||
Template,
|
||||
|
||||
[EnumMember(Value = "flex")]
|
||||
Flex
|
||||
}
|
||||
|
||||
[JsonConverter(typeof(StringEnumConverter))]
|
||||
public enum TemplateType
|
||||
{
|
||||
[EnumMember(Value = "buttons")]
|
||||
Buttons,
|
||||
|
||||
[EnumMember(Value = "confirm")]
|
||||
Confirm,
|
||||
|
||||
[EnumMember(Value = "carousel")]
|
||||
Carousel,
|
||||
|
||||
[EnumMember(Value = "image_carousel")]
|
||||
ImageCarousel,
|
||||
}
|
||||
|
||||
[JsonConverter(typeof(StringEnumConverter))]
|
||||
public enum ActionType
|
||||
{
|
||||
[EnumMember(Value = "postback")]
|
||||
Postback,
|
||||
|
||||
[EnumMember(Value = "message")]
|
||||
Message,
|
||||
|
||||
[EnumMember(Value = "uri")]
|
||||
Uri,
|
||||
|
||||
[EnumMember(Value = "datetimepicker")]
|
||||
Datetimepicker
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
using Newtonsoft.Json;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace LineMessaging
|
||||
{
|
||||
public class LineMulticastMessage
|
||||
{
|
||||
[JsonProperty("to")]
|
||||
public IEnumerable<string> To { get; set; }
|
||||
|
||||
[JsonProperty("messages")]
|
||||
public IEnumerable<ILineMessage> Messages { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
using Newtonsoft.Json;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace LineMessaging
|
||||
{
|
||||
public class LinePushMessage
|
||||
{
|
||||
[JsonProperty("to")]
|
||||
public string To { get; set; }
|
||||
|
||||
[JsonProperty("messages")]
|
||||
public IEnumerable<ILineMessage> Messages { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
using Newtonsoft.Json;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace LineMessaging
|
||||
{
|
||||
public class LineReplyMessage
|
||||
{
|
||||
[JsonProperty("replyToken")]
|
||||
public string ReplyToken { get; set; }
|
||||
|
||||
[JsonProperty("messages")]
|
||||
public IEnumerable<ILineMessage> Messages { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace LineMessaging
|
||||
{
|
||||
public class LineRichMenu
|
||||
{
|
||||
[JsonProperty("size")]
|
||||
public LineSizeObject Size { get; set; }
|
||||
|
||||
[JsonProperty("selected")]
|
||||
public bool Selected { get; set; }
|
||||
|
||||
[JsonProperty("name")]
|
||||
public string Name { get; set; }
|
||||
|
||||
[JsonProperty("charBarText")]
|
||||
public string CharBarText { get; set; }
|
||||
|
||||
[JsonProperty("areas")]
|
||||
public BoundsObject[] Areas { get; set; }
|
||||
|
||||
public class BoundsObject
|
||||
{
|
||||
[JsonProperty("bounds")]
|
||||
public LineAreaBounds Bounds { get; set; }
|
||||
|
||||
[JsonProperty("action")]
|
||||
public ILineAction Action { get; set; }
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace LineMessaging
|
||||
{
|
||||
public class LineRichMenuResponse : LineRichMenu
|
||||
{
|
||||
[JsonProperty("richMenuId")]
|
||||
public string RichMenuId { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace LineMessaging
|
||||
{
|
||||
public class LineSizeObject
|
||||
{
|
||||
[JsonProperty("width")]
|
||||
public int Width { get; set; }
|
||||
|
||||
[JsonProperty("height")]
|
||||
public int Height { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace LineMessaging
|
||||
{
|
||||
public class LineStickerMessage : ILineMessage
|
||||
{
|
||||
[JsonProperty("type")]
|
||||
public MessageType Type => MessageType.Sticker;
|
||||
|
||||
[JsonProperty("packageId")]
|
||||
public string PackageId { get; set; }
|
||||
|
||||
[JsonProperty("stickerId")]
|
||||
public string StickerId { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
using Newtonsoft.Json;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace LineMessaging
|
||||
{
|
||||
// Root myDeserializedClass = JsonConvert.DeserializeObject<Root>(myJsonResponse);
|
||||
|
||||
|
||||
public interface ITemplateObject
|
||||
{
|
||||
|
||||
[JsonProperty("type")]
|
||||
TemplateType Type { get; }
|
||||
}
|
||||
|
||||
public class ButtonTemplateObject : ITemplateObject
|
||||
{
|
||||
|
||||
public ButtonTemplateObject()
|
||||
{
|
||||
Actions = new List<ILineAction>();
|
||||
ImageSize = "cover";
|
||||
ImageBackgroundColor = "#FFFFFF";
|
||||
ImageAspectRatio = "rectangle";
|
||||
}
|
||||
[JsonProperty("type")]
|
||||
public TemplateType Type => TemplateType.Buttons;
|
||||
|
||||
[JsonProperty("thumbnailImageUrl")]
|
||||
public string ThumbnailImageUrl { get; set; }
|
||||
|
||||
[JsonProperty("imageAspectRatio")]
|
||||
public string ImageAspectRatio { get; set; }
|
||||
|
||||
[JsonProperty("imageSize")]
|
||||
public string ImageSize { get; set; }
|
||||
|
||||
[JsonProperty("imageBackgroundColor")]
|
||||
public string ImageBackgroundColor { get; set; }
|
||||
|
||||
[JsonProperty("title")]
|
||||
public string Title { get; set; }
|
||||
|
||||
[JsonProperty("text")]
|
||||
public string Text { get; set; }
|
||||
|
||||
[JsonProperty("defaultAction")]
|
||||
public ILineAction DefaultAction { get; set; }
|
||||
|
||||
[JsonProperty("actions")]
|
||||
public List<ILineAction> Actions { get; set; }
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace LineMessaging
|
||||
{
|
||||
public class LineTemplateMessage<T> : ILineMessage where T: ITemplateObject,new ()
|
||||
{
|
||||
public LineTemplateMessage()
|
||||
{
|
||||
Template = new T();
|
||||
}
|
||||
[JsonProperty("type")]
|
||||
public MessageType Type => MessageType.Template;
|
||||
|
||||
[JsonProperty("altText")]
|
||||
public string AltText { get; set; }
|
||||
|
||||
[JsonProperty("template")]
|
||||
public T Template { get; set; }
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
using Newtonsoft.Json;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace LineMessaging
|
||||
{
|
||||
public class LineTextMessage : ILineMessage
|
||||
{
|
||||
[JsonProperty("type")]
|
||||
public MessageType Type => MessageType.Text;
|
||||
|
||||
[JsonProperty("text")]
|
||||
public string Text { get; set; }
|
||||
[JsonProperty("emojis")]
|
||||
public List<Emoji> Emojis { get; set; }
|
||||
public void AddEmoji(int index, string productId, string emojiId)
|
||||
{
|
||||
if (Emojis == null) Emojis = new List<Emoji>();
|
||||
Emojis.Add(new Emoji()
|
||||
{
|
||||
Index = index,
|
||||
ProductId = productId,
|
||||
EmojiId = emojiId
|
||||
});
|
||||
}
|
||||
public void AddEmoji(int indexStart, int indexEnd, string productId, string emojiId)
|
||||
{
|
||||
if (Emojis == null) Emojis = new List<Emoji>();
|
||||
for (int i = indexStart; i < indexEnd; i++)
|
||||
{
|
||||
Emojis.Add(new Emoji()
|
||||
{
|
||||
Index = i,
|
||||
ProductId = productId,
|
||||
EmojiId = emojiId
|
||||
});
|
||||
}
|
||||
}
|
||||
public void AddEmoji(string replaceSymbol, string productId, string emojiId)
|
||||
{
|
||||
if (Emojis == null) Emojis = new List<Emoji>();
|
||||
this.Text = this.Text.Replace(replaceSymbol, "|");
|
||||
|
||||
foreach (var i in AllIndexesOf(this.Text, "|"))
|
||||
{
|
||||
Emojis.Add(new Emoji()
|
||||
{
|
||||
Index = i,
|
||||
ProductId = productId,
|
||||
EmojiId = emojiId
|
||||
});
|
||||
}
|
||||
this.Text = this.Text.Replace("|", "$");
|
||||
}
|
||||
private IEnumerable<int> AllIndexesOf(string str, string searchstring)
|
||||
{
|
||||
int minIndex = str.IndexOf(searchstring);
|
||||
while (minIndex != -1)
|
||||
{
|
||||
yield return minIndex;
|
||||
minIndex = str.IndexOf(searchstring, minIndex + searchstring.Length);
|
||||
}
|
||||
}
|
||||
}
|
||||
public class Emoji
|
||||
{
|
||||
[JsonProperty("index")]
|
||||
public int Index { get; set; }
|
||||
|
||||
[JsonProperty("productId")]
|
||||
public string ProductId { get; set; }
|
||||
|
||||
[JsonProperty("emojiId")]
|
||||
public string EmojiId { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace LineMessaging
|
||||
{
|
||||
public class LineVideoMessage : ILineMessage
|
||||
{
|
||||
[JsonProperty("type")]
|
||||
public MessageType Type => MessageType.Video;
|
||||
|
||||
[JsonProperty("originalContentUrl")]
|
||||
public string OriginalContentUrl { get; set; }
|
||||
|
||||
[JsonProperty("previewImageUrl")]
|
||||
public string PreviewImageUrl { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace LineMessaging
|
||||
{
|
||||
public interface ILineMessage
|
||||
{
|
||||
MessageType Type { get; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
using Newtonsoft.Json;
|
||||
using System;
|
||||
|
||||
namespace LineMessaging
|
||||
{
|
||||
public class LineOAuthTokenResponse
|
||||
{
|
||||
[JsonProperty("access_token")]
|
||||
public string AccessToken { get; set; }
|
||||
|
||||
[JsonProperty("expires_in")]
|
||||
public long UnixtimeExpiresIn { get; set; }
|
||||
|
||||
[JsonIgnore]
|
||||
public DateTime ExpiresIn
|
||||
{
|
||||
get { return UnixtimeExpiresIn.FromUnixTime(); }
|
||||
}
|
||||
|
||||
[JsonProperty("token_type")]
|
||||
public string TokenType { get; set; } = "Bearer";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace LineMessaging
|
||||
{
|
||||
public class LineOAuthErrorResponse
|
||||
{
|
||||
[JsonProperty("error")]
|
||||
public string Error { get; set; }
|
||||
|
||||
[JsonProperty("error_description")]
|
||||
public string Description { get; set; }
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return $"{Error}. description: {Description}.";
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Converters;
|
||||
using System.Runtime.Serialization;
|
||||
|
||||
namespace LineMessaging
|
||||
{
|
||||
[JsonConverter(typeof(StringEnumConverter))]
|
||||
public enum WebhookRequestEventType
|
||||
{
|
||||
[EnumMember(Value = "message")]
|
||||
Message,
|
||||
|
||||
[EnumMember(Value = "follow")]
|
||||
Follow,
|
||||
|
||||
[EnumMember(Value = "unfollow")]
|
||||
Unfollow,
|
||||
|
||||
[EnumMember(Value = "join")]
|
||||
Join,
|
||||
|
||||
[EnumMember(Value = "leave")]
|
||||
Leave,
|
||||
|
||||
[EnumMember(Value = "postback")]
|
||||
Postback,
|
||||
|
||||
[EnumMember(Value = "beacon")]
|
||||
Beacon
|
||||
}
|
||||
|
||||
[JsonConverter(typeof(StringEnumConverter))]
|
||||
public enum WebhookRequestSourceType
|
||||
{
|
||||
[EnumMember(Value = "user")]
|
||||
User,
|
||||
|
||||
[EnumMember(Value = "group")]
|
||||
Group,
|
||||
|
||||
[EnumMember(Value = "room")]
|
||||
Room
|
||||
}
|
||||
|
||||
[JsonConverter(typeof(StringEnumConverter))]
|
||||
public enum WebhookRequestBeaconType
|
||||
{
|
||||
[EnumMember(Value = "enter")]
|
||||
Enter,
|
||||
|
||||
[EnumMember(Value = "leave")]
|
||||
Leave,
|
||||
|
||||
[EnumMember(Value = "banner")]
|
||||
Banner
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,125 @@
|
||||
using Newtonsoft.Json;
|
||||
using System;
|
||||
|
||||
namespace LineMessaging
|
||||
{
|
||||
public class LineWebhookContent
|
||||
{
|
||||
[JsonProperty("events")]
|
||||
public Event[] Events { get; set; }
|
||||
|
||||
public class Event
|
||||
{
|
||||
[JsonProperty("type")]
|
||||
public WebhookRequestEventType Type { get; set; }
|
||||
|
||||
[JsonProperty("timestamp")]
|
||||
public long UnixTimestamp { get; set; }
|
||||
|
||||
[JsonIgnore]
|
||||
public DateTime Timestamp
|
||||
{
|
||||
get { return UnixTimestamp.FromUnixTime(); }
|
||||
}
|
||||
|
||||
[JsonProperty("replyToken")]
|
||||
public string ReplyToken { get; set; }
|
||||
|
||||
[JsonProperty("source")]
|
||||
public SourceObject Source { get; set; }
|
||||
|
||||
[JsonProperty("message")]
|
||||
public MessageObject Message { get; set; }
|
||||
|
||||
[JsonProperty("postback")]
|
||||
public PostbackObject Postback { get; set; }
|
||||
|
||||
[JsonProperty("beacon")]
|
||||
public BeaconObject Beacon { get; set; }
|
||||
|
||||
public class SourceObject
|
||||
{
|
||||
[JsonProperty("type")]
|
||||
public WebhookRequestSourceType Type { get; set; }
|
||||
|
||||
[JsonProperty("userId")]
|
||||
public string UserId { get; set; }
|
||||
|
||||
[JsonProperty("groupId")]
|
||||
public string GroupId { get; set; }
|
||||
|
||||
[JsonProperty("roomId")]
|
||||
public string RoomId { get; set; }
|
||||
}
|
||||
|
||||
public class MessageObject
|
||||
{
|
||||
[JsonProperty("id")]
|
||||
public long Id { get; set; }
|
||||
|
||||
[JsonProperty("type")]
|
||||
public MessageType Type { get; set; }
|
||||
|
||||
[JsonProperty("text")]
|
||||
public string Text { get; set; }
|
||||
|
||||
[JsonProperty("fileName")]
|
||||
public string FileName { get; set; }
|
||||
|
||||
[JsonProperty("fileSize")]
|
||||
public long? FileSize { get; set; }
|
||||
|
||||
[JsonProperty("title")]
|
||||
public string Title { get; set; }
|
||||
|
||||
[JsonProperty("address")]
|
||||
public string Address { get; set; }
|
||||
|
||||
[JsonProperty("latitude")]
|
||||
public double? Latitude { get; set; }
|
||||
|
||||
[JsonProperty("longitude")]
|
||||
public double? Longitude { get; set; }
|
||||
|
||||
[JsonProperty("packageId")]
|
||||
public string PackageId { get; set; }
|
||||
|
||||
[JsonProperty("stickerId")]
|
||||
public string StickerId { get; set; }
|
||||
}
|
||||
|
||||
public class PostbackObject
|
||||
{
|
||||
[JsonProperty("data")]
|
||||
public string Data { get; set; }
|
||||
|
||||
[JsonProperty("params")]
|
||||
public PostbackParams Params { get; set; }
|
||||
|
||||
public class PostbackParams
|
||||
{
|
||||
[JsonProperty("date")]
|
||||
public string Date { get; set; }
|
||||
|
||||
[JsonProperty("time")]
|
||||
public string Time { get; set; }
|
||||
|
||||
[JsonProperty("datetime")]
|
||||
public string Datetime { get; set; }
|
||||
}
|
||||
}
|
||||
|
||||
public class BeaconObject
|
||||
{
|
||||
[JsonProperty("hwid")]
|
||||
public string HardwareId { get; set; }
|
||||
|
||||
[JsonProperty("type")]
|
||||
public WebhookRequestBeaconType Type { get; set; }
|
||||
|
||||
[JsonProperty("dm")]
|
||||
public string DeviceMessage { get; set; }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user