private void SendMail(App app, AppUpdate update) { ICollection<AppTrack> tracks = repository.AppTrack.RetrieveByApp(app.Id); foreach (AppTrack track in tracks) { User user = repository.User.Retrieve(track.User); if (track.RequireNotification(user, update.Type)) { MailMessage message = CreateMailMessage(user, app, update); if (settings.Debug) { StringBuilder text = new StringBuilder() .AppendLine("Send mail:") .AppendLine("From: " + message.From.Address) .AppendLine("To: " + message.To[0].Address) .AppendLine("Subject: " + message.Subject) .AppendLine(message.Body); logger.Trace(text.ToString()); } else { try { smtp.Send(message); logger.Trace( "Sent mail to user {0}-{1} via {2} for update{3}", user.Id, user.Username, user.Email, update.Id ); } catch (SmtpFailedRecipientException) { logger.Warn("Failed to send email to {0}, address may be invalid", user.Email); } catch (Exception ex) { logger.ErrorException("Encountered unexpected exception when send email", ex); } } } } }
public ICollection<AppUpdate> CheckForUpdate(AppBrief newOne) { DateTime now = DateTime.Now; List<AppUpdate> updates = new List<AppUpdate>(); // 检查版本 if (Version != newOne.Version) { AppUpdate update = new AppUpdate() { App = Id, Time = now, NewValue = newOne.Version, OldValue = Version, Type = AppUpdateType.NewRelease, }; updates.Add(update); } // 检查价格,价格单位有变动时涉及换算问题,不计入价格变化中 if (Price != newOne.Price && Currency == newOne.Currency) { AppUpdate update = new AppUpdate() { App = Id, Time = now, NewValue = newOne.Price.ToString(), OldValue = Price.ToString(), Type = newOne.Price == 0 ? AppUpdateType.PriceFree : (newOne.Price > Price ? AppUpdateType.PriceIncrease : AppUpdateType.PriceDecrease) }; updates.Add(update); } return updates; }
public void ProcessUpdate(App app, AppUpdate update) { lock (UpdateData) { if (!UpdateData.ContainsKey(app)) { UpdateData[app] = new List<AppUpdate>(); } UpdateData[app].Add(update); } }
public void ProcessUpdate(App app, AppUpdate update) { /* * 1. 把所有AppTrack的HasRead改回false * 2. 发送邮件通知用户 */ int trackCount = repository.AppTrack.ResetReadStatusByApp(update.App); logger.Trace("Set {0} tracks to unread for app {1}-{2}", trackCount, app.Id, app.Brief.Name); SendMail(app, update); }
public void Save(AppUpdate update) { update.Id = Guid.NewGuid(); string sql = @"insert into `AppUpdate` ( `Id`, `App`, `Time`, `Type`, `OldValue`, `NewValue` ) values ( ?Id, ?App, ?Time, ?Type, ?OldValue, ?NewValue );"; MySqlCommand command = connection.CreateCommand(); command.CommandText = sql; command.Parameters.AddWithValue("?Id", update.Id.ToString("N")); command.Parameters.AddWithValue("?App", update.App); command.Parameters.AddWithValue("Time", update.Time); command.Parameters.AddWithValue("?Type", update.Type); command.Parameters.AddWithValue("?OldValue", update.OldValue); command.Parameters.AddWithValue("?NewValue", update.NewValue); command.ExecuteNonQuery(); }
private MailMessage CreateMailMessage(User user, App app, AppUpdate update) { MailMessage message = new MailMessage( new MailAddress(settings.MailAddress, settings.MailUser, Encoding.UTF8), new MailAddress(user.Email) ); message.SubjectEncoding = Encoding.UTF8; message.Subject = String.Format(subjects[update.Type], app.Brief.Name, update.OldValue, update.NewValue); message.BodyEncoding = Encoding.UTF8; message.IsBodyHtml = true; message.Body = String.Format( templates[update.Type], user.Username, app.Brief.Name, update.OldValue, update.NewValue, app.Id, app.Brief.ViewUrl, DateTime.Now, app.ReleaseNotes ); return message; }
public static AppUpdate ToAppUpdate(this IDataRecord record) { AppUpdate update = new AppUpdate() { App = record.GetInt32("App"), Id = record.GetGuid("Id"), NewValue = record.GetString("NewValue"), OldValue = record.GetString("OldValue"), Type = (AppUpdateType)record.GetInt32("Type"), Time = record.GetDateTime("Time") }; return update; }
public void Save(AppUpdate update) { appUpdates.Save(update); }
private static int MigrateAppUpdates(int offset, int batchSize) { var command = souce.CreateCommand(); command.CommandType = CommandType.Text; command.CommandText = "select App, Time, Type, OldValue, NewValue from AppUpdate limit ?offset, ?batchSize"; command.Parameters.AddWithValue("?offset", offset); command.Parameters.AddWithValue("?batchSize", batchSize); List<AppUpdate> updates = new List<AppUpdate>(); Stopwatch watch = new Stopwatch(); watch.Start(); using (var reader = command.ExecuteReader()) { while (reader.Read()) { AppUpdate update = new AppUpdate() { App = reader.GetInt32(0), Time = reader.GetDateTime(1), Type = (AppUpdateType)reader.GetInt32(2), OldValue = reader.GetString(3), NewValue = reader.GetString(4) }; // 新建和加入到应用的2个更新,在新系统中使用的是NewValue,需要换过来 if (update.Type == AppUpdateType.New || update.Type == AppUpdateType.AddToPing) { update.NewValue = update.OldValue; update.OldValue = String.Empty; } // 现有AppStore中国区全部是用人民币作为价格,因此将美元全部换回人民币 if (update.Type == AppUpdateType.PriceIncrease || update.Type == AppUpdateType.PriceDecrease || update.Type == AppUpdateType.PriceFree) { // 价格相关的更新,OldValue和NewValue都是价格直接值 float oldPrice = Single.Parse(update.OldValue); float newPrice = Single.Parse(update.NewValue); if ((int)oldPrice != oldPrice) { update.OldValue = priceMapping[oldPrice].ToString(); } if ((int)newPrice != newPrice) { update.NewValue = priceMapping[newPrice].ToString(); } } else if (update.Type == AppUpdateType.New || update.Type == AppUpdateType.AddToPing || update.Type == AppUpdateType.Revoke) { // 另外几个更新,用的是{version, $price}的形式,需要分隔开来再计算 string[] oldValueParts = update.OldValue.Split(new string[] { ", " }, StringSplitOptions.None); string[] newValueParts = update.NewValue.Split(new string[] { ", " }, StringSplitOptions.None); if (oldValueParts.Length > 1) { float oldPrice = Single.Parse(oldValueParts.Last().Substring(1)); if ((int)oldPrice != oldPrice) { oldValueParts[oldValueParts.Length - 1] = priceMapping[oldPrice].ToString(); update.OldValue = String.Join(", ", oldValueParts); } } if (newValueParts.Length > 1) { float newPrice = Single.Parse(newValueParts.Last().Substring(1)); if ((int)newPrice != newPrice) { newValueParts[newValueParts.Length - 1] = priceMapping[newPrice].ToString(); update.NewValue = String.Join(", ", newValueParts); } } } // 版本更新不需要动 updates.Add(update); } } watch.Stop(); Console.WriteLine("Retrieved {0} updates using {1}", updates.Count, watch.Elapsed); watch.Reset(); watch.Start(); using (MySqlTransaction transaction = destination.BeginTransaction()) { foreach (AppUpdate update in updates) { repository.AppUpdate.Save(update); } transaction.Commit(); } watch.Stop(); Console.WriteLine("Saved to mongo using {0}", watch.Elapsed); return updates.Count; }
public void Save(App app) { AppUpdate updateForNew = new AppUpdate() { App = app.Id, Time = app.Brief.ReleaseDate.Date, Type = AppUpdateType.New, NewValue = app.Brief.Version + ", " + app.Brief.PriceWithSymbol }; appUpdates.Save(updateForNew); AppUpdate updateForAdd = new AppUpdate() { App = app.Id, Time = DateTime.Now, Type = AppUpdateType.AddToPing, NewValue = app.Brief.Version + ", " + app.Brief.PriceWithSymbol }; appUpdates.Save(updateForAdd); app.Brief.LastValidUpdate = updateForAdd; apps.Save(app); }
private void RevokeApps(RepositoryEmitter repository) { Stopwatch watch = new Stopwatch(); watch.Start(); foreach (App app in revokedApps) { // 添加下架信息 AppUpdate update = new AppUpdate() { App = app.Id, Type = AppUpdateType.Revoke, OldValue = app.Brief.Version + ", " + app.Brief.PriceWithSymbol, Time = DateTime.Now }; repository.AppUpdate.Save(update); // 从在售应用中移除 repository.App.Delete(app.Id); // 添加到下架应用中 RevokedApp revoked = new RevokedApp(app); revoked.RevokeTime = DateTime.Now; repository.App.SaveRevoked(revoked); // 移除全文索引 indexer.DeleteApp(app); logger.Trace("Set app {0}-{1} to be revoked", app.Id, app.Brief.Name); } watch.Stop(); logger.Info("Revoked {0} apps using {1}ms", revokedApps.Count, watch.ElapsedMilliseconds); watch.Reset(); watch.Stop(); indexer.Flush(); watch.Stop(); logger.Info("Deleted index for {0} apps using {1}ms", revokedApps.Count, watch.ElapsedMilliseconds); }
public static IHtmlString UpdateDescrioption(this HtmlHelper helper, AppUpdate update) { if (update.Type == AppUpdateType.New || update.Type == AppUpdateType.AddToPing || update.Type == AppUpdateType.Revoke) { return helper.Raw(update.OldValue); } else if (update.Type == AppUpdateType.NewRelease) { return helper.Raw(update.OldValue + " -> " + update.NewValue); } else { char unit = update.Time < unitChangeDate ? '$' : '¥'; return helper.Raw(unit + update.OldValue + " -> " + unit + update.NewValue); } }
private void TryRescue(IEnumerable<RevokedApp> apps) { int[] identities = apps.Select(a => a.Id).ToArray(); ICollection<App> retrievedApps = appParser.RetrieveApps(identities); if (retrievedApps == null) { return; } foreach (App resurrected in retrievedApps) { // 添加重新上架信息 AppUpdate update = new AppUpdate() { App = resurrected.Id, NewValue = resurrected.Brief.Version + ", " + resurrected.Brief.PriceWithSymbol, Time = DateTime.Now, Type = AppUpdateType.Resurrect }; repository.AppUpdate.Save(update); // 从下架应用中移除 repository.App.DeleteRevoked(resurrected.Id); // 重新加入到应用集合中,并标记最后更新 resurrected.Brief.LastValidUpdate = update; repository.App.Save(resurrected); // 添加到全文索引 indexer.AddApp(resurrected); logger.Trace("Resurrected app {0}-{1}", resurrected.Id, resurrected.Brief.Name); } Stopwatch watch = new Stopwatch(); watch.Start(); indexer.Flush(); watch.Stop(); logger.Debug("Indexed {0} apps using {1}ms", retrievedApps.Count, watch.ElapsedMilliseconds); }