using System; using System.Collections.Generic; using System.IdentityModel.Tokens.Jwt; using System.IO; using System.Linq; using System.Threading.Tasks; using FFMpegCore; using FFMpegCore.Enums; using Google.Apis.Auth.OAuth2; using Google.Cloud.Firestore; using Grpc.Auth; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; using Microsoft.Data.SqlClient; using Microsoft.EntityFrameworkCore; using Microsoft.Net.Http.Headers; using Newtonsoft.Json; using Teso_API.Models; namespace Teso_API.Controllers { [AllowAnonymous, Route("posts")] [ApiController] public class PostsController : ControllerBase { private readonly TESOContext _context; private FirestoreDb db; public PostsController(TESOContext context) { _context = context; db = new FirestoreDbBuilder { ProjectId = ServerLocation.credentials.project_id, ChannelCredentials = GoogleCredential.FromJson(JsonConvert.SerializeObject(ServerLocation.credentials)).ToChannelCredentials(), }.Build(); } [Authorize] [Route("mypost"), HttpGet] public async Task>> GetPosts() { var accessToken = Request.Headers[HeaderNames.Authorization]; string token = accessToken; token = token.Substring(6).Trim(); var handler = new JwtSecurityTokenHandler(); var jwtToken = handler.ReadToken(token) as JwtSecurityToken; string userID = jwtToken.Claims.First(claim => claim.Type == "userGUID").Value; List postedAds = new List(); List posts = await _context.Posts.AsQueryable().Where(i => i.PublisherId == userID).OrderByDescending(t => t.Timestamp).ToListAsync(); foreach (Post post in posts) { PostedAd upload = new PostedAd(); upload.post = post; upload.likes = await _context.PostFavs.AsQueryable().Where(l => l.PostId == post.PostId).ToListAsync(); upload.comments = await _context.CommentsPosts.AsQueryable().Where(c => c.PostId == post.PostId).ToListAsync(); upload.campaignAd = await _context.CampAds.AsQueryable().AnyAsync(p => p.PostId == post.PostId); if (upload.campaignAd) { upload.campaignAdvert = await _context.CampAds.AsQueryable().Where(d => d.PostId == post.PostId).AsNoTracking().FirstAsync(); if (upload.campaignAdvert != null) { postedAds.Add(upload); } } else { postedAds.Add(upload); } } return postedAds; } [Authorize] [Route("userpost"), HttpPost] public async Task>> UserPost([FromBody] string id) { var accessToken = Request.Headers[HeaderNames.Authorization]; string token = accessToken; token = token.Substring(6).Trim(); var handler = new JwtSecurityTokenHandler(); var jwtToken = handler.ReadToken(token) as JwtSecurityToken; string userID = jwtToken.Claims.First(claim => claim.Type == "userGUID").Value; List postedAds = new List(); List posts = await _context.Posts.AsQueryable().Where(i => i.PublisherId == id) .Select(e => new Post { Aspect = e.Aspect, PlaybackID = e.PlaybackID, PostId = e.PostId, PublisherId = e.PublisherId, AssetID = e.AssetID, Timestamp = e.Timestamp, Title = e.Title, Rendition = e.Rendition, }) .OrderByDescending(t => t.Timestamp).ToListAsync(); foreach (Post post in posts) { if (!_context.ReportedContents.Any(p => p.PostId == post.PostId && p.UserGuid == userID)) { PostedAd upload = new PostedAd(); upload.post = post; upload.likes = await _context.PostFavs.AsQueryable().Where(l => l.PostId == post.PostId).ToListAsync(); upload.comments = await _context.CommentsPosts.AsQueryable().Where(c => c.PostId == post.PostId).ToListAsync(); upload.campaignAd = await _context.CampAds.AsQueryable().AnyAsync(p => p.PostId == post.PostId); if (upload.campaignAd) { upload.campaignAdvert = await _context.CampAds.AsQueryable().Where(d => d.PostId == post.PostId).AsNoTracking().FirstAsync(); if (upload.campaignAdvert != null && upload.campaignAdvert.Approved.Value) { postedAds.Add(upload); } } else { postedAds.Add(upload); } } } return postedAds; } [Authorize] [Route("homefeed"), HttpPost] public async Task>> HomeFeed() { var accessToken = Request.Headers[HeaderNames.Authorization]; string token = accessToken; token = token.Substring(6).Trim(); var handler = new JwtSecurityTokenHandler(); var jwtToken = handler.ReadToken(token) as JwtSecurityToken; string userID = jwtToken.Claims.First(claim => claim.Type == "userGUID").Value; var param = new SqlParameter[] { new SqlParameter { ParameterName = "@user", SqlValue = userID, SqlDbType = System.Data.SqlDbType.VarChar, Direction = System.Data.ParameterDirection.Input }, new SqlParameter { ParameterName = "@status", SqlValue = 0, SqlDbType = System.Data.SqlDbType.Bit, Direction = System.Data.ParameterDirection.Input }, }; List posts = await _context.Posts.FromSqlRaw("exec dbo.[usp_posts_get] @user,@status", param).ToListAsync(); return posts; } [Authorize] [Route("upload-post"), HttpPost] public async Task UploadPost(PostUpload post) { try { var accessToken = Request.Headers[HeaderNames.Authorization]; string token = accessToken; token = token.Substring(6).Trim(); var handler = new JwtSecurityTokenHandler(); var jwtToken = handler.ReadToken(token) as JwtSecurityToken; string userID = jwtToken.Claims.First(claim => claim.Type == "userGUID").Value; Post newPost = new Post(); newPost.PlaybackID = post.path; newPost.Title = post.title; newPost.Timestamp = DateTime.Now; newPost.PublisherId = userID; newPost.PostId = "TESADS" + String.Format("{0:d6}", (DateTime.Now.Ticks / 10) % 100000); newPost.AssetID = post.thumbnail; newPost.Aspect = post.aspect; WriteBatch batch = db.StartBatch(); if (!String.IsNullOrEmpty(post.campaignID)) { CampAd campaignAdvert = new CampAd(); campaignAdvert.PostId = newPost.PostId; campaignAdvert.CampaignId = post.campaignID; campaignAdvert.Approved = null; string businessID = await _context.Campaigns.AsQueryable().Where(bid => bid.CampaignId == campaignAdvert.CampaignId) .Select(b => b.BusinessId).FirstOrDefaultAsync(); TesoBusinessDetail recipient = await _context.TesoBusinessDetails.AsQueryable().Where(i => i.BusinessId == businessID).FirstOrDefaultAsync(); TesoUserDetail requester = await _context.TesoUserDetails.AsQueryable().Where(i => i.UserGUID == userID).FirstOrDefaultAsync(); DocumentReference docRef = db.Collection(ServerLocation.business_notifications).Document(businessID).Collection(businessID).Document(); Dictionary user = new Dictionary { { "notificationType", "audition" }, { "timestamp", new DateTimeOffset(DateTimeOffset.UtcNow.DateTime).ToUnixTimeMilliseconds()}, { "participant", userID }, { "participantUsername", requester.Username }, { "participantFirstname", requester.Firstname }, { "participantSurname", requester.Surname }, {"participantThumbnail",requester.ThumbnailDp }, }; batch.Set(docRef, user); _context.CampAds.Add(campaignAdvert); _context.Posts.Add(newPost); await _context.SaveChangesAsync(); await batch.CommitAsync(); } else { _context.Posts.Add(newPost); DocumentReference PostRef = db.Collection("posts").Document(newPost.PostId); Dictionary postActual = new Dictionary { { "playbackID", newPost.PlaybackID }, { "timestamp",new DateTimeOffset(DateTimeOffset.UtcNow.DateTime).ToUnixTimeMilliseconds()}, { "title",newPost.Title}, { "publisher", userID }, { "postId", newPost.PostId }, { "aspect", post.aspect }, { "assetID", newPost.AssetID}, { "rendition", newPost.Rendition}, { "campaignId",post.campaignID }, { "likes",0}, { "comments",0}, }; batch.Set(PostRef, postActual); await _context.SaveChangesAsync(); await batch.CommitAsync(); } PostedAd upload = new PostedAd(); upload.post = newPost; upload.likes = new List(); upload.comments = new List(); return Ok(upload); } catch (Exception ex) { Console.WriteLine(ex.ToString()); return StatusCode(500); } } [Authorize] [Route("add-comment"), HttpPost] public async Task CommentOnPost(CommentsPost comments) { var accessToken = Request.Headers[HeaderNames.Authorization]; string token = accessToken; token = token.Substring(6).Trim(); var handler = new JwtSecurityTokenHandler(); var jwtToken = handler.ReadToken(token) as JwtSecurityToken; string userID = jwtToken.Claims.First(claim => claim.Type == "userGUID").Value; string username = jwtToken.Claims.First(claim => claim.Type == "username").Value; string dp = await _context.TesoUserDetails.AsQueryable().Where(i => i.UserGUID == userID).Select(t => t.ThumbnailDp).FirstOrDefaultAsync(); Post post = await _context.Posts.AsQueryable().Where(p => p.PostId == comments.PostId).FirstOrDefaultAsync(); _context.CommentsPosts.Add(comments); try { await _context.SaveChangesAsync(); WriteBatch batch = db.StartBatch(); if (post.PublisherId != userID) { DocumentReference docRef = db.Collection(ServerLocation.user_notifications).Document(post.PublisherId).Collection(post.PublisherId).Document(comments.CommentId); string message = username + " commented on your post"; Dictionary user = new Dictionary { { "notificationType", "comments" }, { "timestamp", new DateTimeOffset(DateTimeOffset.UtcNow.DateTime).ToUnixTimeMilliseconds()}, { "message", message }, { "post", post.PostId}, { "thumbnail", dp }, {"post_owner", post.PublisherId} }; batch.Set(docRef, user); } DocumentReference postRef = db.Collection("posts").Document(post.PostId).Collection("comments").Document(comments.CommentId); Dictionary comment = new Dictionary { { "comment", comments.Comment }, { "timestamp", new DateTimeOffset(DateTimeOffset.UtcNow.DateTime).ToUnixTimeMilliseconds()}, { "post", post.PostId }, { "commenter", username}, { "commenterID", userID}, { "commentID", comments.CommentId}, { "thumbnail", dp }, }; batch.Set(postRef, comment); DocumentReference PostRef = db.Collection("posts").Document(post.PostId); Dictionary commentUpdate = new Dictionary { { "comments", FieldValue.Increment(1) }, }; batch.Update(PostRef, commentUpdate); await batch.CommitAsync(); } catch (Exception e) { Console.WriteLine(e.ToString()); return StatusCode(500); } return Ok(); } [Authorize] [Route("delete-comment"), HttpPost] public async Task DeleteCommentOnPost(CommentsPost comments) { var accessToken = Request.Headers[HeaderNames.Authorization]; string token = accessToken; token = token.Substring(6).Trim(); var handler = new JwtSecurityTokenHandler(); var jwtToken = handler.ReadToken(token) as JwtSecurityToken; string userID = jwtToken.Claims.First(claim => claim.Type == "userGUID").Value; string username = jwtToken.Claims.First(claim => claim.Type == "username").Value; string dp = await _context.TesoUserDetails.AsQueryable().Where(i => i.UserGUID == userID).Select(t => t.ThumbnailDp).FirstOrDefaultAsync(); Post post = await _context.Posts.AsQueryable().Where(p => p.PostId == comments.PostId).FirstOrDefaultAsync(); _context.CommentsPosts.Remove(comments); try { WriteBatch batch = db.StartBatch(); DocumentReference postRef = db.Collection("posts").Document(post.PostId).Collection("comments").Document(comments.CommentId); batch.Delete(postRef); DocumentReference PostRef = db.Collection("posts").Document(post.PostId); Dictionary commentUpdate = new Dictionary { { "comments", FieldValue.Increment(-1) }, }; batch.Update(PostRef, commentUpdate); await batch.CommitAsync(); await _context.SaveChangesAsync(); } catch (Exception e) { Console.WriteLine(e.ToString()); return StatusCode(500); } return Ok(); } [Authorize] [Route("add-like"), HttpPost] public async Task LikePost(PostFav postFav) { var accessToken = Request.Headers[HeaderNames.Authorization]; string token = accessToken; token = token.Substring(6).Trim(); var handler = new JwtSecurityTokenHandler(); var jwtToken = handler.ReadToken(token) as JwtSecurityToken; string userID = jwtToken.Claims.First(claim => claim.Type == "userGUID").Value; string username = jwtToken.Claims.First(claim => claim.Type == "username").Value; string dp = await _context.TesoUserDetails.AsQueryable().Where(i => i.UserGUID == userID).Select(t => t.ThumbnailDp).FirstOrDefaultAsync(); bool reward = false; Post post = await _context.Posts.AsQueryable().Where(p => p.PostId == postFav.PostId).FirstOrDefaultAsync(); CampAd campAdvert = await _context.CampAds.AsQueryable().Where(p => p.PostId == postFav.PostId).FirstOrDefaultAsync(); WriteBatch batch = db.StartBatch(); if (campAdvert != null) { int currentLikes = await _context.PostFavs.AsQueryable().Where(cl => cl.PostId == postFav.PostId).CountAsync(); if ((currentLikes + 1) % 2 == 0) { reward = true; } } if (reward) { CampaignFund funds = await _context.CampaignFunds.AsQueryable().Where(t => t.CampaignId == campAdvert.CampaignId).FirstOrDefaultAsync(); if (funds.CoinsAvailable.Value > 0) { funds.CoinsAvailable--; UserFinance userFinance = await _context.UserFinances.AsQueryable().Where(f => f.UserGUID == post.PublisherId).FirstOrDefaultAsync(); userFinance.Gold++; _context.UserTransactions.Add(new UserTransaction { CoinAmount = 1, CoinType = "TESCNS02", RealCash = decimal.Parse("0.0"), Timestamp = DateTime.Now, TransactionID = String.Format("{0:d9}", (DateTime.Now.Ticks / 10) % 10000000) + userID, UserGUID = post.PublisherId, TransactionType = "TCT004", Comments = "Campaign ad reward payment" }); if (funds.CoinsAvailable == 0) { Campaign campaign = await _context.Campaigns.AsQueryable().Where(c => c.CampaignId == campAdvert.CampaignId).FirstOrDefaultAsync(); campaign.EndDate = DateTime.Now; campaign.Status = "ended"; DocumentReference BusdocRef = db.Collection(ServerLocation.business_notifications).Document(campaign.BusinessId).Collection(campaign.BusinessId).Document(); Dictionary Bususer = new Dictionary { { "notificationType", "campaign" }, { "timestamp", new DateTimeOffset(DateTimeOffset.UtcNow.DateTime).ToUnixTimeMilliseconds()}, { "message", $"Your campaign titled {campaign.Title} has ended as all rewards have been claimed !!!" }, }; batch.Set(BusdocRef, Bususer); } DocumentReference docRef2 = db.Collection(ServerLocation.user_notifications).Document(post.PublisherId).Collection(post.PublisherId).Document(); Dictionary user2 = new Dictionary { { "notificationType", "reward" }, { "timestamp", new DateTimeOffset(DateTimeOffset.UtcNow.DateTime).ToUnixTimeMilliseconds()}, { "message", "Congratulations you have received 1 gold coin for an ad you posted" }, {"recipient",post.PublisherId }, {"reward","1" }, }; batch.Set(docRef2, user2); } } _context.PostFavs.Add(postFav); try { await _context.SaveChangesAsync(); if (post.PublisherId != userID) { DocumentReference docRef = db.Collection(ServerLocation.user_notifications).Document(post.PublisherId).Collection(post.PublisherId).Document(postFav.CountId); string message = username + " liked your post"; Dictionary user = new Dictionary { { "notificationType", "likes" }, { "timestamp", new DateTimeOffset(DateTimeOffset.UtcNow.DateTime).ToUnixTimeMilliseconds()}, { "message", message }, { "post", post.PostId}, { "thumbnail", dp }, {"post_owner", post.PublisherId} }; batch.Set(docRef, user); } DocumentReference postRef = db.Collection("posts").Document(post.PostId).Collection("likes").Document(postFav.CountId); Dictionary comment = new Dictionary { { "timestamp", new DateTimeOffset(DateTimeOffset.UtcNow.DateTime).ToUnixTimeMilliseconds()}, { "post", JsonConvert.SerializeObject(post) }, { "admirer", username}, { "admirerID", userID}, { "thumbnail", dp }, }; batch.Set(postRef, comment); DocumentReference PostRef = db.Collection("posts").Document(post.PostId); Dictionary likeUpdate = new Dictionary { { "likes", FieldValue.Increment(1) }, }; batch.Update(PostRef, likeUpdate); await batch.CommitAsync(); } catch (Exception e) { Console.WriteLine(e.ToString()); return StatusCode(500); } return Ok(); } [Authorize] [Route("remove-like"), HttpPost] public async Task UnLikePost([FromBody] string postID) { var accessToken = Request.Headers[HeaderNames.Authorization]; string token = accessToken; token = token.Substring(6).Trim(); var handler = new JwtSecurityTokenHandler(); var jwtToken = handler.ReadToken(token) as JwtSecurityToken; string userID = jwtToken.Claims.First(claim => claim.Type == "userGUID").Value; string username = jwtToken.Claims.First(claim => claim.Type == "username").Value; string dp = await _context.TesoUserDetails.AsQueryable().Where(i => i.UserGUID == userID).Select(t => t.ThumbnailDp).FirstOrDefaultAsync(); PostFav postFav = await _context.PostFavs.AsQueryable().Where(p => p.AdmirerId == userID && p.PostId == postID).FirstOrDefaultAsync(); Post post = await _context.Posts.AsQueryable().Where(p => p.PostId == postFav.PostId).FirstOrDefaultAsync(); _context.PostFavs.Remove(postFav); try { WriteBatch batch = db.StartBatch(); DocumentReference postRef = db.Collection("posts").Document(post.PostId).Collection("likes").Document(postFav.CountId); batch.Delete(postRef); DocumentReference PostRef = db.Collection("posts").Document(post.PostId); Dictionary likeUpdate = new Dictionary { { "likes", FieldValue.Increment(-1) }, }; batch.Update(PostRef, likeUpdate); await _context.SaveChangesAsync(); await batch.CommitAsync(); } catch (Exception e) { Console.WriteLine(e.ToString()); return StatusCode(500); } return Ok(); } [Authorize] [Route("delete-post"), HttpPost] public async Task DeletePost(Post posts) { var accessToken = Request.Headers[HeaderNames.Authorization]; string token = accessToken; token = token.Substring(6).Trim(); var handler = new JwtSecurityTokenHandler(); var jwtToken = handler.ReadToken(token) as JwtSecurityToken; string userID = jwtToken.Claims.First(claim => claim.Type == "userGUID").Value; string username = jwtToken.Claims.First(claim => claim.Type == "username").Value; string dp = await _context.TesoUserDetails.AsQueryable().Where(i => i.UserGUID == userID).Select(t => t.ThumbnailDp).FirstOrDefaultAsync(); PostFav fav = await _context.PostFavs.AsQueryable().Where(p => p.PostId == posts.PostId).FirstOrDefaultAsync(); CommentsPost comment = await _context.CommentsPosts.AsQueryable().Where(p => p.PostId == posts.PostId).FirstOrDefaultAsync(); PendingDeleteFile deleteFile = new PendingDeleteFile(); deleteFile.DateDeleted = DateTime.Now; deleteFile.Filename = posts.PlaybackID; deleteFile.CountId = "TESADSDEL" + String.Format("{0:d6}", (DateTime.Now.Ticks / 10) % 100000); _context.Posts.Remove(posts); if (fav != null) _context.PostFavs.Remove(fav); if (comment != null) _context.CommentsPosts.Remove(comment); _context.PendingDeleteFiles.Add(deleteFile); try { DocumentReference postRef = db.Collection("posts").Document(posts.PostId); await _context.SaveChangesAsync(); await postRef.DeleteAsync(); } catch (Exception e) { Console.WriteLine(e.ToString()); return StatusCode(500); } return Ok(); } [Authorize] [Route("view-post"), HttpPost] public async Task WatchPost([FromBody] string postID) { var accessToken = Request.Headers[HeaderNames.Authorization]; string token = accessToken; token = token.Substring(6).Trim(); var handler = new JwtSecurityTokenHandler(); var jwtToken = handler.ReadToken(token) as JwtSecurityToken; string userID = jwtToken.Claims.First(claim => claim.Type == "userGUID").Value; string username = jwtToken.Claims.First(claim => claim.Type == "username").Value; if(_context.PostViews.Any(i => i.PostId == postID && i.UserGuid == userID)) { return Ok(); } _context.PostViews.Add(new PostView { CountId = postID + userID + DateTime.Now, Timestamp = DateTime.Now, PostId = postID, UserGuid = userID }); try { await _context.SaveChangesAsync(); } catch { } return Ok(); } [Authorize] [Route("getrendition"), HttpPost] public async Task> GetRendtion([FromBody] string id) { return await _context.Posts.AsQueryable().Where(p => p.PostId == id).Select(s=>s.Rendition).FirstOrDefaultAsync(); } [Authorize] [Route("flag-post"), HttpPost] public async Task ReportPost(ReportedContent reported) { var accessToken = Request.Headers[HeaderNames.Authorization]; string token = accessToken; token = token.Substring(6).Trim(); var handler = new JwtSecurityTokenHandler(); var jwtToken = handler.ReadToken(token) as JwtSecurityToken; string userID = jwtToken.Claims.First(claim => claim.Type == "userGUID").Value; string username = jwtToken.Claims.First(claim => claim.Type == "username").Value; ReportedContent content = new ReportedContent { PostId = reported.PostId, PublisherId = reported.PublisherId, Report = reported.Report, Timestamp = DateTime.Now, UserGuid = userID }; _context.ReportedContents.Add(content); try { await _context.SaveChangesAsync(); } catch { return StatusCode(500); } return Ok(); } [Authorize] [Route("unflag-post"), HttpPost] public async Task UnflagPost([FromBody] string postID) { var accessToken = Request.Headers[HeaderNames.Authorization]; string token = accessToken; token = token.Substring(6).Trim(); var handler = new JwtSecurityTokenHandler(); var jwtToken = handler.ReadToken(token) as JwtSecurityToken; string userID = jwtToken.Claims.First(claim => claim.Type == "userGUID").Value; string username = jwtToken.Claims.First(claim => claim.Type == "username").Value; ReportedContent content = await _context.ReportedContents.AsQueryable().Where(e => e.PostId == postID && e.UserGuid == userID).FirstOrDefaultAsync(); _context.ReportedContents.Remove(content); try { await _context.SaveChangesAsync(); } catch { return StatusCode(500); } return Ok(); } private static async Task DeleteCollection(CollectionReference collectionReference, int batchSize) { QuerySnapshot snapshot = await collectionReference.Limit(batchSize).GetSnapshotAsync(); IReadOnlyList documents = snapshot.Documents; while (documents.Count > 0) { foreach (DocumentSnapshot document in documents) { Console.WriteLine("Deleting document {0}", document.Id); await document.Reference.DeleteAsync(); } snapshot = await collectionReference.Limit(batchSize).GetSnapshotAsync(); documents = snapshot.Documents; } Console.WriteLine("Finished deleting all documents from the collection."); } } }