private static string /*letter id*/ CreateLetterInternal(string board_id, string discussion_id, string creator, string words, Subtype subtype, string delta_flags) { string partition_key = SandId.CombineId(board_id, discussion_id); if (NextIdStore.GetLastId(Warehouse.DiscussionLoadTable, partition_key) >= HeartsConfiguration.MAX_NUM_OF_LETTERS_IN_A_DISCUSSION) { Util.ThrowBadRequestException("留言數超過上限(" + HeartsConfiguration.MAX_NUM_OF_LETTERS_IN_A_DISCUSSION + ")則。"); } int next_id = NextIdStore.Next(Warehouse.DiscussionLoadTable, partition_key); // null reference exception for nonexistent board id. string letter_id = SandId.MakeLetterId(next_id); // if exception is thrown after getting id, the id is lost. DynamicTableEntity entity = new DynamicTableEntity(partition_key, letter_id); LetterConverter.CreateLetterEntity(entity, creator, words, subtype, delta_flags, board_id, discussion_id); // Warehouse.DiscussionLoadPond.Get(board_id, discussion_id).AddLetter(entity); Warehouse.DiscussionSummaryPond.Get(board_id, discussion_id).AddLetter(entity); Warehouse.DiscussionLoadTable.Execute(TableOperation.Insert(entity)); // return(letter_id); }
public static ControlHistory ControlLetter(string board_id, string discussion_id, string letter_id, string delta_flags) { string partition_key = SandId.CombineId(board_id, discussion_id); // todo: select only needed properties. TableResult result = Warehouse.DiscussionLoadTable.Execute(TableOperation.Retrieve(partition_key, letter_id)); DynamicTableEntity entity = (DynamicTableEntity)result.Result; // permanent deleting twice is not blocked. GroupStore.CheckControlRight(board_id, discussion_id, letter_id, ref delta_flags, entity); int ec = RevisionStore.IncreaseEditCount(entity); RevisionStore.CreateRevision(entity, board_id, discussion_id, letter_id, ec); int prev_report_cnt = SandFlags.GetNumber(entity.GetFlags(), SandFlags.MT_REPORT); LetterConverter.ModifyLetterFlags(entity, null, delta_flags); int new_report_cnt = SandFlags.GetNumber(entity.GetFlags(), SandFlags.MT_REPORT); Warehouse.DiscussionLoadTable.Execute(TableOperation.Replace(entity)); // Throws StorageException ((412) Precondition Failed) if the entity is modified in between. Warehouse.DiscussionLoadPond.Notify(board_id, discussion_id); Warehouse.DiscussionSummaryPond.Notify(board_id, discussion_id); HttpResponse.RemoveOutputCacheItem("/discussionload/" + board_id + "/" + discussion_id); return(new ControlHistory { ReportCount = new_report_cnt - prev_report_cnt }); }
public static void EditLetter(string board_id, string discussion_id, string letter_id, string editor, string words, string delta_flags, HttpFileCollectionBase files) { string partition_key = SandId.CombineId(board_id, discussion_id); TableResult result = Warehouse.DiscussionLoadTable.Execute(TableOperation.Retrieve(partition_key, letter_id)); DynamicTableEntity entity = (DynamicTableEntity)result.Result; GroupStore.CheckEditRight(board_id, discussion_id, entity); HashSet <string> files_set = new HashSet <string>(); words = processUploadFiles(words, files, files_set); words = processWords(words); claimFiles(words, SandId.CombineId(board_id, discussion_id, letter_id), files_set); // if (entity != null) // let it throw null reference exception. int ec = RevisionStore.IncreaseEditCount(entity); RevisionStore.CreateRevision(entity, board_id, discussion_id, letter_id, ec); LetterConverter.EditLetterEntity(entity, editor, words, delta_flags, board_id, discussion_id); Warehouse.DiscussionLoadTable.Execute(TableOperation.Replace(entity)); // Throws StorageException ((412) Precondition Failed) if the entity is modified in between. Warehouse.DiscussionLoadPond.Notify(board_id, discussion_id); Warehouse.DiscussionSummaryPond.Notify(board_id, discussion_id); HttpResponse.RemoveOutputCacheItem("/discussionload/" + board_id + "/" + discussion_id); }
public static void CheckControlRight(string board_id, string discussion_id, string letter_id, ref string delta_flags, DynamicTableEntity entity) { Subtype subtype = LetterConverter.GetSubtype(entity); if (subtype == Subtype.d) { Util.ThrowUnauthorizedException("不能修改的類型。"); } bool auto_unreport = false; if (SandFlags.Check(delta_flags, SandFlags.MT_PERMANENT_DELETE, 1)) { GroupStore.CheckPermanentDeleteRight(board_id, discussion_id, letter_id, entity); auto_unreport = true; } int delete_num = SandFlags.GetNumber(delta_flags, SandFlags.MT_DELETED); if (delete_num == 1 || delete_num == -1) { //bool is_undelete = SandFlags.Check(delta_flags, SandFlags.DELETED_FLAG_CHAR, -1); int user_level = GroupStore.CheckDeleteRight(board_id, discussion_id, letter_id, entity, delete_num == -1); //delta_flags = SandFlags.DELETED_FLAG_CHAR + (delete_num * user_level).ToString(); //delta_flags = SandFlags.MultiplyNumber(delta_flags, SandFlags.DELETED_FLAG_CHAR, user_level); delta_flags = SandFlags.Operate(delta_flags, new FlagOperation { type = FlagOperation.Type.Multiply, MetaTitle = SandFlags.MT_DELETED, N = user_level }); string current_flags = entity.GetFlags(); SandFlags.CheckLevel(current_flags, SandFlags.MT_DELETED, delta_flags); auto_unreport = true; } if (SandFlags.Check(delta_flags, SandFlags.MT_REPORT, 0)) { GroupStore.CheckUnreportRight(board_id); } else if (SandFlags.Check(delta_flags, SandFlags.MT_REPORT, 1)) { } else { if (auto_unreport) { delta_flags = SandFlags.Add(delta_flags, SandFlags.MT_REPORT, 0); } } }
public static void CreateRevision(DynamicTableEntity letter_entity, string board_id, string discussion_id, string letter_id, int version) { string partition_key = SandId.CombineId(board_id, discussion_id, letter_id); DynamicTableEntity entity = new DynamicTableEntity(partition_key, SandId.MakeRevisionId(version)); LetterConverter.CopyLetterRevision(letter_entity, entity, version); Warehouse.RevisionTable.Execute(TableOperation.Insert(entity)); // If an exception is thrown after revision created but before edit count in letter entity is updated, next time edit will fail because the revision already exists. }
public static void CheckEditRight(string board_id, string discussion_id, DynamicTableEntity entity) { Subtype subtype = LetterConverter.GetSubtype(entity); if (subtype == Subtype.d) { Util.ThrowUnauthorizedException("不能編輯的類型。"); } if (!CreatorConverter.IsCurrentUserCreator(entity) && !DiscussionLoadStore.IsCurrentUserDiscussionCreator(board_id, discussion_id) && !IsBoardOwner(board_id)) { Util.ThrowUnauthorizedException("沒有編輯權限。只有副板主以上、串主、或原作者可以編輯。"); } }
private static void moveForeMeta() { Regex regex = new Regex(@"^>>(.+?)\n", RegexOptions.IgnoreCase | RegexOptions.Multiline | RegexOptions.CultureInvariant); //Regex regex = new Regex(@"^>>(.+?)$", RegexOptions.IgnoreCase | RegexOptions.Multiline | RegexOptions.CultureInvariant); // some abstract contain only ">>(0,0)" and no "\n". string pkFilter = TableQuery.GenerateFilterCondition("PartitionKey", QueryComparisons.GreaterThanOrEqual, ""); TableQuery query = new TableQuery().Where(pkFilter).Select(new string[] { "flags2", "abstract" }); int count = 0; foreach (DynamicTableEntity entity in Warehouse.DiscussionLoadTable.ExecuteQuery(query)) { string flags = null; string ab = LetterConverter.GetAbstract(entity); if (ab != null) { ab = regex.Replace(ab, (Match match) => { if (match.Groups[1].Value[0] == '(') { flags = entity.GetFlags(); flags = SandFlags.Add(flags, SandFlags.MT_COORDINATE, match.Groups[1].Value); } return(string.Empty); }); } if (flags != null) { count++; entity["flags2"] = new EntityProperty(flags); entity["abstract"] = new EntityProperty(ab); Warehouse.DiscussionLoadTable.Execute(TableOperation.Merge(entity)); //if (count > 0) // break; } } }
public void AddLetter(DynamicTableEntity entity) { Subtype subtype = LetterConverter.GetSubtype(entity); if (subtype == Subtype.h) { this.viewType = entity.GetViewType(); } string json = LetterConverter.LetterToJson(entity, this.BoardId, this.DiscussionId, this.viewType); if (subtype == Subtype.h) { if (this.headingJson == null) { this.headingJson = json; } } else if (entity.RowKey == SandId.FIRST_SUBJECT_LETTER_ID) { if (this.subjectJson == null) { this.subjectJson = json; } } else if (subtype == Subtype.s || subtype == Subtype.r) { this.replyQueue.Enqueue(json); if (this.replyQueue.Count > REPLY_COUNT) { string dummy; this.replyQueue.TryDequeue(out dummy); } } // subtype d is ignored. when there are lots of subtype d, replies will be pushed out of queue. }
private void addLetter(TextWriter writer, DynamicTableEntity entity) { LetterConverter.WriteForCrawler(writer, entity, false, null); Subtype subtype = LetterConverter.GetSubtype(entity); switch (subtype) { case Subtype.h: if (this.Heading == null) { this.Heading = /*RemoveForeMeta*/ (LetterConverter.GetAbstract(entity)); } break; case Subtype.s: // when subject is split to multiple segments, subtype s will be met multiple times. if (this.Description == null) { this.Description = extractOgImage(LetterConverter.GetWholeWords(entity, false)); } break; } }