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);
        }
예제 #2
0
        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);
        }
예제 #3
0
        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);;
        }
예제 #4
0
        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
            });
        }
예제 #5
0
        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);
        }
예제 #6
0
 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();
     });
 }
예제 #7
0
        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);
        }
예제 #8
0
        // 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);
                }
            }
        }
    }
예제 #11
0
        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")]