Backend for the Teso project written in 2022
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

565 lines
27 KiB

3 months ago
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.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<ActionResult<IEnumerable<PostedAd>>> 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<PostedAd> postedAds = new List<PostedAd>();
List<Post> 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<ActionResult<IEnumerable<PostedAd>>> UserPost([FromBody] string id)
{
List<PostedAd> postedAds = new List<PostedAd>();
List<Post> posts = await _context.Posts.AsQueryable().Where(i => i.PublisherId == id).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("homefeed"), HttpPost]
public async Task<ActionResult<IEnumerable<PostedAd>>> 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;
List<PostedAd> postedAds = new List<PostedAd>();
List<Post> posts = await _context.Posts.AsQueryable().Where(i => i.PublisherId != userID).OrderByDescending(t => t.Timestamp).Take(100).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).AsNoTracking().ToListAsync();
upload.comments = await _context.CommentsPosts.AsQueryable().Where(c => c.PostId == post.PostId).AsNoTracking().ToListAsync();
upload.campaignAd = await _context.CampAds.AsQueryable().AnyAsync(p => p.PostId == post.PostId);
upload.publisher = await (from u in _context.TesoUserDetails.AsQueryable()
join e in _context.UserFinances on u.UserGUID equals e.UserGUID into finances
from fnc in finances.DefaultIfEmpty()
where u.UserGUID == post.PublisherId
select new TesoUser()
{
username = u.Username,
address = u.Address,
country = u.Country,
thumbnail_dp = u.ThumbnailDp,
DateOfBirth = u.DateOfBirth,
description = u.Description,
email = u.Email,
firstname = u.Firstname,
friends = "0",
gender = u.Gender,
gold = fnc.UserGUID != null ? fnc.Gold.ToString() : "0",
silver = fnc.UserGUID != null ? fnc.Silver.ToString() : "0",
lastname = u.Surname,
phonenumber = u.Phonenumber.ToString(),
userGUID = u.UserGUID
}).AsNoTracking().FirstOrDefaultAsync();
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("upload-post"), HttpPost]
[RequestSizeLimit(524288000)]
public async Task<ActionResult<PostedAd>> UploadPost([FromForm] 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;
var file = post.video;
if (file == null)
{
return new UnsupportedMediaTypeResult();
}
Post newPost = new Post();
newPost.Path = DateTime.Now.ToString("yyyyMMddHHmmssfff") + userID.Trim() + ".mp4";
newPost.Title = post.title;
newPost.Timestamp = DateTime.Now;
newPost.PublisherId = userID;
newPost.PostId = "TESADS" + String.Format("{0:d6}", (DateTime.Now.Ticks / 10) % 100000);
newPost.Thumbnail = post.thumbnail;
newPost.Aspect = post.aspect;
using (var fileStream = new FileStream(ServerLocation.videoAds + newPost.Path , FileMode.Create))
{
await file.CopyToAsync(fileStream);
}
//await FFMpegArguments
//.FromFileInput(ServerLocation.videoAds + "raw" + newPost.Path)
//.OutputToFile(ServerLocation.videoAds + newPost.Path, false, options => options
// // .WithVideoCodec(VideoCodec.LibX264)
// //.WithConstantRateFactor(21)
// //.WithAudioCodec(AudioCodec.Aac)
// //.WithVariableBitrate(4)
// //.WithVideoFilters(filterOptions => filterOptions
// // .Scale(VideoSize.Original))
// .WithFastStart())
//.ProcessAsynchronously();
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<string, object> user = new Dictionary<string, object>
{
{ "notificationType", "audition" },
{ "timestamp", new DateTimeOffset(DateTimeOffset.UtcNow.DateTime).ToUnixTimeMilliseconds()},
{ "participant", userID },
{ "participantUsername", requester.Username },
{ "participantFirstname", requester.Firstname },
{ "participantSurname", requester.Surname },
{"participantThumbnail",requester.ThumbnailDp },
};
_context.CampAds.Add(campaignAdvert);
_context.Posts.Add(newPost);
await _context.SaveChangesAsync();
await docRef.SetAsync(user);
}
else
{
_context.Posts.Add(newPost);
await _context.SaveChangesAsync();
}
PostedAd upload = new PostedAd();
upload.post = newPost;
upload.likes = new List<PostFav>();
upload.comments = new List<CommentsPost>();
return Ok(upload);
}
catch (Exception ex)
{
Console.WriteLine(ex.ToString());
return StatusCode(500);
}
}
[Authorize]
[Route("add-comment"), HttpPost]
public async Task<ActionResult> 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();
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<string, object> user = new Dictionary<string, object>
{
{ "notificationType", "comments" },
{ "timestamp", new DateTimeOffset(DateTimeOffset.UtcNow.DateTime).ToUnixTimeMilliseconds()},
{ "message", message },
{ "post", post.PostId},
{ "thumbnail", dp },
{"post_owner", post.PublisherId}
};
await docRef.SetAsync(user);
}
DocumentReference postRef = db.Collection("posts").Document("comments").Collection(post.PostId).Document(comments.CommentId);
Dictionary<string, object> comment = new Dictionary<string, object>
{
{ "comment", comments.Comment },
{ "timestamp", new DateTimeOffset(DateTimeOffset.UtcNow.DateTime).ToUnixTimeMilliseconds()},
{ "post", post.PostId },
{ "commenter", username},
{ "commenterID", userID},
{ "commentID", comments.CommentId},
{ "thumbnail", dp },
};
await postRef.SetAsync(comment);
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
return StatusCode(500);
}
return Ok();
}
[Authorize]
[Route("delete-comment"), HttpPost]
public async Task<ActionResult> 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
{
DocumentReference postRef = db.Collection("posts").Document("comments").Collection(post.PostId).Document(comments.CommentId);
await postRef.DeleteAsync();
await _context.SaveChangesAsync();
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
return StatusCode(500);
}
return Ok();
}
[Authorize]
[Route("add-like"), HttpPost]
public async Task<ActionResult> 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<string, object> Bususer = new Dictionary<string, object>
{
{ "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<string, object> user2 = new Dictionary<string, object>
{
{ "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<string, object> user = new Dictionary<string, object>
{
{ "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("likes").Collection(post.PostId).Document(postFav.CountId);
Dictionary<string, object> comment = new Dictionary<string, object>
{
{ "timestamp", new DateTimeOffset(DateTimeOffset.UtcNow.DateTime).ToUnixTimeMilliseconds()},
{ "post", JsonConvert.SerializeObject(post) },
{ "admirer", username},
{ "admirerID", userID},
{ "thumbnail", dp },
};
batch.Set(postRef, comment);
await batch.CommitAsync();
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
return StatusCode(500);
}
return Ok();
}
[Authorize]
[Route("remove-like"), HttpPost]
public async Task<ActionResult> 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
{
DocumentReference postRef = db.Collection("posts").Document("likes").Collection(post.PostId).Document(postFav.CountId);
await postRef.DeleteAsync();
await _context.SaveChangesAsync();
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
return StatusCode(500);
}
return Ok();
}
[Authorize]
[Route("delete-post"), HttpPost]
public async Task<ActionResult> 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.Path;
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
{
CollectionReference postRefLikes = db.Collection("posts").Document("likes").Collection(posts.PostId);
CollectionReference postRefComments = db.Collection("posts").Document("comments").Collection(posts.PostId);
await _context.SaveChangesAsync();
await DeleteCollection(postRefLikes, 10);
await DeleteCollection(postRefComments, 10);
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
return StatusCode(500);
}
return Ok();
}
private static async Task DeleteCollection(CollectionReference collectionReference, int batchSize)
{
QuerySnapshot snapshot = await collectionReference.Limit(batchSize).GetSnapshotAsync();
IReadOnlyList<DocumentSnapshot> 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.");
}
}
}