You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

1409 lines
59 KiB

using log4net;
using CounsellorBL.Helper;
using MonumentDefine;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using OT.COM.ArsenalDB;
using SoldierData.EnterprizeV4;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using static MonumentDefine.Enums;
using System.Text;
using GroupBuyParser;
namespace CounsellorBL.Helper
{
/// <summary>
/// 類別名稱:Mailer
/// 類別說明:
/// 起始作者:
/// 起始日期:
/// 最新修改人:
/// 最新修改日:
/// </summary>
public class FbRestHelper : DBService
{
private static ILog _inst = null;
private static ILog Logger
{
get
{
if (_inst == null)
{
_inst = LogManager.GetLogger(typeof(FbRestHelper));
}
return _inst;
}
}
public override string MainTable => null;
#region 類別
/// <summary>
/// Fb留言資料
/// </summary>
private class FbCommentData
{
public List<data> data { get; set; }
public JObject paging { get; set; }
}
private class data
{
public DateTime created_time { get; set; }
public from from { get; set; }
public string message { get; set; }
public string id { get; set; }
public parent parent { get; set; }
public int comment_count { get; set; }
}
private class from
{
public string name { get; set; }
public string id { get; set; }
public Picture picture { get; set; }
public class Picture
{
public PictureData data { get; set; }
public class PictureData
{
public string url { get; set; }
}
}
}
private class parent
{
public string id { get; set; }
}
/// <summary>
/// Fb 延長token
/// </summary>
private class FbToken
{
public string access_token { get; set; }
public string type { get; set; }
}
/// <summary>
/// Fb token 驗證
/// </summary>
public class FbTokenVerification
{
public VerificationContent data { get; set; }
}
public class VerificationContent
{
public string app_id { get; set; }
public string type { get; set; }
public int data_access_expires_at { get; set; }
//public error error { get; set; }
public int expires_at { get; set; }
public bool is_valid { get; set; }
public string user_id { get; set; }
}
private class error
{
public int code { get; set; }
public string message { get; set; }
public int subcode { get; set; }
}
/// <summary>
/// FB API get token response information
/// </summary>
public class FbGetTokenEntity
{
public string access_token { get; set; }
public string token_type { get; set; }
public string expires_in { get; set; }
}
APIURLHelper ApiUrlHelper = new APIURLHelper();
/// <summary>
/// fb 貼文
/// </summary>
public class FbGetPost
{
public List<FbGetPostdata> data { get; set; }
public JObject paging { get; set; }
}
public class FbGetPostdata
{
public string id { get; set; }
public string message { get; set; }
public string full_picture { get; set; }
public string source { get; set; }
public DateTime updated_time { get; set; }
public DateTime created_time { get; set; }
}
public class UserInfo
{
public string name { get; set; }
public string email { get; set; }
public string link { get; set; }
public string birthday { get; set; }
public string gender { get; set; }
public Picture picture { get; set; }
public string id { get; set; }
public class Picture
{
public PictureData data { get; set; }
public class PictureData
{
public string url { get; set; }
}
}
}
public class PushPost
{
public string id { get; set; }
}
#endregion
public enum CommentStatus
{
/// <summary>
/// 無問題 (綠)
/// </summary>
OK = 1,
/// <summary>
/// 有問題【無數量】【無分店】【無產品】【數字有更新】 (紅)
/// </summary>
InvalidFormat = 2,
/// <summary>
/// 會員無登入系統 (橘)
/// </summary>
UnknownMember = 3,
/// <summary>
/// 黑名單或其他回覆的留言 (黑)
/// </summary>
Duplicate = 4,
/// <summary>
/// 已轉成訂單,不顯示其中
/// </summary>
TransferOrder = 9
}
class CommentModel
{
public string uid { get; set; }
public string group_user_id { get; set; }
public string comment { get; set; }
public DateTime comment_time { get; set; }
}
#region FbAPI
// 針對應用程式 可以使用{應用程式ID}|{應用程式密鑰}
/// <summary>
/// 上傳貼文的POST
/// </summary>
/// <param name="authorizationToken"></param>
/// <param name="message"></param>
/// <param name="path">圖片路徑</param>
public string CallFbPostPushAPI(string authorizationToken, string message, string groupId, List<string> path, out string o_sPostFBID)
{
string sMsg = null;
string sPostFBID = null;
Logger.Info($"CallFbPostPushAPI start groupId={groupId}");
if (path != null)
{
path.ForEach(p =>
{
Logger.Info($"CallFbPostPushAPI path={p}");
});
}
try
{
do
{
// 送出資料
string uri = string.Format("https://graph.facebook.com/v8.0/{0}/feed", groupId);
var lsData = new List<APIHelper.DataContent>()
{
new APIHelper.DataContent { Key = "access_token" , Type = typeof(StringContent) , Content = authorizationToken },
new APIHelper.DataContent { Key = "message", Type = typeof(StringContent), Content = message },
new APIHelper.DataContent { Key = "published", Type = typeof(StringContent), Content = "false" }
};
Logger.Info($"CallFbPostPushAPI f2 uri={uri}");
if (path != null && path.Any())
{
int i = 0;
path.ForEach(x =>
{
if (x != null)
{
lsData.Add(new APIHelper.DataContent { Key = $"attached_media[{i}]", Type = typeof(StringContent), Content = "{\"media_fbid\":" + x + "}" });
}
i++;
});
}
Logger.Info($"CallFbPostPushAPI f3 uri={uri}");
sMsg = APIHelper.BasePost(uri, null, lsData, out HttpResponseMessage responseMessage);
if (sMsg != null)
{
Logger.Error(sMsg);
break;
}
Logger.Info($"CallFbPostPushAPI responseMessage.IsSuccessStatusCode = {responseMessage.IsSuccessStatusCode}");
if (responseMessage.IsSuccessStatusCode)
{
var fb_error = GetFbApiError(responseMessage);
if (!string.IsNullOrWhiteSpace(fb_error))
{
sMsg = fb_error;
Logger.Error($"CallFbPostPushAPI f7");
Logger.Error($"CallFbPostPushAPI sMsg={sMsg}");
break;
}
Logger.Info($"CallFbPostPushAPI f6");
string sContent = responseMessage.Content.ReadAsStringAsync().Result;
Logger.Info($"CallFbPostPushAPI f6 sContent={sContent}");
sPostFBID = JsonConvert.DeserializeObject<PushPost>(sContent).id;
Logger.Info($"CallFbPostPushAPI f6 sPostFBID={sPostFBID}");
}
else
{
Logger.Error($"CallFbPostPushAPI f7");
sMsg = JsonConvert.SerializeObject(responseMessage);
Logger.Error($"CallFbPostPushAPI sMsg={sMsg}");
break;
}
}
while (false);
}
catch (Exception ex)
{
sMsg = ex.Message;
Logger.Error($"Exception={sMsg}");
}
o_sPostFBID = sPostFBID;
Logger.Info($"CallFbPostPushAPI end groupId={groupId}");
return sMsg;
}
/// <summary>
/// 上傳圖片的POST
/// </summary>
/// <param name="authorizationToken"></param>
/// <param name="message"></param>
/// <param name="path">圖片路徑</param>
public string CallFbPicturePushAPI(string authorizationToken, string groupId, string path, out string o_sPicID)
{
string sMsg = null;
string sPicID = null;
Logger.Info($"CallFbPicturePushAPI start groupId={groupId} path={path}");
try
{
do
{
// 送出資料
//string uri = string.Format("https://graph.facebook.com/v7.0/{0}/photos", groupId);
//Logger.Info($"CallFbPicturePushAPI uri = {uri}");
//var lsData = new List<APIHelper.DataContent>()
//{
// new APIHelper.DataContent { Key = "access_token" , Type = typeof(StringContent) , Content = authorizationToken },
// new APIHelper.DataContent { Key = "url", Type = typeof(StringContent), Content = path },
// new APIHelper.DataContent { Key = "published", Type = typeof(StringContent), Content = "false" },
// new APIHelper.DataContent { Key = "attempt", Type = typeof(StringContent), Content = "3" }
//};
// 送出資料
string uri = string.Format("https://graph.facebook.com/v7.0/{0}/photos?access_token={1}", groupId, authorizationToken);
Logger.Info($"CallFbPicturePushAPI uri = {uri}");
var lsData = new List<APIHelper.DataContent>()
{
//new APIHelper.DataContent { Key = "access_token" , Type = typeof(StringContent) , Content = authorizationToken },
new APIHelper.DataContent { Key = "url", Type = typeof(StringContent), Content = path },
new APIHelper.DataContent { Key = "published", Type = typeof(StringContent), Content = "false" },
new APIHelper.DataContent { Key = "attempt", Type = typeof(StringContent), Content = "3" },
new APIHelper.DataContent { Key = "suppress_http_code", Type = typeof(StringContent), Content = "1" },
new APIHelper.DataContent { Key = "format", Type = typeof(StringContent), Content = "json" },
new APIHelper.DataContent { Key = "pretty", Type = typeof(StringContent), Content = "0" },
//new APIHelper.DataContent { Key = "debug", Type = typeof(StringContent), Content = "all" },
new APIHelper.DataContent { Key = "transport", Type = typeof(StringContent), Content = "cors" },
};
sMsg = APIHelper.BasePost(uri, null, lsData, out HttpResponseMessage responseMessage);
if (sMsg != null)
{
Logger.Error($"CallFbPicturePushAPI uri = {uri} sMsg={sMsg}");
break;
}
if (responseMessage.IsSuccessStatusCode)
{
var fb_error = GetFbApiError(responseMessage);
if (!string.IsNullOrWhiteSpace(fb_error))
{
sMsg = fb_error;
Logger.Error($"CallFbPicturePushAPI f7");
Logger.Error($"CallFbPicturePushAPI sMsg={sMsg}");
break;
}
string sContent = responseMessage.Content.ReadAsStringAsync().Result;
Logger.Info($"CallFbPicturePushAPI sContent={sContent}");
sPicID = JsonConvert.DeserializeObject<PushPost>(sContent).id;
Logger.Info($"CallFbPicturePushAPI sPicID={sPicID}");
}
else
{
Logger.Error($"CallFbPicturePushAPI f7");
sMsg = JsonConvert.SerializeObject(responseMessage);
Logger.Error($"CallFbPicturePushAPI sMsg={sMsg}");
break;
}
}
while (false);
}
catch (Exception ex)
{
sMsg = ex.Message;
Logger.Error($"CallFbPicturePushAPI exception={sMsg}");
}
o_sPicID = sPicID;
Logger.Info($"CallFbPicturePushAPI end groupId={groupId} path={path} sResult={sPicID}");
return sMsg;
}
/// <summary>
/// 貼文的Get(抓貼文、圖片、影片)
/// </summary>
/// <param name="authorizationToken"></param>
/// <param name="message"></param>
/// <param name="path">圖片路徑</param>
public bool CallFbPostGetAPI(string authorizationToken, string groupId)
{
// 送出資料 取1000筆資料
string uri = string.Format("https://graph.facebook.com/v7.0/{0}/feed?fields=full_picture,message,source,updated_time,created_time&limit=1000&", groupId);
var dicData = new Dictionary<string, string>()
{
{ "access_token", authorizationToken }
};
APIHelper.BaseGet(uri, null, dicData, out HttpResponseMessage responseMessage);
if (responseMessage.IsSuccessStatusCode)
{
GetFbPostData(JsonConvert.DeserializeObject<FbGetPost>(responseMessage.Content.ReadAsStringAsync().Result));
}
return responseMessage.IsSuccessStatusCode;
}
/// <summary>
/// 貼文的Get(抓貼文、圖片、影片)
/// </summary>
/// <param name="authorizationToken"></param>
/// <param name="message"></param>
/// <param name="path">圖片路徑</param>
public string CallFbGetInformation(string authorizationToken, out UserInfo userInfo)
{
userInfo = null;
string sMsg = null;
do
{
try
{
// 送出資料 取1000筆資料
string uri = "https://graph.facebook.com/v7.0/me";
var dicData = new Dictionary<string, string>()
{
{ "access_token", authorizationToken },
{ "fields","name,email,link,picture.type(normal),birthday,gender"}
};
var lsData = new List<APIHelper.DataContent>()
{
//new APIHelper.DataContent { Key = "access_token" , Type = typeof(StringContent) , Content = authorizationToken },
new APIHelper.DataContent { Key = "access_token", Type = typeof(StringContent), Content = authorizationToken },
new APIHelper.DataContent { Key = "fields", Type = typeof(StringContent), Content = "name,email,link,picture.type(normal),birthday,gender" },
};
sMsg = APIHelper.BasePost(uri, null, lsData, out HttpResponseMessage responseMessage);
if (responseMessage.IsSuccessStatusCode)
{
sMsg = GetFbApiError(responseMessage);
if (!string.IsNullOrWhiteSpace(sMsg))
{
break;
}
userInfo = JsonConvert.DeserializeObject<UserInfo>(responseMessage.Content.ReadAsStringAsync().Result);
}
}
catch (Exception ex)
{
throw ;
}
} while (false);
return sMsg;
}
/// <summary>
/// 貼文的Get(抓貼文、圖片、影片)
/// </summary>
/// <param name="authorizationToken"></param>
/// <param name="message"></param>
/// <param name="path">圖片路徑</param>
public FbGetPost CallFbPostGetDataAPI(string authorizationToken, string groupId, int grabDate_ = 0)
{
if (grabDate_ == 0 || grabDate_ > 30)
grabDate_ = 30;// 30日為預設天數
// 送出資料 撈取30天內之文章 並重複取至無資料
string uri = string.Format("https://graph.facebook.com/v7.0/{0}/feed?fields=full_picture,message,source,updated_time,created_time&limit=100&since={1}&",
groupId,
DateTime.Now.AddDays(-grabDate_).ToString("yyyy-MM-dd")
);
FbGetPost rawResult = null;
FbGetPost result = new FbGetPost() { data = new List<FbGetPostdata>(), paging = new JObject() };
bool isOver = false;
var dicData = new Dictionary<string, string>()
{
{ "access_token", authorizationToken }
};
while (!isOver)
{
APIHelper.BaseGet(uri, null, dicData, out HttpResponseMessage responseMessage);
if (responseMessage.IsSuccessStatusCode)
{
rawResult = JsonConvert.DeserializeObject<FbGetPost>(responseMessage.Content.ReadAsStringAsync().Result);
result.data.AddRange(rawResult.data);
uri = rawResult.paging != null ? rawResult.paging["next"].ToString() : null;
if (rawResult.data.Count == 0)
{
isOver = true;
}
}
else
{
isOver = true;
}
}
return result;
}
/// <summary>
/// 貼文的Get(抓單篇貼文)
/// </summary>
/// <param name="authorizationToken"></param>
/// <param name="message"></param>
/// <param name="path">圖片路徑</param>
public FbGetPostdata CallSingleFbPostGetDataAPI(string authorizationToken, string postId)
{
string uri = string.Format("https://graph.facebook.com/v7.0/{0}?fields=created_time&", postId);
FbGetPost result = new FbGetPost() { data = new List<FbGetPostdata>(), paging = new JObject() };
var dicData = new Dictionary<string, string>()
{
{ "access_token", authorizationToken }
};
FbGetPostdata rawResult = null;
APIHelper.BaseGet(uri, null, dicData, out HttpResponseMessage responseMessage);
if (responseMessage.IsSuccessStatusCode)
{
rawResult = JsonConvert.DeserializeObject<FbGetPostdata>(responseMessage.Content.ReadAsStringAsync().Result);
}
return rawResult;
}
/// <summary>
/// 取回留言的Get
/// </summary>
/// <param name="authorizationToken"></param>
/// <param name="message"></param>
/// <param name="path">圖片路徑</param>
public bool CallFbCommentGetAPI(string articleId, string authorizationToken, string postId, out List<tb_grp_comment> comments)
{
// 送出資料
string uri = string.Format("https://graph.facebook.com/v7.0/{0}/comments?filter=stream&fields={1}&access_token={2}&limit={3}", postId, "id,created_time,from{name,id,picture},message,parent,comment_count", authorizationToken, "150");
FbCommentData rawResult = null;
FbCommentData result = new FbCommentData() { data = new List<data>(), paging = new JObject() };
bool isOver = false;
while (!isOver)
{
APIHelper.BaseGet(uri, null, new Dictionary<string, string>(), out HttpResponseMessage responseMessage);
if (responseMessage.IsSuccessStatusCode)
{
var fb_error = GetFbApiError(responseMessage);
if (!string.IsNullOrWhiteSpace(fb_error))
{
Logger.Error($"{nameof(CallFbCommentGetAPI)} FB API response error message: {fb_error} ");
}
rawResult = JsonConvert.DeserializeObject<FbCommentData>(responseMessage.Content.ReadAsStringAsync().Result);
result.data.AddRange(rawResult.data);
uri = rawResult.paging != null && rawResult.paging.ContainsKey("next") ? rawResult.paging["next"].ToString() : null;
if (rawResult.data.Count == 0 || uri == null)
{
isOver = true;
}
}
else
{
var error = $"{nameof(CallFbCommentGetAPI)} Error, ReasonPhrase:{responseMessage.ReasonPhrase} hrmResult.Headers.WwwAuthenticate:{responseMessage.Headers.WwwAuthenticate} ";
Logger.Error(error);
isOver = true;
}
}
if (result.data.Count > 0)
{
string sMsg = GetFCommentsData(articleId, result, postId, out comments);
// 儲存出錯
if (sMsg != null)
{
comments = null;
}
}
else
{
comments = null;
}
return true;
}
/// <summary>
/// 延長token
/// </summary>
/// <param name="authorizationToken"></param>
/// <param name="message"></param>
/// <param name="path">圖片路徑</param>
public bool CallFbLongTokenGetAPI(string authorizationToken, string client_id, string client_secret)
{
// 送出資料
string uri = "https://graph.facebook.com/oauth/access_token?";
var dicData = new Dictionary<string, string>()
{
{ "grant_type", "fb_exchange_token" },
{ "client_id", client_id },
{ "client_secret", client_secret },
{ "fb_exchange_token", authorizationToken },
};
APIHelper.BaseGet(uri, null, dicData, out HttpResponseMessage responseMessage);
if (responseMessage.IsSuccessStatusCode)
{
var responseData = JsonConvert.DeserializeObject<FbToken>(responseMessage.Content.ReadAsStringAsync().Result);
}
return responseMessage.IsSuccessStatusCode;
}
/// <summary>
/// 驗證token, 可改用 Function FbApiCheckToken
/// </summary>
/// <param name="authorizationToken"></param>
/// <param name="message"></param>
/// <param name="path">圖片路徑</param>
public string CallFbCheckTokenGetAPI(string authorizationToken, string client_id, string client_secret, out int status)
{
// 送出資料
status = 0; // 預設0: 正常 1: 即將到期 2: 驗證失敗
string uri = "https://graph.facebook.com/debug_token?";
var dicData = new Dictionary<string, string>()
{
{ "input_token", authorizationToken },
{ "access_token", string.Format("{0}|{1}",client_id,client_secret) },
};
APIHelper.BaseGet(uri, null, dicData, out HttpResponseMessage responseMessage);
if (responseMessage.IsSuccessStatusCode)
{
var responseData = JsonConvert.DeserializeObject<FbTokenVerification>(responseMessage.Content.ReadAsStringAsync().Result);
if (responseData.data.is_valid)
{
var timeStamp = responseData.data.expires_at - Convert.ToInt32(DateTime.UtcNow.AddHours(8).Subtract(new DateTime(1970, 1, 1)).TotalSeconds);
if (timeStamp > 20 * 86400) // 20天
{
return null;
}
else
{
status = 1;
return "Token即將到期";
}
}
else
{
status = 2;
return "Token驗證失敗";
}
}
else
{
status = 2;
return "Request失敗";
}
}
/// <summary>
/// Send FB Message
/// </summary>
/// <param name="messenger_id_"></param>
/// <param name="message_"></param>
/// <param name="access_token_"></param>
/// <param name="errorHandle_"></param>
/// <returns></returns>
public void SendMessage(ref string messenger_id_, ref string message_, ref string access_token_, Action<HttpResponseMessage> successHandle_, Action<HttpResponseMessage, string> errorHandle_)
{
string url = ApiUrlHelper.SendMessage(access_token_);
var dataContents = new
{
recipient = new { id = messenger_id_ },
messaging_type = "MESSAGE_TAG",
message = new { text = message_ },
tag = "POST_PURCHASE_UPDATE"
};
SendPostFbApi(url, dataContents, successHandle_, errorHandle_);
}
/// <summary>
///
/// </summary>
/// <returns></returns>
public void CheckAccessToken(ref string access_token_, Action<HttpResponseMessage> successHandle_, Action<HttpResponseMessage, string> errorHandle_)
{
string url = ApiUrlHelper.CheckAccessToken(access_token_);
SendGetFbApi(url, successHandle_, errorHandle_);
}
public void GetUserAccessToken(ref string user_access_token_, ref string app_id_, ref string app_secret_, Action<HttpResponseMessage> successHandle_, Action<HttpResponseMessage, string> errorHandle_)
{
string url = ApiUrlHelper.GetUserAccessToken(user_access_token_, app_id_, app_secret_);
SendGetFbApi(url, successHandle_, errorHandle_);
}
public void GetPageAccessToken(ref string user_id_, ref string long_lived_user_access_token, Action<HttpResponseMessage> successHandle_, Action<HttpResponseMessage, string> errorHandle_)
{
string url = ApiUrlHelper.GetPageAccessToken(user_id_, long_lived_user_access_token);
SendGetFbApi(url, successHandle_, errorHandle_);
}
#endregion
#region 專案獨有
///// <summary>
///// 貼文資料新增到SQL
///// </summary>
///// <param name="state"></param>
///// <returns></returns>
private void GetFbPostData(FbGetPost fbGetPost)
{
ArsenalInterface ai;
List<Command> lCmds = new List<Command>();
// 取社團
QueryJsonElementCollection lBlocks = new QueryJsonElementCollection();
QueryJsonElement qjeOrigin = lBlocks.GetInst();
qjeOrigin.table = tb_grp_group.TABLENAME;
qjeOrigin.displaycols = new List<string>() { tb_grp_group.CN_UID, tb_grp_group.CN_FB_GROUP_ID };
qjeOrigin.wherecols = new WhereNode(tb_grp_group.CN_FB_GROUP_ID, WhereNode.EColumnOperation.EOT_EQ, typeof(tb_grp_group), fbGetPost.data[0].id.Split("_")[0]);
lBlocks.Add(qjeOrigin);
var sMsg = MakeSelectJoinByBlocks(lBlocks, out Command cRes);
ai = ArsenalDBMgr.GetInst(cRes);
List<tb_grp_group> group = ai.RunQueryList<tb_grp_group>(cRes);
// 取貼文資料
lBlocks.Clear();
QueryJsonElement qjeArticle = lBlocks.GetInst();
qjeArticle.table = tb_grp_article.TABLENAME;
qjeArticle.displaycols = new List<string>() { tb_grp_article.CN_UID, tb_grp_article.CN_GROUP_UID, tb_grp_article.CN_FB_ARTICLE_ID };
qjeArticle.wherecols = new WhereNode(tb_grp_article.CN_GROUP_UID, WhereNode.EColumnOperation.EOT_EQ, typeof(tb_grp_article), group.First().uid);
lBlocks.Add(qjeArticle);
sMsg = MakeSelectJoinByBlocks(lBlocks, out Command cArt);
ai = ArsenalDBMgr.GetInst(cArt);
List<tb_grp_article> article = ai.RunQueryList<tb_grp_article>(cArt);
// 取媒體資料
lBlocks.Clear();
QueryJsonElement qjeArticleMedia = lBlocks.GetInst();
qjeArticleMedia.table = tb_grp_article_media.TABLENAME;
qjeArticleMedia.displaycols = new List<string>() { tb_grp_article_media.CN_UID, tb_grp_article_media.CN_ARTICLE_UID, tb_grp_article_media.CN_MEDIA_ID, tb_grp_article_media.CN_URI };
lBlocks.Add(qjeArticleMedia);
sMsg = MakeSelectJoinByBlocks(lBlocks, out Command cMedia);
ai = ArsenalDBMgr.GetInst(cMedia);
List<tb_grp_article_media> lsmedia = ai.RunQueryList<tb_grp_article_media>(cMedia);
fbGetPost.data.ForEach(x =>
{
var uid = string.Empty;
// 如果貼文存在則更新 否則新增
if (!article.Any(y => y.fb_article_id == x.id))
{
uid = Guid.NewGuid().ToString();
tb_grp_article cNew = new tb_grp_article()
{
uid = uid,
group_uid = group.First().uid,
message = x.message,
post_status = (int)EPostStatus.EPS_FETCH_FROM_FB,
fb_article_id = x.id,
release_date = x.created_time
};
lCmds.Add(Command.SetupInsertCmd(cNew));
}
else
{
uid = article.First(y => y.fb_article_id == x.id).uid;
tb_grp_article cWhere = new tb_grp_article() { uid = uid };
tb_grp_article cUpdate = new tb_grp_article()
{
group_uid = group.First().uid,
message = x.message,
post_status = (int)EPostStatus.EPS_FETCH_FROM_FB,
fb_article_id = x.id,
release_date = x.created_time
};
lCmds.Add(Command.SetupUpdateCmd(cUpdate, cWhere));
}
if (!lsmedia.Any(y => y.uri == x.full_picture) && x.full_picture != null)
{
tb_grp_article_media media = new tb_grp_article_media()
{
article_uid = uid,
uri = x.full_picture,
type = BLWording.MediaType.Photo,
status_flag = (int)MediaType.GetFb
};
lCmds.Add(Command.SetupInsertCmd(media));
}
if (!lsmedia.Any(y => y.uri == x.full_picture) && x.source != null)
{
tb_grp_article_media media = new tb_grp_article_media()
{
article_uid = uid,
uri = x.source,
type = BLWording.MediaType.Video,
status_flag = (int)MediaType.GetFb
};
lCmds.Add(Command.SetupInsertCmd(media));
}
});
if (lCmds.Any())
{
ai = ArsenalDBMgr.GetInst(lCmds[0], GetDefaultSystemColumnInfo());
ai.RunEditCmds(lCmds);
sMsg = GetLastErrorCode(lCmds);
}
}
/// <summary>
/// 貼文留言存進SQL
/// </summary>
/// <param name="fbGetPost"></param>
/// <param name="id"></param>
private string GetFCommentsData(string articleId, FbCommentData fbGetPost, string post_id, out List<tb_grp_comment> comments)
{
// 沒有留言
if (fbGetPost.data.Count == 0)
{
comments = null;
return null;
}
List<Command> lCmds = new List<Command>();
// 用文章 ID取文章 data
var article = GetArticleByPostID(articleId);
comments = new List<tb_grp_comment>();
// 取回原先的留言
List<tb_grp_comment> originComments = GetComments(article.uid);
// 如果先前已有匯入留言,已匯入過的留言不再重複匯入
List<string> existFbCommentID = originComments.Select(x => x.fb_comment_id).ToList();
// 取回該社團可以取貨的地點
var branches = GetBranches(article.group_uid).ToDictionary(x => x.uid, x => x.branch_name);
var products = GetProducts(article.uid);
// 會員預設取貨地點(中文)的對應表,沒設定取貨地點不會放進列表
var memberDefaultBranchDict = GetMembers(post_id.Split('_')[0])
.Where(x => !string.IsNullOrEmpty(x.default_branch) && branches.ContainsKey(x.default_branch))
.ToDictionary(x => x.group_user_id, x => branches[x.default_branch]);
// 將名稱以['A', 'B'...]這樣依序產生,如果產品有3個,就要放入['A', 'B', 'C']
List<GroupBuyParser.ProductInfo> productInfoNames = new List<GroupBuyParser.ProductInfo>();
//productInfoNames = products.Select((x, i) => new GroupBuyParser.ProductInfo
//{
// Name = x.name ?? "",
// Specifications = string.IsNullOrEmpty(x.specification) ? null : x.specification.Split(',', StringSplitOptions.RemoveEmptyEntries)
//}).ToList();
var productInfos = products.Select((x, i) => new GroupBuyParser.ProductInfo
{
Name = ((char)('A' + x.seq)).ToString(),
Specifications = string.IsNullOrEmpty(x.specification) ? null : x.specification.Split(',', StringSplitOptions.RemoveEmptyEntries).OrderByDescending(x => x.Count()).ToArray()
}).ToList();
//var productInfos = productInfoNames.Concat(productInfosChar).ToList();
Logger.Info($"開始解析貼文 文章ID: {article.uid} 設定: {JsonConvert.SerializeObject(productInfos)}");
var parser = new GroupBuyParser.GroupBuyParser
{
Settings = new GroupBuyParser.ParserSettings
{
Products = productInfos,
Branches = branches.Values.ToList()
}
};
StringBuilder parseCommentErrorLog = new StringBuilder();
foreach (var item in fbGetPost.data)
{
// 沒有留言就不處理
if (string.IsNullOrEmpty(item.message))
{
continue;
}
// 判斷已經重複的ID
if (existFbCommentID.Contains(item.id))
{
continue;
}
// 判斷是否為回覆留言
string parentUid = null;
if (item.parent != null)
{
parentUid = item.parent.id;
}
// 如果取不回fb_id(使用者沒有允許應用程式查看貼文)仍要處理
string group_user_id = item.from?.id;
string json = "";
int status = 0;
// 傳入該會員預設取貨地點(非會員則為null)
string defaultBranch = null;
if (!string.IsNullOrEmpty(group_user_id) && memberDefaultBranchDict.ContainsKey(group_user_id))
{
defaultBranch = memberDefaultBranchDict[group_user_id];
}
var parseData = new GroupBuyParser.ParserData
{
Text = item.message,
DefaultBranch = defaultBranch
};
parser.Parse(parseData);
if (parseData.Success)
{
bool isProductCorrect = true;
foreach (var product in parseData.Product.ToList())
{
if (product.Name == "I")
{
isProductCorrect = false;
break;
}
}
if (isProductCorrect) // 名稱有I 不Insert進資料庫
{
json = JsonConvert.SerializeObject(parseData.Product);
status = (int)CommentStatus.OK;
}
else
{
status = (int)CommentStatus.InvalidFormat;
}
}
else
{
status = (int)CommentStatus.InvalidFormat;
// 增加log紀錄確認解析失敗的原因
parseCommentErrorLog.AppendLine($"解析貼文失敗 姓名: {item.from?.name} 內容: {item.message} 原因: {parseData.ErrorMessage}");
}
if (string.IsNullOrEmpty(group_user_id))
{
status = (int)CommentStatus.UnknownMember;
}
else if (!memberDefaultBranchDict.ContainsKey(group_user_id))
{
status = (int)CommentStatus.UnknownMember;
}
else if (comments.Any(x => x.group_user_id == group_user_id)) // 是否有重複留言
{
status = (int)CommentStatus.Duplicate;
}
if (parentUid != null)
{
status = (int)CommentStatus.Duplicate;
}
tb_grp_comment cNew = new tb_grp_comment
{
uid = Guid.NewGuid().ToString(),
article_uid = article.uid,
origin_comment = item.message,
comment = json,
group_user_id = group_user_id,
comment_time = item.created_time,
fb_comment_id = item.id,
status = status,
user_name = item.from?.name,
user_picture = item.from?.picture.data.url,
parent_comment_id = parentUid == null ? null : parentUid
};
comments.Add(cNew);
}
if (parseCommentErrorLog.Length != 0)
{
// 參考原本寫法, 解析貼文失敗訊息標記為Info
parseCommentErrorLog.Insert(0, Environment.NewLine);
Logger.Info(parseCommentErrorLog.ToString());
}
// 沒有新增任何留言就不處理
if (comments.Count == 0)
{
return null;
}
lCmds.AddRange(comments.Select(x => Command.SetupInsertCmd(x)));
var ai = ArsenalDBMgr.GetInst(lCmds[0], GetDefaultSystemColumnInfo());
ai.RunEditCmds(lCmds);
var sMsg = GetLastErrorCode(lCmds);
return sMsg;
}
/// <summary>
/// 將留言轉成訂單(結單)
/// </summary>
/// <param name="article_uid"></param>
public string CheckOrder(string article_uid, JArray jData)
{
// 貼文資料
var article = GetArticle(article_uid);
// 商品資料
var productData = GetProducts(article_uid).OrderBy(x => x.seq).ToArray();
// 貼文對應的群組UID
var groupUid = article.group_uid;
// 取得社團成員ID對應的UID
var fb_group_id = article.fb_article_id.Split('_')[0];
var memberDict = GetMembers(fb_group_id).ToDictionary(x => x.group_user_id, x => x.uid);
// 分店的對應表
var branchDict = GetBranches(groupUid).ToDictionary(x => x.branch_name, x => x.uid);
// 取回過去的訂單主檔
var IsOrderMaster = GetOrderMasters(article_uid);
// 如果過去已經有結單,使用同一個order_code,反之取回新的訂單編號(這不就是article_uid嗎?)
var orderCode = IsOrderMaster.Any() ? IsOrderMaster.First().order_code : GetOrderCode();
var orderName = IsOrderMaster.Any() ? IsOrderMaster.First().name : article.name; // 有結單過的貼文使用舊名稱
var orderMasterDic = new Dictionary<string, tb_ord_order_master>();
// 再次結單屬於新的order_master
// 先取回所有留言
var comments = GetComments(article_uid);
// 留言解析成功的才更新
List<CommentModel> data = new List<CommentModel>();
foreach (JToken token in jData)
{
Dictionary<string, object> dicData = token.ToObject<Dictionary<string, object>>();
var commentData = comments.Where(x => x.status != (int)CommentStatus.TransferOrder && !string.IsNullOrEmpty(x.comment) &&
x.status_flag == BLWording.STATUS_FLAG_ON && !string.IsNullOrEmpty(x.group_user_id) && x.uid == dicData["uid"].ToString()).Select(x => new
{
x.uid,
x.group_user_id,
x.comment,
x.comment_time
});
if (commentData.Any())
{
CommentModel tempComment = new CommentModel()
{
uid = commentData.Select(x => x.uid).FirstOrDefault(),
comment = commentData.Select(x => x.comment).FirstOrDefault(),
group_user_id = commentData.Select(x => x.group_user_id).FirstOrDefault(),
comment_time = commentData.Select(x => x.comment_time).FirstOrDefault()
};
data.Add(tempComment);
}
}
if (!data.Any())
{
return null;
}
List<Command> lCmds = new List<Command>();
List<tb_ord_order_detail> lOrderDetails = new List<tb_ord_order_detail>();
ArsenalInterface ai = null;
foreach (var item in data)
{
// 解析留言訂購格式,以每一項為單位塞到DB去
var products = JsonConvert.DeserializeObject<IEnumerable<GroupBuyParser.ParserProduct>>(item.comment);
foreach (var product in products)
{
// 目前暫定A = 0 B = 1...
var productIndex = product.Name[0] - 'A';
var productItem = productData.FirstOrDefault(x => x.seq == productIndex);
if (product.Branch == "未知" || string.IsNullOrWhiteSpace(product.Branch))
{
break;
}
var branch_uid = branchDict[product.Branch];
// 如果目前沒有主檔,新增主檔
if (!orderMasterDic.ContainsKey(branch_uid))
{
// 查詢group_uid
tb_grp_branch cBranch = new tb_grp_branch();
cBranch.SetDirty(tb_grp_branch.CN_GROUP_UID);
tb_grp_branch cCon = new tb_grp_branch() { uid = branch_uid };
Command cSelect = Command.SetupSelectCmd(cBranch, cCon);
ai = ArsenalDBMgr.GetInst(cSelect);
tb_grp_branch qds = ai.RunQuerySingleORM<tb_grp_branch>(cSelect);
var newOrderMaster = new tb_ord_order_master
{
uid = Guid.NewGuid().ToString(),
type = 1,
name = orderName,
order_code = orderCode,
article_uid = article_uid,
branch_uid = branch_uid,
group_uid = qds.group_uid,
status = (int)OrderStatus.NotArrived,
};
lCmds.Add(Command.SetupInsertCmd(newOrderMaster));
// 增加Dictionary的內容,避免內容被重複新增
orderMasterDic.Add(branch_uid, newOrderMaster);
}
if (product.Qty > 0)
{
var order = new tb_ord_order_detail
{
uid = Guid.NewGuid().ToString(),
order_uid = orderMasterDic[branch_uid].uid,
article2product_uid = productItem.uid,
member_uid = memberDict[item.group_user_id],
specification = product.Specification != "" ? product.Specification : null,
order_qty = product.Qty,
price = productItem.price * product.Qty,
comment_time = item.comment_time,
comment_uid = item.uid,
status = (int)OrderStatus.NotArrived
};
lOrderDetails.Add(order);
// 更新留言變成不顯示
tb_grp_comment updateComment = new tb_grp_comment { status = (int)CommentStatus.TransferOrder };
tb_grp_comment updateCommentCond = new tb_grp_comment { uid = item.uid };
lCmds.Add(Command.SetupUpdateCmd(updateComment, updateCommentCond));
}
}
}
if (lOrderDetails.Count == 0)
{
return "結單錯誤(請確認訂單資訊)";
}
if (article.post_status < 64)
{
tb_grp_article updateArticle = new tb_grp_article { post_status = (int)EPostStatus.EPS_ORDER };
tb_grp_article updateArticleCond = new tb_grp_article { uid = article_uid };
lCmds.Add(Command.SetupUpdateCmd(updateArticle, updateArticleCond));
}
lCmds.AddRange(lOrderDetails.Select(x => Command.SetupInsertCmd(x)));
ai = ArsenalDBMgr.GetInst(lCmds[0], GetDefaultSystemColumnInfo());
ai.RunEditCmds(lCmds);
var sMsg = GetLastErrorCode(lCmds);
return sMsg;
}
private List<tb_ord_order_master> GetOrderMasters(string article_uid)
{
tb_ord_order_master cDisplay = new tb_ord_order_master();
cDisplay.SetFullDirty();
var whereNode = new WhereNode(tb_ord_order_master.CN_ARTICLE_UID, WhereNode.EColumnOperation.EOT_EQ, typeof(tb_ord_order_master), article_uid);
var cSelect = Command.SetupSelectCmd(cDisplay, whereNode);
var ai = ArsenalDBMgr.GetInst(cSelect);
var data = ai.RunQueryList<tb_ord_order_master>(cSelect);
return data;
}
/// <summary>
/// 用文章FB ID取回貼文部分資訊
/// </summary>
/// <param name="post_id"></param>
/// <returns></returns>
private static tb_grp_article GetArticleByPostID(string articleId)
{
QueryJsonElementCollection lBlocks = new QueryJsonElementCollection();
QueryJsonElement qjeOrigin = lBlocks.GetInst();
qjeOrigin.table = tb_grp_article.TABLENAME;
qjeOrigin.displaycols = new List<string>() { tb_grp_article.CN_UID, tb_grp_article.CN_FB_ARTICLE_ID, tb_grp_article.CN_GROUP_UID };
qjeOrigin.wherecols = new WhereNode(tb_grp_article.CN_UID, WhereNode.EColumnOperation.EOT_EQ, typeof(tb_grp_article), articleId);
lBlocks.Add(qjeOrigin);
string sMsg = MakeSelectJoinByBlocks(lBlocks, out Command cRes);
var ai = ArsenalDBMgr.GetInst(cRes);
var articles = ai.RunQueryList<tb_grp_article>(cRes);
return articles.First();
}
/// <summary>
/// 用文章UID取回貼文部分資訊
/// </summary>
/// <param name="article_uid"></param>
/// <returns></returns>
private tb_grp_article GetArticle(string article_uid)
{
QueryJsonElementCollection lBlocks = new QueryJsonElementCollection();
QueryJsonElement qjeOrigin = lBlocks.GetInst();
qjeOrigin.table = tb_grp_article.TABLENAME;
qjeOrigin.displaycols = new List<string>
{
tb_grp_article.CN_GROUP_UID,
tb_grp_article.CN_FB_ARTICLE_ID,
tb_grp_article.CN_POST_STATUS,
tb_grp_article.CN_NAME
};
qjeOrigin.wherecols = new WhereNode(tb_grp_article.CN_UID, WhereNode.EColumnOperation.EOT_EQ, typeof(tb_grp_article), article_uid);
lBlocks.Add(qjeOrigin);
string sMsg = MakeSelectJoinByBlocks(lBlocks, out Command cRes);
var ai = ArsenalDBMgr.GetInst(cRes);
var articles = ai.RunQueryList<tb_grp_article>(cRes);
return articles.First();
}
/// <summary>
/// 用文章UID取回原先的留言
/// </summary>
/// <param name="article_uid"></param>
/// <returns></returns>
private List<tb_grp_comment> GetComments(string article_uid)
{
tb_grp_comment cDisplay = new tb_grp_comment();
cDisplay.SetFullDirty();
var whereNode = new WhereNode(tb_grp_comment.CN_ARTICLE_UID, WhereNode.EColumnOperation.EOT_EQ, typeof(tb_grp_comment), article_uid);
var cSelect = Command.SetupSelectCmd(cDisplay, whereNode);
var ai = ArsenalDBMgr.GetInst(cSelect);
var originComments = ai.RunQueryList<tb_grp_comment>(cSelect);
return originComments;
}
/// <summary>
/// 用社團UID取回取貨地點
/// </summary>
/// <param name="group_uid"></param>
/// <returns></returns>
private List<tb_grp_branch> GetBranches(string group_uid)
{
tb_grp_branch cDisplay = new tb_grp_branch();
cDisplay.SetFullDirty();
var whereNode = new WhereNode(tb_grp_branch.CN_GROUP_UID, WhereNode.EColumnOperation.EOT_EQ, typeof(tb_grp_branch), group_uid);
var cSelect = Command.SetupSelectCmd(cDisplay, whereNode);
var ai = ArsenalDBMgr.GetInst(cSelect);
var data = ai.RunQueryList<tb_grp_branch>(cSelect);
return data;
}
/// <summary>
/// 用貼文UID取回該貼文所有商品的部分資訊
/// </summary>
/// <param name="article_uid"></param>
/// <returns></returns>
private List<tb_prd_article2product> GetProducts(string article_uid)
{
/**開始組指令**/
QueryJsonElementCollection lBlocks = new QueryJsonElementCollection();
QueryJsonElement qjeArticleToProduct = lBlocks.GetInst();
qjeArticleToProduct.table = tb_prd_article2product.TABLENAME;
qjeArticleToProduct.displaycols = new List<string>()
{
tb_prd_article2product.CN_UID,
tb_prd_article2product.CN_NAME,
tb_prd_article2product.CN_PRICE,
tb_prd_article2product.CN_SEQ,
tb_prd_article2product.CN_SPECIFICATION
};
qjeArticleToProduct.wherecols = new WhereNode(tb_prd_article2product.CN_ARTICLE_UID, WhereNode.EColumnOperation.EOT_EQ, typeof(tb_prd_article2product), article_uid);
lBlocks.Add(qjeArticleToProduct);
QueryJsonElement qjeProduct = lBlocks.GetInst();
qjeProduct.table = tb_prd_product.TABLENAME;
qjeProduct.jointable = qjeArticleToProduct;
qjeProduct.joincols = new Dictionary<string, string>()
{
{ tb_prd_product.CN_UID, tb_prd_article2product.CN_PRD_UID }
};
lBlocks.Add(qjeProduct);
var sMsg = MakeSelectJoinByBlocks(lBlocks, out Command cRes);
var ai = ArsenalDBMgr.GetInst(cRes);
List<tb_prd_article2product> data = ai.RunQueryList<tb_prd_article2product>(cRes);
return data.ToList();
}
/// <summary>
/// 用FB社團ID取回所有使用者資訊
/// </summary>
/// <param name="group_id"></param>
/// <returns></returns>
private List<tb_meb_member> GetMembers(string group_id)
{
tb_meb_member tDisplay = new tb_meb_member();
tDisplay.SetFullDirty();
List<WhereNode> lwWhereData = new List<WhereNode>();
lwWhereData.Add(new WhereNode(tb_meb_member.CN_GROUP_ID, WhereNode.EColumnOperation.EOT_EQ, typeof(tb_meb_member), group_id));
lwWhereData.Add(new WhereNode(tb_meb_member.CN_NAME, WhereNode.EColumnOperation.EOT_NEQ, typeof(tb_meb_member), "現貨銷售"));
Command cSelect = Command.SetupSelectCmd(tDisplay, new WhereNode(WhereNode.ENodeOperation.ENO_AND, lwWhereData.ToArray()));
ArsenalInterface ai = ArsenalDBMgr.GetInst(cSelect);
List<tb_meb_member> members = ai.RunQueryList<tb_meb_member>(cSelect);
return members;
}
/// <summary>
/// 取得目前的訂單號碼
/// </summary>
/// <param name="post_id"></param>
/// <returns></returns>
public string GetOrderCode()
{
string dateString = DateTime.Now.ToString("yyMMdd");
QueryJsonElementCollection lBlocks = new QueryJsonElementCollection();
QueryJsonElement qjeOrigin = lBlocks.GetInst();
qjeOrigin.table = tb_ord_order_master.TABLENAME;
qjeOrigin.displaycols = new List<string>() { tb_ord_order_master.CN_ORDER_CODE };
qjeOrigin.wherecols = new WhereNode(tb_ord_order_master.CN_ORDER_CODE, WhereNode.EColumnOperation.EOT_LIKE, typeof(tb_ord_order_master), dateString + "%");
lBlocks.Add(qjeOrigin);
string sMsg = MakeSelectJoinByBlocks(lBlocks, out Command cRes);
var ai = ArsenalDBMgr.GetInst(cRes);
var orders = ai.RunQueryList<tb_ord_order_master>(cRes);
// 兩碼流水號,例如20082801 = 2020/8/28 第一批訂單
var lastOrderNo = orders.Select(x => x.order_code).OrderByDescending(x => x).FirstOrDefault();
int newIndex = 1;
if (!string.IsNullOrEmpty(lastOrderNo))
{
newIndex = int.Parse(lastOrderNo.Substring(6, 2)) + 1;
}
return dateString + newIndex.ToString("00");
}
#endregion
private void SendGetFbApi(string url, Action<HttpResponseMessage> successHandle_, Action<HttpResponseMessage, string> errorHandle_)
{
APIHelper.BaseGet(url, null, new Dictionary<string, string>(), out HttpResponseMessage responseMessage);
FbApiResponseHandler(responseMessage, successHandle_, errorHandle_);
}
private void SendPostFbApi(string url, dynamic postContent, Action<HttpResponseMessage> successHandle_, Action<HttpResponseMessage, string> errorHandle_)
{
APIHelper.BasePost(url, null, postContent, out HttpResponseMessage responseMessage, "json");
FbApiResponseHandler(responseMessage, successHandle_, errorHandle_);
}
/// <summary>
/// If FB API response SUCCESS return true, else you can defined your error handle function like write log
/// </summary>
/// <param name="httpResponseMessage_"></param>
/// <param name="errorHandle_"></param>
/// <returns></returns>
private void FbApiResponseHandler(HttpResponseMessage httpResponseMessage_, Action<HttpResponseMessage> successHandle_, Action<HttpResponseMessage, string> errorHandle_)
{
// check response header
if (!httpResponseMessage_.IsSuccessStatusCode)
{
var headerError = $"{httpResponseMessage_.ReasonPhrase}, {httpResponseMessage_.Headers.WwwAuthenticate}";
errorHandle_(httpResponseMessage_, headerError);
return;
}
// check response content
var bodyError = GetFbApiError(httpResponseMessage_);
if (!string.IsNullOrWhiteSpace(bodyError))
{
errorHandle_(httpResponseMessage_, bodyError);
return;
}
successHandle_(httpResponseMessage_);
}
/// <summary>
/// 檢查Response code 200後, FB回傳的內容是否包含錯誤訊息
/// </summary>
/// <param name="httpMessage_"></param>
/// <returns></returns>
public static string GetFbApiError(HttpResponseMessage httpMessage_)
{
var sContent = httpMessage_.Content.ReadAsStringAsync().Result;
var jsonObject = JObject.Parse(sContent);
if (jsonObject["error"] != null)
{
return jsonObject["error"].ToString();
}
return "";
}
}
}