public async Task <VisitorTracking> UpdateVisitTimeElapsedAsync(long visitorTrackingId, CancellationToken cancellationToken) { var entity = await this.FairplaytubeDatabaseContext.VisitorTracking .SingleOrDefaultAsync(p => p.VisitorTrackingId == visitorTrackingId, cancellationToken); if (entity != null) { entity.LastTrackedDateTime = DateTimeOffset.UtcNow; await FairplaytubeDatabaseContext.SaveChangesAsync(cancellationToken); } return(entity); }
public async Task ApproveVideoJobApplicationAsync(long videoJobApplicationId, CancellationToken cancellationToken) { var loggedInUserAzureObjectId = this.CurrentUserProvider.GetObjectId(); var videoJobApplication = await this.FairplaytubeDatabaseContext.VideoJobApplication .Include(p => p.VideoJob).ThenInclude(p => p.VideoInfo) .ThenInclude(p => p.ApplicationUser) .Where(p => p.VideoJobApplicationId == videoJobApplicationId) .SingleOrDefaultAsync(cancellationToken: cancellationToken); if (videoJobApplication is null) { throw new CustomValidationException(Localizer[VideoJobApplicationNotFoundTextKey]); } if (loggedInUserAzureObjectId != videoJobApplication.VideoJob .VideoInfo.ApplicationUser.AzureAdB2cobjectId.ToString()) { throw new CustomValidationException(Localizer[NotVideoOwnerTextKey]); } var hasApprovedApplication = await FairplaytubeDatabaseContext.VideoJobApplication .AnyAsync(p => p.VideoJobApplicationId == videoJobApplicationId && p.VideoJobApplicationStatusId == (short)Common.Global.Enums.VideoJobApplicationStatus.Selected, cancellationToken : cancellationToken); if (hasApprovedApplication) { throw new CustomValidationException(Localizer[ApprovedApplicationsExistTextKey]); } videoJobApplication.VideoJobApplicationStatusId = (short)Common.Global.Enums.VideoJobApplicationStatus.Selected; await FairplaytubeDatabaseContext.SaveChangesAsync(cancellationToken); var applicantUserEntity = await this.FairplaytubeDatabaseContext.ApplicationUser .SingleAsync(p => p.ApplicationUserId == videoJobApplication.ApplicantApplicationUserId, cancellationToken : cancellationToken); string message = String.Format(Localizer[ApprovedApplicationUserNotificationTextKey], videoJobApplication.VideoJob.Title, videoJobApplication.VideoJob.VideoInfo.Name); await HubContext.Clients.User(applicantUserEntity.AzureAdB2cobjectId.ToString()) .ReceiveMessage(new Models.Notifications.NotificationModel() { Message = message, }); await EmailService.SendEmailAsync(toEmailAddress : applicantUserEntity.EmailAddress, subject : Localizer[ApprovedApplicationEmailSubjectTextKey], body : message, isBodyHtml : true, cancellationToken : cancellationToken); }
public async Task AddAnonymousUserRequestAsync(CreateUserRequestModel createUserRequestModel, CancellationToken cancellationToken) { UserRequest userRequestEntity = new() { Description = createUserRequestModel.Description, UserRequestTypeId = (short)createUserRequestModel.UserRequestType, EmailAddress = createUserRequestModel.EmailAddress, }; await FairplaytubeDatabaseContext.UserRequest.AddAsync(userRequestEntity, cancellationToken); await FairplaytubeDatabaseContext.SaveChangesAsync(cancellationToken); await NotifyNewUserRequestToAllUsersAsync(userRequestEntity, cancellationToken);; }
public async Task AddVideoJobApplicationAsync(CreateVideoJobApplicationModel createVideoJobApplicationModel, CancellationToken cancellationToken) { var loggedInUserAzureObjectId = CurrentUserProvider.GetObjectId(); var userEntity = FairplaytubeDatabaseContext.ApplicationUser .Single(p => p.AzureAdB2cobjectId.ToString() == loggedInUserAzureObjectId); var videoJobApplicationEntity = await FairplaytubeDatabaseContext.VideoJobApplication .Include(p => p.ApplicantApplicationUser) .Include(p => p.VideoJob) .ThenInclude(p => p.VideoInfo) .ThenInclude(p => p.ApplicationUser) .SingleOrDefaultAsync(p => p.VideoJobId == createVideoJobApplicationModel.VideoJobId && p.ApplicantApplicationUser.AzureAdB2cobjectId.ToString() == loggedInUserAzureObjectId, cancellationToken: cancellationToken); if (videoJobApplicationEntity is not null) { throw new CustomValidationException(Localizer[UserApplicationAlreadyExistsTextKey]); } var videoJobEntity = await FairplaytubeDatabaseContext.VideoJob .Include(p => p.VideoInfo).ThenInclude(p => p.ApplicationUser) .SingleAsync(p => p.VideoJobId == createVideoJobApplicationModel.VideoJobId, cancellationToken: cancellationToken); if (videoJobEntity.VideoInfo.ApplicationUser .AzureAdB2cobjectId.ToString() == loggedInUserAzureObjectId) { throw new CustomValidationException(Localizer[CannotApplyToOwnedVideosJobsTextKey]); } videoJobApplicationEntity = new VideoJobApplication() { ApplicantApplicationUserId = userEntity.ApplicationUserId, ApplicantCoverLetter = createVideoJobApplicationModel.ApplicantCoverLetter, VideoJobId = createVideoJobApplicationModel.VideoJobId.Value, VideoJobApplicationStatusId = (short)Common.Global.Enums.VideoJobApplicationStatus.New }; await FairplaytubeDatabaseContext.VideoJobApplication.AddAsync(videoJobApplicationEntity, cancellationToken); await FairplaytubeDatabaseContext.SaveChangesAsync(cancellationToken); string message = String.Format(Localizer[UserHasAppliedToJobTextKey], videoJobEntity.VideoInfo.ApplicationUser.FullName, videoJobEntity.Title); await HubContext.Clients.User(videoJobEntity.VideoInfo .ApplicationUser.AzureAdB2cobjectId.ToString()) .ReceiveMessage(new Models.Notifications.NotificationModel() { Message = message }); }
private async Task <long?> LogException(HttpContext context, Exception error, long?errorId) { try { FairplaytubeDatabaseContext fairplaytubeDatabaseContext = this.CreateFairPlayTubeDbContext(context.RequestServices); ErrorLog errorLog = new() { FullException = error.ToString(), StackTrace = error.StackTrace, Message = error.Message }; await fairplaytubeDatabaseContext.ErrorLog.AddAsync(errorLog); await fairplaytubeDatabaseContext.SaveChangesAsync(); errorId = errorLog.ErrorLogId; } catch (Exception) { throw; } ProblemHttpResponse problemHttpResponse = new(); if (error is CustomValidationException) { problemHttpResponse.Detail = error.Message; } else { string userVisibleError = "An error ocurred."; if (errorId.HasValue) { userVisibleError += $" Error code: {errorId}"; } problemHttpResponse.Detail = userVisibleError; } problemHttpResponse.Status = (int)System.Net.HttpStatusCode.BadRequest; await context.Response.WriteAsJsonAsync <ProblemHttpResponse>(problemHttpResponse); return(errorId); }
private void LogApiRequests(IApplicationBuilder app) { app.Use(async(context, next) => { try { var requestMethod = context.Request.Method; var requestPath = context.Request.Path; var isApi = requestPath.StartsWithSegments("/api"); if (isApi) { var isAuthenticated = context.User.Identity.IsAuthenticated; if (isAuthenticated) { var currentUserProvider = context.RequestServices.GetRequiredService <ICurrentUserProvider>(); var userObjectId = currentUserProvider.GetObjectId(); FairplaytubeDatabaseContext fairplaytubeDatabaseContext = context.RequestServices.GetRequiredService <FairplaytubeDatabaseContext>(); var userEntity = await fairplaytubeDatabaseContext.ApplicationUser .SingleAsync(p => p.AzureAdB2cobjectId.ToString() == userObjectId); await fairplaytubeDatabaseContext.ApplicationUserApiRequest .AddAsync(new ApplicationUserApiRequest() { ApplicationUserId = userEntity.ApplicationUserId, Method = requestMethod, Path = context.Request.GetEncodedUrl() }); await fairplaytubeDatabaseContext.SaveChangesAsync(); } } } catch (Exception ex) { await LogException(context, ex, default); } await next(); }); }
public async Task AddAuthenticatedUserRequestAsync(CreateUserRequestModel createUserRequestModel, CancellationToken cancellationToken) { var userObjectId = this.CurrentUserProvider.GetObjectId(); var userEntity = await this.FairplaytubeDatabaseContext .ApplicationUser.SingleAsync(p => p.AzureAdB2cobjectId.ToString() == userObjectId, cancellationToken); if (userEntity is null) { throw new CustomValidationException(Localizer[UserNotFoundTextKey]); } UserRequest userRequestEntity = new() { Description = createUserRequestModel.Description, UserRequestTypeId = (short)createUserRequestModel.UserRequestType, EmailAddress = createUserRequestModel.EmailAddress, ApplicationUserId = userEntity.ApplicationUserId }; await FairplaytubeDatabaseContext.UserRequest.AddAsync(userRequestEntity, cancellationToken); await FairplaytubeDatabaseContext.SaveChangesAsync(cancellationToken); }
// This method gets called by the runtime. Use this method to add services to the container. // For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940 /// <summary> /// Configures the System Services /// </summary> /// <param name="services"></param> public void ConfigureServices(IServiceCollection services) { services.AddSingleton <IStringLocalizerFactory, EFStringLocalizerFactory>(); services.AddSingleton <IStringLocalizer, EFStringLocalizer>(); services.AddLocalization(); bool enablePTILibrariesLogging = Convert.ToBoolean(Configuration["EnablePTILibrariesLogging"]); GlobalPackageConfiguration.EnableHttpRequestInformationLog = enablePTILibrariesLogging; GlobalPackageConfiguration.RapidApiKey = Configuration.GetValue <string>("RapidApiKey"); services.AddSignalR(); services.AddHealthChecks().AddDbContextCheck <FairplaytubeDatabaseContext>(); services.AddSingleton <IHttpContextAccessor, HttpContextAccessor>(); services.AddSingleton <IActionContextAccessor, ActionContextAccessor>(); services.AddTransient <ICurrentUserProvider, CurrentUserProvider>(); services.AddTransient(serviceProvider => { var fairplaytubeDatabaseContext = this.CreateFairPlayTubeDbContext(services); return(fairplaytubeDatabaseContext); }); services.AddTransient <CustomHttpClientHandler>(); services.AddTransient <CustomHttpClient>(sp => { var handler = sp.GetRequiredService <CustomHttpClientHandler>(); return(new CustomHttpClient(handler) { Timeout = TimeSpan.FromMinutes(30) }); }); ConfigureAzureTextAnalytics(services); ConfigureAzureContentModerator(services); ConfigureAzureVideoIndexer(services); ConfigureAzureBlobStorage(services); ConfigureDataStorage(services); ConfigurePayPal(services); ConfigureIpDataService(services); ConfigureIpStackService(services); ConfigureYouTube(services); ConfigureAzureTranslator(services); var smtpConfiguration = Configuration.GetSection(nameof(SmtpConfiguration)).Get <SmtpConfiguration>(); services.AddSingleton(smtpConfiguration); AddPlatformServices(services); services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme) .AddMicrosoftIdentityWebApi(Configuration.GetSection("AzureAdB2C")); services.Configure <JwtBearerOptions>(JwtBearerDefaults.AuthenticationScheme, options => { options.TokenValidationParameters.NameClaimType = "name"; options.TokenValidationParameters.RoleClaimType = "Role"; options.SaveToken = true; options.Events.OnMessageReceived = (context) => { var accessToken = context.Request.Query["access_token"]; // If the request is for our hub... var path = context.HttpContext.Request.Path; if (!string.IsNullOrEmpty(accessToken) && (path.StartsWithSegments(Common.Global.Constants.Hubs.NotificationHub))) { // Read the token out of the query string context.Token = accessToken; } return(Task.CompletedTask); }; options.Events.OnTokenValidated = async(context) => { FairplaytubeDatabaseContext fairplaytubeDatabaseContext = CreateFairPlayTubeDbContext(services); ClaimsIdentity claimsIdentity = context.Principal.Identity as ClaimsIdentity; var userObjectIdClaim = claimsIdentity.Claims.Single(p => p.Type == Common.Global.Constants.Claims.ObjectIdentifier); var user = await fairplaytubeDatabaseContext.ApplicationUser .Include(p => p.ApplicationUserRole) .ThenInclude(p => p.ApplicationRole) .Where(p => p.AzureAdB2cobjectId.ToString() == userObjectIdClaim.Value) .SingleOrDefaultAsync(); var fullName = claimsIdentity.FindFirst(Common.Global.Constants.Claims.Name).Value; var emailAddress = claimsIdentity.FindFirst(Common.Global.Constants.Claims.Emails).Value; if (user != null && user.ApplicationUserRole != null) { foreach (var singleRole in user.ApplicationUserRole) { claimsIdentity.AddClaim(new Claim("Role", singleRole.ApplicationRole.Name)); } user.FullName = fullName; user.EmailAddress = emailAddress; user.LastLogIn = DateTimeOffset.UtcNow; await fairplaytubeDatabaseContext.SaveChangesAsync(); var userSubscriptionPlan = fairplaytubeDatabaseContext.ApplicationUserSubscriptionPlan .Include(p => p.SubscriptionPlan) .Where(p => p.ApplicationUserId == user.ApplicationUserId).Single(); claimsIdentity.AddClaim(new Claim("SubscriptionPlan", userSubscriptionPlan.SubscriptionPlan.Name)); } else { if (user == null) { var userRole = await fairplaytubeDatabaseContext.ApplicationRole.SingleAsync(p => p.Name == Common.Global.Constants.Roles.User); var creatorRole = await fairplaytubeDatabaseContext.ApplicationRole.SingleAsync(p => p.Name == Common.Global.Constants.Roles.Creator); user = new ApplicationUser() { LastLogIn = DateTimeOffset.UtcNow, FullName = fullName, EmailAddress = emailAddress, AzureAdB2cobjectId = Guid.Parse(userObjectIdClaim.Value) }; await fairplaytubeDatabaseContext.ApplicationUser.AddAsync(user); await fairplaytubeDatabaseContext.SaveChangesAsync(); await fairplaytubeDatabaseContext.ApplicationUserRole.AddAsync(new ApplicationUserRole() { ApplicationUserId = user.ApplicationUserId, ApplicationRoleId = userRole.ApplicationRoleId }); await fairplaytubeDatabaseContext.ApplicationUserRole.AddAsync(new ApplicationUserRole() { ApplicationUserId = user.ApplicationUserId, ApplicationRoleId = creatorRole.ApplicationRoleId }); await fairplaytubeDatabaseContext.SaveChangesAsync(); var freeSubscriptionPlan = await fairplaytubeDatabaseContext.SubscriptionPlan .SingleAsync(p => p.Name == Common.Global.Enums.SubscriptionPlan.Free.ToString()); await fairplaytubeDatabaseContext.ApplicationUserSubscriptionPlan.AddAsync( new ApplicationUserSubscriptionPlan() { ApplicationUserId = user.ApplicationUserId, SubscriptionPlanId = freeSubscriptionPlan.SubscriptionPlanId }); await fairplaytubeDatabaseContext.SaveChangesAsync(); var userSubscriptionPlan = fairplaytubeDatabaseContext.ApplicationUserSubscriptionPlan .Include(p => p.SubscriptionPlan) .Where(p => p.ApplicationUserId == user.ApplicationUserId) .Single(); claimsIdentity.AddClaim(new Claim("SubscriptionPlan", userSubscriptionPlan.SubscriptionPlan.Name)); foreach (var singleRole in user.ApplicationUserRole) { claimsIdentity.AddClaim(new Claim("Role", singleRole.ApplicationRole.Name)); } var adminUsers = await fairplaytubeDatabaseContext.ApplicationUser .Include(p => p.ApplicationUserRole).ThenInclude(p => p.ApplicationRole) .Where(p => p.ApplicationUserRole.Any(aur => aur.ApplicationRole.Name == Common.Global.Constants.Roles.Admin)) .ToListAsync(); var emailService = context.HttpContext.RequestServices .GetRequiredService <EmailService>(); foreach (var singleAdminUser in adminUsers) { await emailService.SendEmailAsync(toEmailAddress: singleAdminUser.EmailAddress, subject: "FairPlayTube - New User", body: $"<p>A new user has been created at: {context.Request.Host}</p>" + $"<p>Name: {user.FullName}</p>" + $"<p>Email: {user.EmailAddress}</p>", isBodyHtml: true, cancellationToken: CancellationToken.None); } } } }; }); services.AddControllersWithViews(); services.AddAutoMapper(configAction => { configAction.AddMaps(new[] { typeof(Startup).Assembly }); }); services.AddRazorPages(); services.AddResponseCompression(opts => { opts.MimeTypes = ResponseCompressionDefaults.MimeTypes.Concat( new[] { "application/octet-stream" }); }); services.AddHostedService <Translations.BackgroundTranslationService>(); services.AddHostedService <VideoIndexStatusService>(); bool enableSwagger = Convert.ToBoolean(Configuration["EnableSwaggerUI"]); if (enableSwagger) { var azureAdB2CInstance = Configuration["AzureAdB2C:Instance"]; var azureAdB2CDomain = Configuration["AzureAdB2C:Domain"]; var azureAdB2CClientAppClientId = Configuration["AzureAdB2C:ClientAppClientId"]; var azureAdB2ClientAppDefaultScope = Configuration["AzureAdB2C:ClientAppDefaultScope"]; services.AddSwaggerGen(c => { var basePath = AppContext.BaseDirectory; var mainAppXmlFilename = typeof(Startup).GetTypeInfo().Assembly.GetName().Name + ".xml"; var modelsFileName = typeof(FairPlayTube.Models.Video.VideoInfoModel).Assembly.GetName().Name + ".xml"; var mainAppXmlPath = Path.Combine(basePath, mainAppXmlFilename); var modelsXmlPath = Path.Combine(basePath, modelsFileName); c.IncludeXmlComments(mainAppXmlPath); c.IncludeXmlComments(modelsXmlPath); c.SwaggerDoc("v1", new Microsoft.OpenApi.Models.OpenApiInfo { Title = "FairPlayTube API" }); c.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme() { Type = SecuritySchemeType.OAuth2, Flows = new OpenApiOAuthFlows() { Implicit = new OpenApiOAuthFlow() { AuthorizationUrl = new Uri($"{azureAdB2CInstance}/{azureAdB2CDomain}/oauth2/v2.0/authorize"), TokenUrl = new Uri($"{azureAdB2CInstance}/{azureAdB2CDomain}/oauth2/v2.0/token"), Scopes = new Dictionary <string, string> { { azureAdB2ClientAppDefaultScope, "Access APIs" } } }, } }); c.OperationFilter <SecurityRequirementsOperationFilter>(); }); } services.AddFeatureManagement() .AddFeatureFilter <PaidFeatureFilter>() .UseDisabledFeaturesHandler((features, context) => { string joinedFeaturesNames = String.Join(",", features); context.Result = new ObjectResult($"Missing features: {joinedFeaturesNames}") { StatusCode = (int)System.Net.HttpStatusCode.Forbidden }; }); }
protected async override Task ExecuteAsync(CancellationToken stoppingToken) { using var scope = this.ServiceScopeFactory.CreateScope(); var videoService = scope.ServiceProvider.GetRequiredService <VideoService>(); var azureVideoIndexerService = scope.ServiceProvider.GetRequiredService <AzureVideoIndexerService>(); FairplaytubeDatabaseContext fairplaytubeDatabaseContext = scope.ServiceProvider.GetRequiredService <FairplaytubeDatabaseContext>(); var config = scope.ServiceProvider.GetRequiredService <IConfiguration>(); var videoIndexerBaseCallbackUrl = config["VideoIndexerCallbackUrl"]; var videoIndexerCallbackUrl = $"{videoIndexerBaseCallbackUrl}/api/AzureVideoIndexer/OnVideoIndexed"; var indexingPreset = "Advanced"; //TODO: Temporaily set to show capabilities, later this needs to has business logic while (!stoppingToken.IsCancellationRequested) { //Check https://stackoverflow.com/questions/48368634/how-should-i-inject-a-dbcontext-instance-into-an-ihostedservice try { await CheckProcessingVideosAsync(videoService, fairplaytubeDatabaseContext, stoppingToken); var pendingIndexingVideos = fairplaytubeDatabaseContext.VideoInfo.Where(p => p.VideoIndexStatusId == (short)Common.Global.Enums.VideoIndexStatus.Pending) .OrderBy(p => p.VideoInfoId) .Take(50); foreach (var singleVideo in pendingIndexingVideos) { var allPersonModels = await azureVideoIndexerService.GetAllPersonModelsAsync(stoppingToken); var defaultPersonModel = allPersonModels.Single(p => p.isDefault == true); stoppingToken.ThrowIfCancellationRequested(); string encodedName = HttpUtility.UrlEncode(singleVideo.Name); string encodedDescription = HttpUtility.UrlEncode(singleVideo.Description); var indexVideoResponse = await azureVideoIndexerService.UploadVideoAsync(new Uri(singleVideo.VideoBloblUrl), encodedName, encodedDescription, singleVideo.FileName, personModelId : Guid.Parse(defaultPersonModel.id), privacy : AzureVideoIndexerService.VideoPrivacy.Public, callBackUri : new Uri(videoIndexerCallbackUrl), language : singleVideo.VideoLanguageCode, indexingPreset : indexingPreset, cancellationToken : stoppingToken); singleVideo.VideoId = indexVideoResponse.id; singleVideo.IndexedVideoUrl = $"https://www.videoindexer.ai/embed/player/{singleVideo.AccountId}" + $"/{indexVideoResponse.id}/" + $"?&locale=en&location={singleVideo.Location}"; singleVideo.VideoIndexStatusId = (short)Common.Global.Enums.VideoIndexStatus.Processing; await fairplaytubeDatabaseContext.SaveChangesAsync(stoppingToken); } try { var allVideoIndexerPersons = await videoService.GetAllPersonsAsync(stoppingToken); await videoService.SavePersonsAsync(personsModels : allVideoIndexerPersons, cancellationToken : stoppingToken); } catch (Exception ex) { fairplaytubeDatabaseContext.ChangeTracker.Clear(); await fairplaytubeDatabaseContext.ErrorLog.AddAsync(new ErrorLog() { FullException = ex.ToString(), StackTrace = ex.StackTrace, Message = ex.Message }, stoppingToken); await fairplaytubeDatabaseContext.SaveChangesAsync(stoppingToken); } var detailsPagePattern = Constants.PublicVideosPages.Details.Replace("{VideoId}", String.Empty); var detailsPagesWithPendingVideoId = fairplaytubeDatabaseContext.VisitorTracking.Where(p => p.VideoInfoId == null && p.VisitedUrl.Contains(detailsPagePattern)); foreach (var singleVisitedPage in detailsPagesWithPendingVideoId) { var pageUri = new Uri(singleVisitedPage.VisitedUrl); var lastSegment = pageUri.Segments.Last().TrimEnd('/'); if (!String.IsNullOrWhiteSpace(lastSegment)) { var videoInfoEntity = fairplaytubeDatabaseContext.VideoInfo.SingleOrDefault(p => p.VideoId == lastSegment); if (videoInfoEntity != null) { singleVisitedPage.VideoInfoId = videoInfoEntity.VideoInfoId; } } } await fairplaytubeDatabaseContext.SaveChangesAsync(stoppingToken); } catch (Exception ex) { this.Logger?.LogError(exception: ex, message: ex.Message); try { fairplaytubeDatabaseContext.ChangeTracker.Clear(); await fairplaytubeDatabaseContext.ErrorLog.AddAsync(new ErrorLog() { FullException = ex.ToString(), StackTrace = ex.StackTrace, Message = ex.Message }, stoppingToken); await fairplaytubeDatabaseContext.SaveChangesAsync(stoppingToken); } catch (Exception ex1) { this.Logger?.LogError(exception: ex1, message: ex1.Message); //TODO: Add Email Notification } } this.Logger?.LogInformation($"{nameof(VideoIndexStatusService)} waiting for 5 minutes."); await Task.Delay(TimeSpan.FromMinutes(5), stoppingToken); } }
private async Task Process(CancellationToken stoppingToken) { using var scope = this.ServiceScopeFactory.CreateScope(); FairplaytubeDatabaseContext fairplaytubeDatabaseContext = scope.ServiceProvider.GetRequiredService <FairplaytubeDatabaseContext>(); var translationService = scope.ServiceProvider.GetRequiredService <TranslationService>(); var clientAppAssembly = typeof(Client.Program).Assembly; var clientAppTypes = clientAppAssembly.GetTypes(); var componentsAssembly = typeof(Components._Imports).Assembly; var componentsTypes = componentsAssembly.GetTypes(); var modelsAssembly = typeof(Models.Video.UploadVideoModel).Assembly; var modelsTypes = modelsAssembly.GetTypes(); var servicesAssembly = typeof(FairPlayTube.Services.TranslationService).Assembly; var servicesTypes = servicesAssembly.GetTypes(); var commonAssembly = typeof(FairPlayTube.Common.Global.Constants).Assembly; var commonTypes = commonAssembly.GetTypes(); List <Type> typesToCheck = new(); typesToCheck.AddRange(clientAppTypes); typesToCheck.AddRange(componentsTypes); typesToCheck.AddRange(modelsTypes); typesToCheck.AddRange(servicesTypes); typesToCheck.AddRange(commonTypes); foreach (var singleTypeToCheck in typesToCheck) { string typeFullName = singleTypeToCheck.FullName; var fields = singleTypeToCheck.GetFields( BindingFlags.Public | BindingFlags.Static | BindingFlags.FlattenHierarchy ); foreach (var singleField in fields) { var resourceKeyAttributes = singleField.GetCustomAttributes <ResourceKeyAttribute>(); if (resourceKeyAttributes != null && resourceKeyAttributes.Any()) { ResourceKeyAttribute keyAttribute = resourceKeyAttributes.Single(); var defaultValue = keyAttribute.DefaultValue; string key = singleField.GetRawConstantValue().ToString(); var entity = await fairplaytubeDatabaseContext.Resource .SingleOrDefaultAsync(p => p.CultureId == 1 && p.Key == key && p.Type == typeFullName, stoppingToken); if (entity is null) { entity = new Resource() { CultureId = 1, Key = key, Type = typeFullName, Value = keyAttribute.DefaultValue }; await fairplaytubeDatabaseContext.Resource.AddAsync(entity, stoppingToken); } } } } if (fairplaytubeDatabaseContext.ChangeTracker.HasChanges()) { await fairplaytubeDatabaseContext.SaveChangesAsync(stoppingToken); } var allEnglishUSKeys = await fairplaytubeDatabaseContext.Resource .Include(p => p.Culture) .Where(p => p.Culture.Name == "en-US") .ToListAsync(stoppingToken); TranslateRequestTextItem[] translateRequestItems = allEnglishUSKeys.Select(p => new TranslateRequestTextItem() { Text = p.Value }).ToArray(); var additionalSupportedCultures = await fairplaytubeDatabaseContext.Culture .Where(p => p.Name != "en-US").ToListAsync(cancellationToken: stoppingToken); foreach (var singleAdditionalCulture in additionalSupportedCultures) { var cultureTranslations = await translationService.TranslateAsync(translateRequestItems, "en", singleAdditionalCulture.Name, stoppingToken); var cultureEntity = await fairplaytubeDatabaseContext .Culture.SingleAsync(p => p.Name == singleAdditionalCulture.Name, cancellationToken : stoppingToken); for (int iPos = 0; iPos < cultureTranslations.Length; iPos++) { var singleEnglishUSKey = allEnglishUSKeys[iPos]; var translatedValue = cultureTranslations[iPos].translations.First().text; Resource resourceEntity = await fairplaytubeDatabaseContext.Resource .SingleOrDefaultAsync(p => p.Key == singleEnglishUSKey.Key && p.Type == singleEnglishUSKey.Type && p.CultureId == cultureEntity.CultureId, cancellationToken : stoppingToken); if (resourceEntity is null) { resourceEntity = new() { Key = singleEnglishUSKey.Key, Type = singleEnglishUSKey.Type, Value = translatedValue, CultureId = cultureEntity.CultureId }; await fairplaytubeDatabaseContext.Resource.AddAsync(resourceEntity, stoppingToken); } } if (fairplaytubeDatabaseContext.ChangeTracker.HasChanges()) { await fairplaytubeDatabaseContext.SaveChangesAsync(stoppingToken); } } } }
public async Task <PaypalPayoutBatch> SendVideoJobPaymentAsync(long videoJobId, CancellationToken cancellationToken) { var userObjectId = this.CurrentUserProvider.GetObjectId(); var user = await FairplaytubeDatabaseContext.ApplicationUser .SingleAsync(p => p.AzureAdB2cobjectId.ToString() == userObjectId, cancellationToken : cancellationToken); var videoJobEntity = await this.FairplaytubeDatabaseContext.VideoJob .Include(p => p.VideoInfo) .Include(p => p.VideoJobEscrow) .SingleOrDefaultAsync(p => p.VideoJobId == videoJobId, cancellationToken); if (videoJobEntity is null) { throw new CustomValidationException(Localizer[JobNotFoundTextKey]); } if (user.ApplicationUserId != videoJobEntity.VideoInfo.ApplicationUserId) { throw new CustomValidationException(Localizer[NotVideoOwnerTextKey]); } var acceptedApplication = await this.FairplaytubeDatabaseContext .VideoJobApplication.Include(p => p.ApplicantApplicationUser) .Where(p => p.VideoJobApplicationStatusId == (short)Common.Global.Enums.VideoJobApplicationStatus.Selected) .SingleAsync(cancellationToken: cancellationToken); var userPaypalEmailAddress = acceptedApplication.ApplicantApplicationUser.EmailAddress; string detailedMessage = $"You have been paid for your work on the FairPlayTube Platform, " + $"specifically on the video titled : {videoJobEntity.VideoInfo.Name}." + $"Job Title: {videoJobEntity.Title}" + $"Job Description: {videoJobEntity.Description}" + $"Amoung Paid: {videoJobEntity.Budget}"; CreateBatchPayoutRequest createBatchPayoutRequest = new() { sender_batch_header = new Sender_Batch_Header() { email_message = detailedMessage, email_subject = $"You have been paid on FairPlayTube", sender_batch_id = Guid.NewGuid().ToString() }, items = new Item[] { new Item() { amount = new Amount() { currency = "USD", value = videoJobEntity.Budget.ToString("0.00") }, note = $"Thank You for using FairPlayTube!. Please keep the great work. " + $"{detailedMessage}", notification_language = "en-US", receiver = userPaypalEmailAddress, recipient_type = "EMAIL", sender_item_id = Guid.NewGuid().ToString() } } }; var accessTokenResponse = await this.PaypalService.GetAccessTokenAsync(null, cancellationToken); var response = await this.PaypalService.CreateBatchPayoutAsync(createBatchPayoutRequest, accessTokenResponse.access_token, cancellationToken); PaypalPayoutBatch paypalPayoutBatch = new() { PayoutBatchId = response.batch_header.payout_batch_id, EmailMessage = createBatchPayoutRequest.sender_batch_header.email_message, EmailSubject = createBatchPayoutRequest.sender_batch_header.email_subject, SenderBatchId = createBatchPayoutRequest.sender_batch_header.sender_batch_id, PaypalPayoutBatchItem = createBatchPayoutRequest.items.Select(p => new PaypalPayoutBatchItem() { AmountCurrency = p.amount.currency, AmountValue = Convert.ToDecimal(p.amount.value), Note = p.note, NotificationLanguage = p.notification_language, RecipientType = p.recipient_type, ReceiverEmailAddress = p.receiver, SenderItemId = p.sender_item_id }).ToArray() }; await FairplaytubeDatabaseContext.PaypalPayoutBatch.AddAsync(paypalPayoutBatch, cancellationToken); acceptedApplication.VideoJobApplicationStatusId = (short)Common.Global.Enums.VideoJobApplicationStatus.Paid; videoJobEntity.VideoJobEscrow.PaypalPayoutBatchItemId = paypalPayoutBatch.PaypalPayoutBatchItem.Single().PaypalPayoutBatchItemId; await FairplaytubeDatabaseContext.SaveChangesAsync(cancellationToken); return(paypalPayoutBatch); } #region Resource Keys [ResourceKey(defaultValue: "Unable to find the specified job")]