/// <summary> /// Fetches a contributor object from the database. /// </summary> /// <param name="xenforoID">The contributor's xenforo ID, if any.</param> /// <returns>A contributor object, or null if not found.</returns> public Contributor GetByXenforoId(int xenforoID) { #region SQL(select_con) string select_con = PrepareSql($@" SELECT * FROM {Main.Config.ContributorTableName} WHERE XenforoID = @XenforoID" ); #endregion #region SQL(select_a) string select_a = $@" SELECT UserID FROM {Main.Config.ContributorAccountsTableName} WHERE ContributorID = @ID" ; #endregion using (var db = OpenConnection()) { Contributor con = (Contributor)db.QuerySingleOrDefault <Contributor.DataModel>(select_con, new { XenforoID = xenforoID }); if (con == null) { return(null); } con.Accounts = new List <int>(db.Query <int>(select_a, con.ToDataModel())); return(con); } }
/// <summary> /// Upgrades a contributor's tier based on their total credit balance. /// </summary> /// <param name="contributor">A reference to the contributor object to upgrade.</param> /// <param name="suppressNotifications">Whether or not notification updates should be suppressed.</param> /// <returns>A task for this action.</returns> public async Task UpgradeTier(Contributor contributor, bool suppressNotifications = false) { if (suppressNotifications || (contributor.Notifications & Notifications.TierUpdate) == Notifications.TierUpdate) { ContributorUpdates updates = 0; Tier tier = await GetByCreditsAsync(contributor.TotalCredits); if (contributor.Tier != tier.ID) { contributor.Tier = tier.ID; // Don't touch notifications on suppress if (!suppressNotifications) { contributor.Notifications |= Notifications.NewTier; contributor.Notifications ^= Notifications.TierUpdate; updates |= ContributorUpdates.Notifications; } updates |= ContributorUpdates.Tier; } if (!await Main.Contributors.UpdateAsync(contributor, updates)) { TShock.Log.ConsoleError("CTRS-DB: something went wrong while updating a contributor's notifications."); } } }
public async Task<float> GetContributorCredits(Contributor contributor) { // Only works if the contributor has linked their Xenforo account to their TShock account if (!contributor.XenforoId.HasValue || contributor.Accounts.Count == 0) return 0f; // Note: Currently, Xenforo will only store the first account to successfully authenticate XFUser user = await GetAsync(contributor.Accounts[0]); return user.Credits; }
public async Task <float> GetContributorCredits(Contributor contributor) { // Only works if the contributor has linked their Xenforo account to their TShock account if (!contributor.XenforoId.HasValue || contributor.Accounts.Count == 0) { return(0f); } // Note: Currently, Xenforo will only store the first account to successfully authenticate XFUser user = await GetAsync(contributor.Accounts[0]); return(user.Credits); }
/// <summary> /// Fetches a contributor object from the database. /// </summary> /// <param name="userID">The user ID of an authenticated account.</param> /// <returns>A contributor object, or null if not found.</returns> public Contributor Get(int userID) { #region SQL(select_id) string select_id = PrepareSql($@" SELECT ContributorID FROM {Main.Config.ContributorAccountsTableName} WHERE UserID = @UserID" ); #endregion #region SQL(select_con) string select_con = PrepareSql($@" SELECT * FROM {Main.Config.ContributorTableName} WHERE ID = @Id" ); #endregion #region SQL(select_a) string select_a = PrepareSql($@" SELECT UserID FROM {Main.Config.ContributorAccountsTableName} WHERE ContributorID = @ID" ); #endregion int contributorID; using (var db = OpenConnection()) { contributorID = db.QuerySingleOrDefault <int>(select_id, new { UserID = userID }); if (contributorID == 0) { return(null); } Contributor con = (Contributor)db.QuerySingleOrDefault <Contributor.DataModel>(select_con, new { Id = contributorID }); // The foreign key constraints would have to fail for this to happen, but better safe than sorry if (con == null) { return(null); } con.Accounts = new List <int>(db.Query <int>(select_a, con.ToDataModel())); return(con); } }
/// <summary> /// Formats the info message sent to players when they use the info command. /// {0} - Player Name /// {1} - Accounts (comma separated if more than one) /// {2} - WebID /// {3} - Credits /// {4} - TotalCredits /// {5} - LastDonation (dd-MMM-yyyy) /// {6} - Tier.Name with ChatColor /// {7} - NextTier.Name /// {8} - CreditsForNextTier /// {9} - ChatColor /// {10} - Experience Multiplier in percentage aditive: 1.10 = '10%' /// {11} - Experience Multiplier in percentage total: 1.10 = '110%' /// </summary> /// <param name="player">The contributor to take elements from.</param> /// <returns>The formatted string.</returns> public string FormatInfo(TSPlayer player, Contributor contributor, float credits, Tier tier = null, Tier nextTier = null) { return String.Format(_config.Texts.Info, player.Name, contributor.Accounts.Count == 0 ? "N/A" : String.Join(",", contributor.Accounts), contributor.XenforoId.HasValue ? contributor.XenforoId.Value.ToString() : "N/A", String.Format(_main.Config.CreditsFormat, (int)credits), String.Format(_main.Config.CreditsFormat, (int)contributor.TotalCredits), !contributor.LastDonation.HasValue ? "N/A" : contributor.LastDonation.Value.ToString("d-MMM-yyyy"), tier != null ? tier.ChatColor.HasValue ? TShock.Utils.ColorTag(tier.Name, tier.ChatColor.Value) : tier.Name : "N/A", nextTier != null ? nextTier.ChatColor.HasValue ? TShock.Utils.ColorTag(nextTier.Name, nextTier.ChatColor.Value) : nextTier.Name : "N/A", String.Format(_main.Config.CreditsFormat, (nextTier != null && tier != null) ? ((int)(nextTier.CreditsRequired - credits)).ToString() : "N/A"), Tools.ColorToRGB(contributor.ChatColor), tier != null ? $"{Math.Round(tier.ExperienceMultiplier * 100 - 100)}%" : "0%", tier != null ? $"{Math.Round(tier.ExperienceMultiplier * 100)}%" : "100%"); }
public ContributorUpdateEventArgs(Contributor contributor, ContributorUpdates updates) { ContributorId = contributor.Id; Updates = updates; if ((Updates & ContributorUpdates.XenforoID) == ContributorUpdates.XenforoID) XenforoId = contributor.XenforoId.Value; if ((Updates & ContributorUpdates.TotalCredits) == ContributorUpdates.TotalCredits) TotalCredits = contributor.TotalCredits; if ((Updates & ContributorUpdates.LastDonation) == ContributorUpdates.LastDonation) LastDonation = contributor.LastDonation; if ((Updates & ContributorUpdates.LastAmount) == ContributorUpdates.LastAmount) LastAmount = contributor.LastAmount; if ((Updates & ContributorUpdates.Tier) == ContributorUpdates.Tier) Tier = contributor.Tier; if ((Updates & ContributorUpdates.ChatColor) == ContributorUpdates.ChatColor) ChatColor = contributor.ChatColor; if ((Updates & ContributorUpdates.Notifications) == ContributorUpdates.Notifications) Notifications = contributor.Notifications; if ((Updates & ContributorUpdates.Settings) == ContributorUpdates.Settings) Settings = contributor.Settings; }
public ContributorUpdateEventArgs(Contributor contributor, ContributorUpdates updates) { ContributorId = contributor.Id; Updates = updates; if ((Updates & ContributorUpdates.XenforoID) == ContributorUpdates.XenforoID) { XenforoId = contributor.XenforoId.Value; } if ((Updates & ContributorUpdates.TotalCredits) == ContributorUpdates.TotalCredits) { TotalCredits = contributor.TotalCredits; } if ((Updates & ContributorUpdates.LastDonation) == ContributorUpdates.LastDonation) { LastDonation = contributor.LastDonation; } if ((Updates & ContributorUpdates.LastAmount) == ContributorUpdates.LastAmount) { LastAmount = contributor.LastAmount; } if ((Updates & ContributorUpdates.Tier) == ContributorUpdates.Tier) { Tier = contributor.Tier; } if ((Updates & ContributorUpdates.ChatColor) == ContributorUpdates.ChatColor) { ChatColor = contributor.ChatColor; } if ((Updates & ContributorUpdates.Notifications) == ContributorUpdates.Notifications) { Notifications = contributor.Notifications; } if ((Updates & ContributorUpdates.Settings) == ContributorUpdates.Settings) { Settings = contributor.Settings; } }
/// <summary> /// Inserts data for a contributor object into the database asynchronously. /// The contributor object must have a Xenforo Id associated with it. /// </summary> /// <param name="contributor">The contributor object to save.</param> /// <returns> /// A task with a <see cref="bool"/> representing whether the operation was successful or not. /// </returns> public Task <bool> AddAsync(Contributor contributor) { return(Task.Run(() => Add(contributor))); }
/// <summary> /// Sends updated contributor data to the database. /// Logs any exception thrown. /// </summary> /// <param name="contributor">The contributor to update with the already-updated values set.</param> /// <param name="updates">The list of values to update.</param> /// <returns>True if it updates one row, false if anything else..</returns> public bool Update(Contributor contributor, ContributorUpdates updates) { if (updates == 0) return true; List<string> updatesList = new List<string>(); if ((updates & ContributorUpdates.XenforoID) == ContributorUpdates.XenforoID) updatesList.Add("XenforoID = @XenforoID"); if ((updates & ContributorUpdates.TotalCredits) == ContributorUpdates.TotalCredits) updatesList.Add("TotalCredits = @TotalCredits"); if ((updates & ContributorUpdates.LastDonation) == ContributorUpdates.LastDonation) updatesList.Add("LastDonation = @LastDonation"); if ((updates & ContributorUpdates.LastAmount) == ContributorUpdates.LastAmount) updatesList.Add("LastAmount = @LastAmount"); if ((updates & ContributorUpdates.Tier) == ContributorUpdates.Tier) updatesList.Add("Tier = @Tier"); if ((updates & ContributorUpdates.ChatColor) == ContributorUpdates.ChatColor) updatesList.Add("ChatColor = @ChatColor"); if ((updates & ContributorUpdates.Notifications) == ContributorUpdates.Notifications) updatesList.Add("Notifications = @Notifications"); if ((updates & ContributorUpdates.Settings) == ContributorUpdates.Settings) updatesList.Add("Settings = @Settings"); #region SQL(update) string update = PrepareSql($@" UPDATE {Main.Config.ContributorTableName} SET {String.Join(", ", updatesList)} WHERE ID = @ID"); #endregion try { lock (syncLock) { using (var db = OpenConnection()) { return db.Execute(update, contributor.ToDataModel()) == 1; } } } catch (Exception ex) { TShock.Log.ConsoleError("{0}\n{1}\n{2}", "CTRS: An error occurred while updating a contributor's info", $"Message: {ex.Message}", "Check logs for more details"); TShock.Log.Error(ex.ToString()); return false; } }
/// <summary> /// Inserts data for a contributor object into the database. /// The contributor object must have a Xenforo Id associated with it. /// </summary> /// <param name="contributor">The contributor object to save.</param> /// <returns>A <see cref="bool"/> representing whether the operation was successful or not.</returns> public bool Add(Contributor contributor) { #region SQL(query) string query = PrepareSql($@" INSERT INTO {Main.Config.ContributorTableName} ( XenforoID, TotalCredits, LastAmount, Notifications, Settings ) VALUES ( @XenforoID, @TotalCredits, @LastAmount, @Notifications, @Settings )"); if (contributor.LastDonation != DateTime.MinValue) { query = PrepareSql($@" INSERT INTO {Main.Config.ContributorTableName} ( XenforoID, TotalCredits, LastDonation, LastAmount, Notifications, Settings ) VALUES ( @XenforoID, @TotalCredits, @LastDonation, @LastAmount, @Notifications, @Settings )"); } #endregion #region SQL(query_a) string query_a = PrepareSql($@" INSERT INTO {Main.Config.ContributorAccountsTableName} ( UserID, ContributorID ) VALUES ( @UserID, @ContributorID )"); #endregion try { lock (syncLock) { using (var db = OpenConnection()) { if (db.Execute(query, contributor.ToDataModel()) == 1) { contributor.Id = GetLastInsertId(); for (int i = 0; i < contributor.Accounts.Count; i++) { if (db.Execute(query_a, new { UserID = contributor.Accounts[i], ContributorID = contributor.Id }) == 0) { return false; } } return true; } return false; } } } catch (Exception ex) { if (Main.Config.LogDatabaseErrors) { TShock.Log.ConsoleError($"CTRS-DB: Unable to add contributor with xenforoID:{contributor.XenforoId.Value}\nMessage: " + ex.Message); TShock.Log.Error(ex.ToString()); } return false; } }
public AuthResult(Contributor contributor) : this(LMReturnCode.Success) { Contributor = contributor; }
// 0 - player name | 1 - amount formatted to credits public string FormatNewDonation(TSPlayer player, Contributor contributor, float amount) { return String.Format(_config.Texts.NewDonation, player.Name, String.Format(_main.Config.CreditsFormat, (int)amount)); }
// 0 - player name | 1 - Tier.Name with ChatColor public string FormatNewTier(TSPlayer player, Contributor contributor, Tier tier) { return String.Format(_config.Texts.NewTier, player.Name, tier.ChatColor.HasValue ? TShock.Utils.ColorTag(tier.Name, tier.ChatColor.Value) : tier.Name); }
// 0 - player name public string FormatIntroduction(TSPlayer player, Contributor contributor) { return String.Format(_config.Texts.Introduction, player.Name); }
/// <summary> /// Sends updated contributor data to the database. /// Logs any exception thrown. /// </summary> /// <param name="contributor">The contributor to update with the already-updated values set.</param> /// <param name="updates">The list of values to update.</param> /// <returns>True if it updates one row, false if anything else..</returns> public bool Update(Contributor contributor, ContributorUpdates updates) { if (updates == 0) { return(true); } List <string> updatesList = new List <string>(); if ((updates & ContributorUpdates.XenforoID) == ContributorUpdates.XenforoID) { updatesList.Add("XenforoID = @XenforoID"); } if ((updates & ContributorUpdates.TotalCredits) == ContributorUpdates.TotalCredits) { updatesList.Add("TotalCredits = @TotalCredits"); } if ((updates & ContributorUpdates.LastDonation) == ContributorUpdates.LastDonation) { updatesList.Add("LastDonation = @LastDonation"); } if ((updates & ContributorUpdates.LastAmount) == ContributorUpdates.LastAmount) { updatesList.Add("LastAmount = @LastAmount"); } if ((updates & ContributorUpdates.Tier) == ContributorUpdates.Tier) { updatesList.Add("Tier = @Tier"); } if ((updates & ContributorUpdates.ChatColor) == ContributorUpdates.ChatColor) { updatesList.Add("ChatColor = @ChatColor"); } if ((updates & ContributorUpdates.Notifications) == ContributorUpdates.Notifications) { updatesList.Add("Notifications = @Notifications"); } if ((updates & ContributorUpdates.Settings) == ContributorUpdates.Settings) { updatesList.Add("Settings = @Settings"); } #region SQL(update) string update = PrepareSql($@" UPDATE {Main.Config.ContributorTableName} SET {String.Join(", ", updatesList)} WHERE ID = @ID" ); #endregion try { lock (syncLock) { using (var db = OpenConnection()) { return(db.Execute(update, contributor.ToDataModel()) == 1); } } } catch (Exception ex) { TShock.Log.ConsoleError("{0}\n{1}\n{2}", "CTRS: An error occurred while updating a contributor's info", $"Message: {ex.Message}", "Check logs for more details"); TShock.Log.Error(ex.ToString()); return(false); } }
/// <summary> /// Asynchronously sends updated contributor data to the database. /// Logs any exception thrown. /// </summary> /// <param name="contributor">The contributor to update with the already-updated values set.</param> /// <param name="updates">The list of values to update.</param> /// <returns>True if it updates one row, false if anything else.</returns> public async Task <bool> UpdateAsync(Contributor contributor, ContributorUpdates updates) { return(await Task.Run(() => Update(contributor, updates))); }
/// <summary> /// Upgrades a contributor's tier based on their total credit balance. /// </summary> /// <param name="contributor">A reference to the contributor object to upgrade.</param> /// <param name="suppressNotifications">Whether or not notification updates should be suppressed.</param> /// <returns>A task for this action.</returns> public async Task UpgradeTier(Contributor contributor, bool suppressNotifications = false) { if (suppressNotifications || (contributor.Notifications & Notifications.TierUpdate) == Notifications.TierUpdate) { ContributorUpdates updates = 0; Tier tier = await GetByCreditsAsync(contributor.TotalCredits); if (contributor.Tier != tier.ID) { contributor.Tier = tier.ID; // Don't touch notifications on suppress if (!suppressNotifications) { contributor.Notifications |= Notifications.NewTier; contributor.Notifications ^= Notifications.TierUpdate; updates |= ContributorUpdates.Notifications; } updates |= ContributorUpdates.Tier; } if (!await Main.Contributors.UpdateAsync(contributor, updates)) TShock.Log.ConsoleError("CTRS-DB: something went wrong while updating a contributor's notifications."); } }
/// <summary> /// Authenticates an <see cref="User"/> to a Xenforo forum account and returns the <see cref="Contributor"/> /// if the authentication succeeds. /// </summary> /// <param name="user">The Xenforo account name.</param> /// <param name="credentials">The Xenforo account password.</param> /// <returns> /// A task with the <see cref="AuthResult"/> and a contributor object. The contributor is only defined /// if the authentication succeeds. /// </returns> public async Task<AuthResult> Authenticate(User user, Credentials credentials) { if (credentials == null) { return new AuthResult(LMReturnCode.UnloadedCredentials); } var sb = new StringBuilder(); sb.Append(_main.Config.Xenforo.XenAPIURI ?? "http://sbplanet.co/forums/api.php"); // REQUEST: api.php?action=authenticate&username=USERNAME&password=PASSWORD sb.Append("?action=authenticate"); if (String.IsNullOrEmpty(credentials.Username)) { #region DEBUG #if DEBUG TShock.Log.ConsoleInfo("AUTH ERROR: {Username} was null"); #endif #endregion return new AuthResult(LMReturnCode.EmptyParameter); } sb.Append("&username="******"AUTH ERROR: {Password} was null"); #endif #endregion return new AuthResult(LMReturnCode.EmptyParameter); } sb.Append("&password="******"REQUESTING: " + sb.ToString()); #endif #endregion string response = ""; using (WebClient client = new WebClient()) { try { response = await client.DownloadStringTaskAsync(sb.ToString()); } catch (WebException e) { using (HttpWebResponse r = (HttpWebResponse)e.Response) using (var reader = new StreamReader(r.GetResponseStream())) { response = reader.ReadToEnd(); } } } #region DEBUG #if DEBUG TShock.Log.ConsoleInfo("RESPONSE: " + response); #endif #endregion var dict = JsonConvert.DeserializeObject<Dictionary<string, object>>(response); if (dict.ContainsKey("hash")) { // Store the hash and perform a second query to get the userID string hash = (string)dict["hash"]; sb.Clear(); sb.Append(_main.Config.Xenforo.XenAPIURI ?? "http://sbplanet.co/forums/api.php"); // REQUEST: api.php?action=getUser&hash=USERNAME:HASH sb.Append("?action=getUser"); sb.Append("&hash="); sb.Append(credentials.Username); sb.Append(':'); sb.Append(hash); #region DEBUG #if DEBUG TShock.Log.ConsoleInfo("REQUESTING: " + sb.ToString()); #endif #endregion using (WebClient client = new WebClient()) { try { response = await client.DownloadStringTaskAsync(sb.ToString()); } catch (WebException e) { using (HttpWebResponse r = (HttpWebResponse)e.Response) using (var reader = new StreamReader(r.GetResponseStream())) { response = reader.ReadToEnd(); } } } #region DEBUG #if DEBUG TShock.Log.ConsoleInfo("RESPONSE: " + response); #endif #endregion dict = JsonConvert.DeserializeObject<Dictionary<string, object>>(response); if (!dict.ContainsKey("user_id")) return new AuthResult(LMReturnCode.UserNotFound); else { // Check if the user is a contributor List<int> groups = new List<int>(); if (dict.ContainsKey("user_group_id")) { groups.Add(Convert.ToInt32(dict["user_group_id"])); } if (dict.ContainsKey("secondary_group_ids")) { ((string)dict["secondary_group_ids"]).Split(',').ForEach(s => { if (!String.IsNullOrWhiteSpace(s)) groups.Add(Convert.ToInt32(s)); }); } if (!_main.Config.Xenforo.ContributorForumGroupIDs.Intersect(groups).Any()) { return new AuthResult(LMReturnCode.UserNotAContributor); } Contributor contributor = await _main.Contributors.GetByXenforoIdAsync(Convert.ToInt32(dict["user_id"])); if (contributor == null) { /* Attempt to find contributor by user ID in the event a transaction * was logged for an unexistant contributor account */ contributor = await _main.Contributors.GetAsync(user.ID); bool success = false; if (contributor == null) { // Add a new contributor contributor = new Contributor(user); contributor.XenforoId = Convert.ToInt32(dict["user_id"]); success = await _main.Contributors.AddAsync(contributor); } else { // Set XenforoID for an existing contributor contributor.XenforoId = Convert.ToInt32(dict["user_id"]); success = await _main.Contributors.UpdateAsync(contributor, ContributorUpdates.XenforoID); } if (success) return new AuthResult(contributor); else return new AuthResult(LMReturnCode.DatabaseError); } else { // Check account limit if (_main.Config.AccountLimit > 0 && contributor.Accounts.Count >= _main.Config.AccountLimit) { return new AuthResult(LMReturnCode.AccountLimitReached); } if (await _main.Contributors.AddAccountAsync(contributor.Id, user.ID)) { contributor.Accounts.Add(user.ID); return new AuthResult(contributor); } else return new AuthResult(LMReturnCode.DatabaseError); } } } else return new AuthResult((LMReturnCode)Convert.ToInt32((long)dict["error"])); }
object restNewTransactionV2(RestRequestArgs args) { int userID; if (!Int32.TryParse(args.Verbs["user_id"], out userID)) return RestInvalidParam("user_id"); if (String.IsNullOrWhiteSpace(args.Parameters["credits"])) return RestMissingParam("credits"); float credits; if (!Single.TryParse(args.Parameters["credits"], out credits)) return RestInvalidParam("credits"); long dateUnix = 0; if (!String.IsNullOrWhiteSpace(args.Parameters["date"])) Int64.TryParse(args.Parameters["date"], out dateUnix); Contributor con = _main.Contributors.GetByXenforoId(userID); bool success = false; if (con == null) { // Transactions must never be ignored. If the contributor doesn't exist, create it con = new Contributor(0); con.XenforoId = userID; con.LastAmount = credits; if (dateUnix > 0) con.LastDonation = dateUnix.FromUnixTime(); con.Tier = 1; con.TotalCredits = credits; success = _main.Contributors.Add(con); if (!success) { TShock.Log.ConsoleInfo($"CTRS-WARNING: Failed to register contribution made by forum user ID [{userID}]!"); } // Fire the Transaction event (must be done after Add to include the contributor Id) Transaction?.Invoke(_main.Contributors, new TransactionEventArgs(con.Id, credits, dateUnix.FromUnixTime())); } else { ContributorUpdates updates = 0; con.LastAmount = credits; updates |= ContributorUpdates.LastAmount; if (dateUnix > 0) { con.LastDonation = dateUnix.FromUnixTime(); updates |= ContributorUpdates.LastDonation; } con.TotalCredits += credits; updates |= ContributorUpdates.TotalCredits; // Fire the Transaction event var transactionArgs = new TransactionEventArgs(con.Id, credits, dateUnix.FromUnixTime()); Transaction?.Invoke(_main.Contributors, transactionArgs); // Suppress notifications if needed if (!transactionArgs.SuppressNotifications) { con.Notifications |= Notifications.NewDonation; con.Notifications |= Notifications.TierUpdate; updates |= ContributorUpdates.Notifications; } success = _main.Contributors.Update(con, updates); } if (!success) return RestError("Transaction was not registered properly."); else return RestResponse("Transaction successful."); }
/// <summary> /// Inserts data for a contributor object into the database asynchronously. /// The contributor object must have a Xenforo Id associated with it. /// </summary> /// <param name="contributor">The contributor object to save.</param> /// <returns> /// A task with a <see cref="bool"/> representing whether the operation was successful or not. /// </returns> public Task<bool> AddAsync(Contributor contributor) { return Task.Run(() => Add(contributor)); }
object restNewTransaction(RestRequestArgs args) { var ret = UserFind(args.Parameters); if (ret is RestObject) return ret; User user = (User)ret; if (String.IsNullOrWhiteSpace(args.Parameters["credits"])) return RestMissingParam("credits"); float credits; if (!Single.TryParse(args.Parameters["credits"], out credits)) return RestInvalidParam("credits"); long dateUnix = 0; if (!String.IsNullOrWhiteSpace(args.Parameters["date"])) Int64.TryParse(args.Parameters["date"], out dateUnix); Contributor con = _main.Contributors.Get(user.ID); bool success = false; if (con == null) { // Transactions must never be ignored. If the contributor doesn't exist, create it con = new Contributor(user); con.LastAmount = credits; if (dateUnix > 0) con.LastDonation = dateUnix.FromUnixTime(); con.Tier = 1; con.TotalCredits = credits; success = _main.Contributors.AddLocal(con); if (!success) TShock.Log.ConsoleInfo($"CTRS-WARNING: Failed to register contribution made by user '{user.Name}'!"); } else { ContributorUpdates updates = 0; con.LastAmount = credits; updates |= ContributorUpdates.LastAmount; if (dateUnix > 0) { con.LastDonation = dateUnix.FromUnixTime(); updates |= ContributorUpdates.LastDonation; } con.TotalCredits += credits; updates |= ContributorUpdates.TotalCredits; con.Notifications |= Notifications.NewDonation; // Always prompt a tier update check here con.Notifications |= Notifications.TierUpdate; updates |= ContributorUpdates.Notifications; success = _main.Contributors.Update(con, updates); } if (!success) return RestError("Transaction was not registered properly."); else return RestResponse("Transaction successful."); }
/// <summary> /// Asynchronously sends updated contributor data to the database. /// Logs any exception thrown. /// </summary> /// <param name="contributor">The contributor to update with the already-updated values set.</param> /// <param name="updates">The list of values to update.</param> /// <returns>True if it updates one row, false if anything else.</returns> public async Task<bool> UpdateAsync(Contributor contributor, ContributorUpdates updates) { return await Task.Run(() => Update(contributor, updates)); }
/// <summary> /// Inserts data for a contributor object into the database. /// The contributor object must have a Xenforo Id associated with it. /// </summary> /// <param name="contributor">The contributor object to save.</param> /// <returns>A <see cref="bool"/> representing whether the operation was successful or not.</returns> public bool Add(Contributor contributor) { #region SQL(query) string query = PrepareSql($@" INSERT INTO {Main.Config.ContributorTableName} ( XenforoID, TotalCredits, LastAmount, Notifications, Settings ) VALUES ( @XenforoID, @TotalCredits, @LastAmount, @Notifications, @Settings )" ); if (contributor.LastDonation != DateTime.MinValue) { query = PrepareSql($@" INSERT INTO {Main.Config.ContributorTableName} ( XenforoID, TotalCredits, LastDonation, LastAmount, Notifications, Settings ) VALUES ( @XenforoID, @TotalCredits, @LastDonation, @LastAmount, @Notifications, @Settings )" ); } #endregion #region SQL(query_a) string query_a = PrepareSql($@" INSERT INTO {Main.Config.ContributorAccountsTableName} ( UserID, ContributorID ) VALUES ( @UserID, @ContributorID )" ); #endregion try { lock (syncLock) { using (var db = OpenConnection()) { if (db.Execute(query, contributor.ToDataModel()) == 1) { contributor.Id = GetLastInsertId(); for (int i = 0; i < contributor.Accounts.Count; i++) { if (db.Execute(query_a, new { UserID = contributor.Accounts[i], ContributorID = contributor.Id }) == 0) { return(false); } } return(true); } return(false); } } } catch (Exception ex) { if (Main.Config.LogDatabaseErrors) { TShock.Log.ConsoleError($"CTRS-DB: Unable to add contributor with xenforoID:{contributor.XenforoId.Value}\nMessage: " + ex.Message); TShock.Log.Error(ex.ToString()); } return(false); } }