using Microsoft.EntityFrameworkCore; using RMuseum.Models.Ganjoor; using RSecurityBackend.Models.Generic; using System; using System.Data; using System.Linq; using System.Threading.Tasks; using RSecurityBackend.Services.Implementation; using RMuseum.Models.Ganjoor.ViewModels; using System.Collections.Generic; namespace RMuseum.Services.Implementation { /// /// IGanjoorService implementation /// public partial class GanjoorService : IGanjoorService { /// /// Switch Bookmark for couplet /// /// /// /// /// public async Task> SwitchCoupletBookmark(Guid userId, int poemId, int coupletIndex) { var bookmark = await _context.GanjoorUserBookmarks.Where(b => b.UserId == userId && b.PoemId == poemId && b.CoupletIndex == coupletIndex).SingleOrDefaultAsync(); if (bookmark != null) { var res = await DeleteGanjoorBookmark(bookmark.Id, userId); if (!string.IsNullOrEmpty(res.ExceptionString)) return new RServiceResult(null, res.ExceptionString); bookmark = null; } else { if(coupletIndex < 0)//bookmark a comment { var res = await BookmarkComment(poemId, coupletIndex, userId); if (!string.IsNullOrEmpty(res.ExceptionString)) return res; bookmark = res.Result; } else { var res = await BookmarkVerse(poemId, coupletIndex, userId); if (!string.IsNullOrEmpty(res.ExceptionString)) return res; bookmark = res.Result; } } return new RServiceResult(bookmark); } /// /// Bookmark couplet if it is not /// /// /// /// /// public async Task> BookmarkCoupletIfNotBookmarked(Guid userId, int poemId, int coupletIndex) { var bookmark = await _context.GanjoorUserBookmarks.Where(b => b.UserId == userId && b.PoemId == poemId && b.CoupletIndex == coupletIndex).SingleOrDefaultAsync(); if (bookmark == null) { var res = await BookmarkVerse(poemId, coupletIndex, userId); if (!string.IsNullOrEmpty(res.ExceptionString)) return res; bookmark = res.Result; } return new RServiceResult(bookmark); } /// /// Bookmark Verse /// /// /// /// /// public async Task> BookmarkVerse(int poemId, int coupletIndex, Guid userId) { if ((await _context.GanjoorUserBookmarks.Where(b => b.UserId == userId && b.PoemId == poemId && b.CoupletIndex == coupletIndex).SingleOrDefaultAsync()) != null) { return new RServiceResult(null, "The couplet is already bookmarkeded."); } GanjoorUserBookmark bookmark = new GanjoorUserBookmark() { UserId = userId, PoemId = poemId, DateTime = DateTime.Now, CoupletIndex = coupletIndex }; _context.GanjoorUserBookmarks.Add(bookmark); await _context.SaveChangesAsync(); return new RServiceResult(bookmark); } /// /// bookmark comment /// /// /// /// /// public async Task> BookmarkComment(int poemId, int negativeCommentId, Guid userId) { if ((await _context.GanjoorUserBookmarks.Where(b => b.UserId == userId && b.PoemId == poemId && b.CoupletIndex == negativeCommentId).SingleOrDefaultAsync()) != null) { return new RServiceResult(null, "The comment is already bookmarkeded."); } int commentId = -negativeCommentId; var comment = await _context.GanjoorComments.AsNoTracking().Where(c => c.Id == commentId).SingleOrDefaultAsync(); if(comment == null) { return new RServiceResult(null, "The comment is deleted."); } GanjoorUserBookmark bookmark = new GanjoorUserBookmark() { UserId = userId, PoemId = poemId, DateTime = DateTime.Now, CoupletIndex = negativeCommentId, PrivateNote = comment.HtmlComment, }; _context.GanjoorUserBookmarks.Add(bookmark); await _context.SaveChangesAsync(); return new RServiceResult(bookmark); } /// /// get user ganjoor bookmarks (only Id, CoupletIndex and DateTime are valid) /// /// /// /// public async Task> GetPoemUserBookmarks(Guid userId, int poemId) { GanjoorUserBookmarkViewModel[] bookmarks = await _context.GanjoorUserBookmarks .Where(b => b.PoemId == poemId && b.UserId == userId) .Select(b => new GanjoorUserBookmarkViewModel() { Id = b.Id, CoupletIndex = b.CoupletIndex, DateTime = b.DateTime, PrivateNote = b.PrivateNote } ) .ToArrayAsync(); return new RServiceResult(bookmarks); } /// /// get verse bookmarks /// /// /// /// /// public async Task> IsCoupletBookmarked(Guid userId, int poemId, int coupletIndex) { return new RServiceResult(await _context.GanjoorUserBookmarks.Where(b => b.PoemId == poemId && b.CoupletIndex == coupletIndex && b.UserId == userId).AnyAsync()); } /// /// delete user bookmark /// /// /// /// to make sure a user can not delete another user's bookmarks /// public async Task> DeleteGanjoorBookmark(Guid bookmarkId, Guid userId) { GanjoorUserBookmark bookmark = await _context.GanjoorUserBookmarks.Where(b => b.Id == bookmarkId && b.UserId == userId).SingleOrDefaultAsync(); if (bookmark == null) { return new RServiceResult(false, "bookmark not found"); } _context.GanjoorUserBookmarks.Remove(bookmark); await _context.SaveChangesAsync(); return new RServiceResult(true); } /// /// modify bookmark private note /// /// /// to make sure a user can not modify another user's bookmarks /// /// public async Task> ModifyBookmarkPrivateNoteAsync(Guid bookmarkId, Guid userId, string note) { try { GanjoorUserBookmark bookmark = await _context.GanjoorUserBookmarks.Where(b => b.Id == bookmarkId && b.UserId == userId).SingleOrDefaultAsync(); if (bookmark == null) { return new RServiceResult(false, "bookmark not found"); } // this note is typed in the same TinyMCE editor used for comments, so it needs // the same HTML sanitizing (and the same guard against silently posting a // half-baked note when sanitizing had to drop real text because of invalid markup) if (!string.IsNullOrEmpty(note)) { var processedNote = await _ProcessCommentHtml(note, _context); if (processedNote.TextWasDropped) { return new RServiceResult(false, _BuildSanitizerDroppedTextError(processedNote.RemainingPlainText)); } note = processedNote.Html; } bookmark.PrivateNote = note; _context.Update(bookmark); await _context.SaveChangesAsync(); return new RServiceResult(true); } catch (Exception exp) { return new RServiceResult(false, exp.ToString()); } } /// /// get user bookmarks (artifacts and items) /// /// /// /// /// public async Task> GetUserBookmarks(PagingParameterModel paging, Guid userId, string q) { var source = _context.GanjoorUserBookmarks .Include(b => b.Poem).ThenInclude(p => p.Cat).ThenInclude(c => c.Poet) .Where(b => b.UserId == userId && (string.IsNullOrEmpty(q) || (!string.IsNullOrEmpty(q) && b.PrivateNote.Contains(q)))) .OrderByDescending(b => b.DateTime) .AsQueryable(); (PaginationMetadata PagingMeta, GanjoorUserBookmark[] Bookmarks) bookmarksPage = await QueryablePaginator.Paginate(source, paging); List result = new List(); foreach (var bookmark in bookmarksPage.Bookmarks) { var verses = await _context.GanjoorVerses.AsNoTracking().Where(v => v.PoemId == bookmark.PoemId && v.CoupletIndex == bookmark.CoupletIndex).OrderBy(v => v.VOrder).ToListAsync(); result.Add ( new GanjoorUserBookmarkViewModel() { Id = bookmark.Id, PoetName = bookmark.Poem.Cat.Poet.Nickname, PoetImageUrl = $"{WebServiceUrl.Url}{$"/api/ganjoor/poet/image/{bookmark.Poem.FullUrl.Substring(1, bookmark.Poem.FullUrl.IndexOf('/', 1) - 1)}.gif"}", PoemFullTitle = bookmark.Poem.FullTitle, PoemFullUrl = bookmark.Poem.FullUrl, CoupletIndex = bookmark.CoupletIndex, VerseText = verses.Count == 0 ? "" : verses[0].Text, Verse2Text = verses.Count < 2 ? "" : verses[1].Text, DateTime = bookmark.DateTime, PrivateNote = bookmark.PrivateNote } ); } return new RServiceResult<(PaginationMetadata PagingMeta, GanjoorUserBookmarkViewModel[] Bookmarks)> ((bookmarksPage.PagingMeta, result.ToArray())); } } }