コード例 #1
0
        private async Task <IReadOnlyList <DomainModel.Package> > FindPackagesAsync(IEnumerable <ITemplateItem> items, ProvisioningAppDBContext context)
        {
            var packages = new List <DomainModel.Package>();

            foreach (ITemplateFolder folder in items.OfType <ITemplateFolder>())
            {
                WriteLog($"Processing folder {folder.Path}...");

                try
                {
                    DomainModel.Package package = await GetPackageAsync(folder, context);

                    if (package == null)
                    {
                        continue;
                    }

                    if (!String.IsNullOrEmpty(package.DisplayName))
                    {
                        packages.Add(package);
                    }
                }
                catch (Exception ex)
                {
                    WriteLog($"Error processing folder {folder.Path}: {ex.Message} - {ex.StackTrace}");
                }
            }

            return(packages);
        }
コード例 #2
0
        private async Task FillAuthorAsync(DomainModel.Package package, string path)
        {
            if (!(_sourceProvider is IAuthorProvider ap))
            {
                return;
            }

            ITemplateAuthor author = await ap.GetAuthorAsync(path);

            if (author == null)
            {
                return;
            }
            package.Author     = author.Name;
            package.AuthorLink = author.Link;
        }
コード例 #3
0
        private async Task FillPackageAsync(DomainModel.Package package, ITemplateFile packageFile)
        {
            using (Stream stream = await packageFile.DownloadAsync())
            {
                // Crate a copy of the source stream
                MemoryStream mem = new MemoryStream();
                await stream.CopyToAsync(mem);

                mem.Position = 0;

                // Prepare the output hierarchy
                ProvisioningHierarchy hierarchy = null;

                if (packageFile.Path.EndsWith(".xml", StringComparison.InvariantCultureIgnoreCase))
                {
                    // That's an XML Provisioning Template file

                    XDocument xml = XDocument.Load(mem);
                    mem.Position = 0;

                    // Deserialize the stream into a provisioning hierarchy reading any
                    // dependecy with the Azure Blob Storage connector
                    var formatter           = XMLPnPSchemaFormatter.GetSpecificFormatter(xml.Root.Name.NamespaceName);
                    var templateLocalFolder = $"{ConfigurationManager.AppSettings["BlobTemplatesProvider:ContainerName"]}/{packageFile.Path.Substring(0, packageFile.Path.LastIndexOf('/'))}";

                    var provider = new XMLAzureStorageTemplateProvider(
                        ConfigurationManager.AppSettings["BlobTemplatesProvider:ConnectionString"],
                        templateLocalFolder);
                    formatter.Initialize(provider);

                    // Get the full hierarchy
                    hierarchy = ((IProvisioningHierarchyFormatter)formatter).ToProvisioningHierarchy(mem);
                }
                else if (packageFile.Path.EndsWith(".pnp", StringComparison.InvariantCultureIgnoreCase))
                {
                    // That's a PnP Package file

                    // Get a provider based on the in-memory .PNP Open XML file
                    OpenXMLConnector    openXmlConnector = new OpenXMLConnector(mem);
                    XMLTemplateProvider provider         = new XMLOpenXMLTemplateProvider(
                        openXmlConnector);

                    // Get the .xml provisioning template file name
                    var xmlTemplateFileName = openXmlConnector.Info?.Properties?.TemplateFileName ??
                                              packageFile.Path.Substring(packageFile.Path.LastIndexOf('/') + 1)
                                              .ToLower().Replace(".pnp", ".xml");

                    // Get the full hierarchy
                    hierarchy = provider.GetHierarchy(xmlTemplateFileName);
                }

                if (hierarchy != null)
                {
                    // We se the DisplayName to the DisplayName of the hierarchy if we don't have a siteTitle in the settings.json file
                    if (string.IsNullOrEmpty(package.DisplayName))
                    {
                        package.DisplayName = hierarchy.DisplayName;
                    }
                    package.ImagePreviewUrl = ChangeUri(packageFile.DownloadUri, hierarchy?.ImagePreviewUrl ?? String.Empty);
                    package.Description     = await GetDescriptionAsync(packageFile.GetDirectoryPath()) ?? hierarchy?.Description ?? "";

                    package.Version           = hierarchy?.Version.ToString();
                    package.PackageProperties = JsonConvert.SerializeObject(hierarchy.Parameters);
                }
            }
        }
コード例 #4
0
        private async Task <DomainModel.Package> GetPackageAsync(ITemplateFolder folder, ProvisioningAppDBContext context)
        {
            var items = await _cloneProvider.GetAsync(folder.Path, WriteLog);

            // Read settings file
            ITemplateFile settingsFile = items.OfType <ITemplateFile>().FindFile(SETTINGS_NAME);

            if (settingsFile == null)
            {
                WriteLog($"Cannot find file {SETTINGS_NAME}");
                return(null);
            }

            #region Prepare the settings file and its outline

            var settings = await settingsFile.DownloadAsJsonAsync(new TemplateSettings());

            #endregion

            // Read the package file
            ITemplateFile packageFile = items.FindFile(settings.packageFile);
            if (packageFile == null)
            {
                WriteLog($"Cannot find file {settings.packageFile}");
                return(null);
            }

            #region Fix the Preview Image URLs

            // Fix the URLs in the metadata settings
            if (settings?.metadata?.displayInfo?.previewImages != null)
            {
                int previewImagesCount = settings.metadata.displayInfo.previewImages.Length;
                for (var n = 0; n < previewImagesCount; n++)
                {
                    var previewImageUrl = settings.metadata.displayInfo.previewImages[n].url;
                    settings.metadata.displayInfo.previewImages[n].url =
                        ChangeUri(packageFile.DownloadUri, previewImageUrl);
                }
            }

            if (settings?.metadata?.displayInfo?.detailItemCategories != null)
            {
                int detailItemCategoriesCount = settings.metadata.displayInfo.detailItemCategories.Length;
                for (var n = 0; n < detailItemCategoriesCount; n++)
                {
                    if (settings.metadata.displayInfo.detailItemCategories[n].items != null)
                    {
                        var detailItemCategoryItemsCount = settings.metadata.displayInfo.detailItemCategories[n].items.Length;
                        for (var m = 0; m < detailItemCategoryItemsCount; m++)
                        {
                            var detailItemCategoryItemPreviewImageUrl = settings.metadata.displayInfo.detailItemCategories[n].items[m].previewImage;
                            if (!String.IsNullOrEmpty(detailItemCategoryItemPreviewImageUrl))
                            {
                                settings.metadata.displayInfo.detailItemCategories[n].items[m].previewImage =
                                    ChangeUri(packageFile.DownloadUri, detailItemCategoryItemPreviewImageUrl);
                            }
                        }
                    }
                }
            }

            #endregion

            var package = new DomainModel.Package
            {
                Id         = !string.IsNullOrEmpty(settings.templateId) ? new Guid(settings.templateId) : Guid.NewGuid(),
                PackageUrl = packageFile.DownloadUri.ToString(),
                // New properties for Wave2
                Promoted           = settings.promoted,
                Preview            = settings.preview,
                TimesApplied       = 0,
                PropertiesMetadata = JsonConvert.SerializeObject(settings.metadata),
                // New properties for Wave 5
                Abstract                   = settings.@abstract,
                SortOrder                  = settings.sortOrder,
                SortOrderPromoted          = settings.sortOrderPromoted,
                RepositoryRelativeUrl      = folder.Path,
                MatchingSiteBaseTemplateId = settings.matchingSiteBaseTemplateId,
                ForceNewSite               = settings.forceNewSite,
                Visible        = settings.visible,
                PageTemplateId = settings.metadata?.displayInfo?.pageTemplateId,
                // New properties for Wave 12
                DisplayName       = settings.metadata?.displayInfo?.siteTitle,
                ForceExistingSite = settings.forceExistingSite,
            };

            // Read the instructions.md and the provisioning.md files
            String instructionsContent = await GetHtmlContentAsync(folder.Path, INSTRUCTIONS_NAME);

            String provisioningContent = await GetHtmlContentAsync(folder.Path, PROVISIONING_NAME);

            package.Instructions   = instructionsContent;
            package.ProvisionRecap = provisioningContent;

            // Read any pre-requirement content files
            var preRequirementContents = items.FindFiles(i =>
                                                         i.Path.ToLower().Contains("prerequirement-") &&
                                                         i.Path.EndsWith(".md", StringComparison.InvariantCultureIgnoreCase));

            // Process content for pre-requirements, if any
            if (preRequirementContents != null)
            {
                // Get the existing content pages for the current folder
                var existingDbContentPages = context.ContentPages
                                             .ToList()
                                             .Where(cp => cp.Id.StartsWith(folder.Path, StringComparison.InvariantCultureIgnoreCase))
                                             .ToDictionary(cp => cp.Id, StringComparer.OrdinalIgnoreCase);

                foreach (var prc in preRequirementContents)
                {
                    // Get the file content
                    String fileContent = await GetHtmlContentAsync(folder.Path, prc.Path.Substring(prc.Path.LastIndexOf('/') + 1));

                    // Update Content Page, if already exists
                    if (existingDbContentPages.TryGetValue(prc.Path, out ContentPage dbContentPage))
                    {
                        dbContentPage.Content = fileContent;
                        context.Entry(dbContentPage).State = EntityState.Modified;
                    }
                    else
                    {
                        // Add new Content Page
                        dbContentPage = new ContentPage
                        {
                            Id      = prc.Path,
                            Content = fileContent,
                        };
                        context.Entry(dbContentPage).State = EntityState.Added;
                    }

                    existingDbContentPages.Remove(prc.Path);
                }

                // Remove leftover content pages, if any
                var objectStateManager = ((IObjectContextAdapter)context).ObjectContext.ObjectStateManager;
                foreach (var dbContentPage in existingDbContentPages)
                {
                    context.Entry(dbContentPage.Value).State = EntityState.Deleted;
                }
            }

            // Find the categories to apply
            if (settings.categories != null && settings.categories.Length > 0)
            {
                var dbCategories = settings.categories.Select(c =>
                {
                    Category dbCategory = context.Categories.Find(c);
                    if (dbCategory == null)
                    {
                        WriteLog($"Cannot find category with id {c}");
                    }

                    return(dbCategory);
                }).ToArray();
                package.Categories.AddRange(dbCategories);
            }

            // Find the platforms to apply
            if (settings.platforms != null && settings.platforms.Length > 0)
            {
                var dbPlatforms = settings.platforms.Select(p =>
                {
                    Platform dbPlatform = context.Platforms.Find(p);
                    if (dbPlatform == null)
                    {
                        WriteLog($"Cannot find platform with id {p}");
                    }

                    return(dbPlatform);
                }).ToArray();
                package.TargetPlatforms.AddRange(dbPlatforms);
            }

            // Find then author and fill her/his information
            await FillAuthorAsync(package, packageFile.Path);

            // Open the package and set info
            await FillPackageAsync(package, packageFile);

            return(package);
        }
コード例 #5
0
        private async Task <CanProvisionResult> CanProvisionInternal(CanProvisionModel model)
        {
            var canProvisionResult = new CanProvisionResult();

            String provisioningScope       = ConfigurationManager.AppSettings["SPPA:ProvisioningScope"];
            String provisioningEnvironment = ConfigurationManager.AppSettings["SPPA:ProvisioningEnvironment"];

            var tokenId          = $"{model.TenantId}-{model.UserPrincipalName.ToLower().GetHashCode()}-{provisioningScope}-{provisioningEnvironment}";
            var graphAccessToken = await ProvisioningAppManager.AccessTokenProvider.GetAccessTokenAsync(
                tokenId, "https://graph.microsoft.com/");

            // Retrieve the provisioning package from the database and from the Blob Storage
            var context = dbContext;

            DomainModel.Package package = null;

            // Get the package
            if (ProvisioningAppManager.IsTestingEnvironment)
            {
                // Process all packages in the test environment
                package = context.Packages.FirstOrDefault(p => p.Id == new Guid(model.PackageId));
            }
            else
            {
                // Process not-preview packages in the production environment
                package = context.Packages.FirstOrDefault(p => p.Id == new Guid(model.PackageId) && p.Preview == false);
            }

            if (package != null)
            {
                // Retrieve parameters from the package/template definition
                var packageFileUrl     = new Uri(package.PackageUrl);
                var packageLocalFolder = packageFileUrl.AbsolutePath.Substring(1,
                                                                               packageFileUrl.AbsolutePath.LastIndexOf('/') - 1);
                var packageFileName = packageFileUrl.AbsolutePath.Substring(packageLocalFolder.Length + 2);

                ProvisioningHierarchy hierarchy = GetHierarchyFromStorage(packageLocalFolder, packageFileName);

                // If we have the hierarchy
                if (hierarchy != null)
                {
                    var accessTokens = new Dictionary <String, String>();

                    AuthenticationManager authManager = new AuthenticationManager();
                    var ptai = new ProvisioningTemplateApplyingInformation();

                    // Retrieve the SPO URL for the Admin Site
                    var rootSiteUrl = model.SPORootSiteUrl;

                    // Retrieve the SPO Access Token for SPO
                    var spoAccessToken = await ProvisioningAppManager.AccessTokenProvider.GetAccessTokenAsync(
                        tokenId, rootSiteUrl,
                        ConfigurationManager.AppSettings["ida:ClientId"],
                        ConfigurationManager.AppSettings["ida:ClientSecret"],
                        ConfigurationManager.AppSettings["ida:AppUrl"]);

                    // Store the SPO Access Token for any further context cloning
                    accessTokens.Add(new Uri(rootSiteUrl).Authority, spoAccessToken);

                    // Define a PnPProvisioningContext scope to share the security context across calls
                    using (var pnpProvisioningContext = new PnPProvisioningContext(async(r, s) =>
                    {
                        if (accessTokens.ContainsKey(r))
                        {
                            // In this scenario we just use the dictionary of access tokens
                            // in fact the overall operation for sure will take less than 1 hour
                            // (in fact, it's a matter of few seconds)
                            return(await Task.FromResult(accessTokens[r]));
                        }
                        else
                        {
                            // Try to get a fresh new Access Token
                            var token = await ProvisioningAppManager.AccessTokenProvider.GetAccessTokenAsync(
                                tokenId, $"https://{r}",
                                ConfigurationManager.AppSettings["ida:ClientId"],
                                ConfigurationManager.AppSettings["ida:ClientSecret"],
                                ConfigurationManager.AppSettings["ida:AppUrl"]);

                            accessTokens.Add(r, token);

                            return(token);
                        }
                    }))
                    {
                        // If the user is an admin (SPO or Tenant) we run the Tenant level CanProvision rules
                        if (model.UserIsSPOAdmin || model.UserIsTenantAdmin)
                        {
                            // Retrieve the SPO URL for the Admin Site
                            var adminSiteUrl = model.SPORootSiteUrl.Replace(".sharepoint.com", "-admin.sharepoint.com");

                            // Retrieve the SPO Access Token for the Admin Site
                            var spoAdminAccessToken = await ProvisioningAppManager.AccessTokenProvider.GetAccessTokenAsync(
                                tokenId, adminSiteUrl,
                                ConfigurationManager.AppSettings["ida:ClientId"],
                                ConfigurationManager.AppSettings["ida:ClientSecret"],
                                ConfigurationManager.AppSettings["ida:AppUrl"]);

                            // Store the SPO Admin Access Token for any further context cloning
                            accessTokens.Add(new Uri(adminSiteUrl).Authority, spoAdminAccessToken);

                            // Connect to SPO Admin Site and evaluate the CanProvision rules for the hierarchy
                            using (var tenantContext = authManager.GetAzureADAccessTokenAuthenticatedContext(adminSiteUrl, spoAdminAccessToken))
                            {
                                using (var pnpTenantContext = PnPClientContext.ConvertFrom(tenantContext))
                                {
                                    // Creat the Tenant object for the current SPO Admin Site context
                                    TenantAdmin.Tenant tenant = new TenantAdmin.Tenant(pnpTenantContext);

                                    // Run the CanProvision rules against the current tenant
                                    canProvisionResult = CanProvisionRulesManager.CanProvision(tenant, hierarchy, null, ptai);
                                }
                            }
                        }
                        else
                        {
                            // Otherwise we run the Site level CanProvision rules

                            // Connect to SPO Root Site and evaluate the CanProvision rules for the hierarchy
                            using (var clientContext = authManager.GetAzureADAccessTokenAuthenticatedContext(rootSiteUrl, spoAccessToken))
                            {
                                using (var pnpContext = PnPClientContext.ConvertFrom(clientContext))
                                {
                                    // Run the CanProvision rules against the root site
                                    canProvisionResult = CanProvisionRulesManager.CanProvision(pnpContext.Web, hierarchy.Templates[0], ptai);
                                }
                            }
                        }
                    }
                }
            }
            else
            {
                throw new ApplicationException("Invalid request, the requested package/template is not available!");
            }

            return(canProvisionResult);
        }
コード例 #6
0
        public async Task <ProvisionContentPackResponse> ProvisionContentPack(ProvisionContentPackRequest provisionRequest)
        {
            var provisionResponse = new ProvisionContentPackResponse();

            // If the input paramenters are missing, raise a BadRequest response
            if (provisionRequest == null)
            {
                ThrowEmptyRequest();
            }

            // If the TenantId input argument is missing, raise a BadRequest response
            if (String.IsNullOrEmpty(provisionRequest.TenantId))
            {
                ThrowMissingArgument("TenantId");
            }

            // If the UserPrincipalName input argument is missing, raise a BadRequest response
            if (String.IsNullOrEmpty(provisionRequest.UserPrincipalName))
            {
                ThrowMissingArgument("UserPrincipalName");
            }

            // If the PackageIds input argument is missing, raise a BadRequest response
            if (provisionRequest.Packages == null || provisionRequest.Packages.Count == 0)
            {
                ThrowMissingArgument("Packages");
            }

            if (provisionRequest != null &&
                !String.IsNullOrEmpty(provisionRequest.TenantId) &&
                !String.IsNullOrEmpty(provisionRequest.UserPrincipalName) &&
                provisionRequest.Packages != null &&
                provisionRequest.Packages.Count > 0)
            {
                try
                {
                    // Process the AuthorizationCode request
                    String provisioningScope       = ConfigurationManager.AppSettings["SPPA:ProvisioningScope"];
                    String provisioningEnvironment = ConfigurationManager.AppSettings["SPPA:ProvisioningEnvironment"];

                    var tokenId = $"{provisionRequest.TenantId}-{provisionRequest.UserPrincipalName.ToLower().GetHashCode()}-{provisioningScope}-{provisioningEnvironment}";

                    try
                    {
                        // Retrieve the refresh token and store it in the KeyVault
                        await ProvisioningAppManager.AccessTokenProvider.SetupSecurityFromAuthorizationCodeAsync(
                            tokenId,
                            provisionRequest.AuthorizationCode,
                            provisionRequest.TenantId,
                            ConfigurationManager.AppSettings["ida:ClientId"],
                            ConfigurationManager.AppSettings["ida:ClientSecret"],
                            "https://graph.microsoft.com/",
                            provisionRequest.RedirectUri);
                    }
                    catch (Exception ex)
                    {
                        // In case of any authorization exception, raise an Unauthorized exception
                        ThrowUnauthorized(ex);
                    }

                    // Validate the Package IDs
                    var context = dbContext;
                    DomainModel.Package package = null;

                    // Get the first item to provision
                    var item = provisionRequest.Packages.First();

                    // And remove it from the whole list of items
                    provisionRequest.Packages.RemoveAt(0);
                    var childrenItems = provisionRequest.Packages;

                    // Get the package
                    if (ProvisioningAppManager.IsTestingEnvironment)
                    {
                        // Process all packages in the test environment
                        package = context.Packages.FirstOrDefault(p => p.Id == new Guid(item.PackageId));
                    }
                    else
                    {
                        // Process not-preview packages in the production environment
                        package = context.Packages.FirstOrDefault(p => p.Id == new Guid(item.PackageId) && p.Preview == false);
                    }

                    // If the package is not valid
                    if (package == null)
                    {
                        // Throw an exception accordingly
                        throw new ArgumentException("Invalid Package Id!");
                    }

                    // First of all, validate the provisioning request for pre-requirements
                    provisionResponse.CanProvisionResult = await CanProvisionInternal(
                        new CanProvisionModel
                    {
                        PackageId         = item.PackageId,
                        TenantId          = provisionRequest.TenantId,
                        UserPrincipalName = provisionRequest.UserPrincipalName,
                        SPORootSiteUrl    = provisionRequest.SPORootSiteUrl,
                        UserIsSPOAdmin    = true,  // We assume that the request comes from an Admin
                        UserIsTenantAdmin = true,  // We assume that the request comes from an Admin
                    });

                    // If the package can be provisioned onto the target
                    if (provisionResponse.CanProvisionResult.CanProvision)
                    {
                        // Prepare the provisioning request
                        var request = new ProvisioningActionModel();
                        request.ActionType               = ActionType.Tenant; // Do we want to support site/tenant or just one?
                        request.ApplyCustomTheme         = false;
                        request.ApplyTheme               = false;             // Do we need to apply any special theme?
                        request.CorrelationId            = Guid.NewGuid();
                        request.CustomLogo               = null;
                        request.DisplayName              = $"Provision Content Pack {item.PackageId}";
                        request.PackageId                = item.PackageId;
                        request.TargetSiteAlreadyExists  = false; // Do we want to check this?
                        request.TargetSiteBaseTemplateId = null;
                        request.TenantId          = provisionRequest.TenantId;
                        request.UserIsSPOAdmin    = true; // We don't use this in the job
                        request.UserIsTenantAdmin = true; // We don't use this in the job
                        request.UserPrincipalName = provisionRequest.UserPrincipalName.ToLower();
                        request.NotificationEmail = provisionRequest.NotificationEmail;
                        request.PackageProperties = item.Parameters;
                        request.ChildrenItems     = childrenItems;
                        request.Webhooks          = provisionRequest.Webhooks;

                        // Enqueue the provisioning request
                        await ProvisioningAppManager.EnqueueProvisioningRequest(request);
                    }

                    // Set the status of the provisioning request
                    provisionResponse.ProvisioningStarted = true;
                }
                catch (HttpResponseException)
                {
                    throw;
                }
                catch (Exception ex)
                {
                    // In case of any other exception, raise an InternalServerError exception
                    ThrowInternalServerError(ex);
                }
            }

            // Return to the requested URL
            return(provisionResponse);
        }
コード例 #7
0
        private async Task <DomainModel.Package> GetPackageAsync(ITemplateFolder folder, ProvisioningAppDBContext context)
        {
            var items = await _cloneProvider.GetAsync(folder.Path, WriteLog);

            // Read settings file
            ITemplateFile settingsFile = items.OfType <ITemplateFile>().FindFile(SETTINGS_NAME);

            if (settingsFile == null)
            {
                WriteLog($"Cannot find file {SETTINGS_NAME}");
                return(null);
            }

            var settings = await settingsFile.DownloadAsJsonAsync(new
            {
                @abstract         = "",
                sortOrder         = 0,
                categories        = new string[0],
                packageFile       = "",
                promoted          = false,
                sortOrderPromoted = 0,
                preview           = false,
                metadata          = new {
                    properties = new[] {
                        new {
                            name           = "",
                            caption        = "",
                            description    = "",
                            editor         = "",
                            editorSettings = "",
                        }
                    }
                }
            });

            // Read the package file
            ITemplateFile packageFile = items.FindFile(settings.packageFile);

            if (packageFile == null)
            {
                WriteLog($"Cannot find file {settings.packageFile}");
                return(null);
            }

            var package = new DomainModel.Package
            {
                Id         = Guid.NewGuid(),
                PackageUrl = packageFile.DownloadUri.ToString(),
                // New properties for Wave2
                Promoted           = settings.promoted,
                Preview            = settings.preview,
                TimesApplied       = 0,
                PropertiesMetadata = JsonConvert.SerializeObject(settings.metadata),
                // New properties for Wave 5
                Abstract              = settings.@abstract,
                SortOrder             = settings.sortOrder,
                SortOrderPromoted     = settings.sortOrderPromoted,
                RepositoryRelativeUrl = folder.Path,
            };

            // Read the instructions.md and the provisioning.md files
            String instructionsContent = await GetHtmlContentAsync(folder.Path, INSTRUCTIONS_NAME);

            String provisioningContent = await GetHtmlContentAsync(folder.Path, PROVISIONING_NAME);

            package.Instructions   = instructionsContent;
            package.ProvisionRecap = provisioningContent;

            // Find the categories to apply
            var dbCategories = settings.categories.Select(c =>
            {
                Category dbCategory = context.Categories.Find(c);
                if (dbCategory == null)
                {
                    WriteLog($"Cannot find category with id {c}");
                }

                return(dbCategory);
            }).ToArray();

            package.Categories.AddRange(dbCategories);

            // Find then author and fill his informations
            await FillAuthorAsync(package, packageFile.Path);

            // Open the package and set info
            await FillPackageAsync(package, packageFile);

            return(package);
        }
コード例 #8
0
        private void LoadPackageDataIntoModel(string packageId, ProvisioningActionModel model)
        {
            var context = GetDataContext();

            DomainModel.Package package = null;

            // Get the package
            if (Boolean.Parse(ConfigurationManager.AppSettings["TestEnvironment"]))
            {
                // Process all packages in the test environment
                package = context.Packages.FirstOrDefault(p => p.Id == new Guid(packageId));
            }
            else
            {
                // Process not-preview packages in the production environment
                package = context.Packages.FirstOrDefault(p => p.Id == new Guid(packageId) && p.Preview == false);
            }

            if (package != null)
            {
                if ((package.PackageType == PackageType.Tenant &&
                     !this.Request.Url.AbsolutePath.Contains("/tenant/")) ||
                    (package.PackageType == PackageType.SiteCollection &&
                     !this.Request.Url.AbsolutePath.Contains("/site/")))
                {
                    throw new ApplicationException("Invalid request, the requested package/template is not valid for the current request!");
                }

                model.DisplayName = package.DisplayName;
                model.ActionType  = package.PackageType == PackageType.SiteCollection ? ActionType.Site : ActionType.Tenant;

                // Configure content for instructions
                model.Instructions = package.Instructions;

                // If we don't have specific instructions
                if (model.Instructions == null)
                {
                    // Get the default instructions
                    var instructionsPage = context.ContentPages.FirstOrDefault(cp => cp.Id == "system/pages/GenericInstructions.md");

                    if (instructionsPage != null)
                    {
                        model.Instructions = instructionsPage.Content;
                    }
                }

                // Configure content for provisioning recap
                model.ProvisionRecap = package.ProvisionRecap;

                // If we don't have specific provisioning recap
                if (String.IsNullOrEmpty(model.ProvisionRecap))
                {
                    // Get the default provisioning recap
                    var provisionRecapPage = context.ContentPages.FirstOrDefault(cp => cp.Id == "system/pages/GenericProvisioning.md");

                    if (provisionRecapPage != null)
                    {
                        model.ProvisionRecap = provisionRecapPage.Content;
                    }
                }

                // Retrieve parameters from the package/template definition
                var packageFileUrl     = new Uri(package.PackageUrl);
                var packageLocalFolder = packageFileUrl.AbsolutePath.Substring(1,
                                                                               packageFileUrl.AbsolutePath.LastIndexOf('/') - 1);
                var packageFileName = packageFileUrl.AbsolutePath.Substring(packageLocalFolder.Length + 2);

                ProvisioningHierarchy hierarchy = GetHierarchyFromStorage(packageLocalFolder, packageFileName);

                // If we have the hierarchy and its parameters
                if (hierarchy != null && hierarchy.Parameters != null)
                {
                    // Use them
                    model.PackageProperties = hierarchy.Parameters;
                }
                else
                {
                    // Otherwise, use an empty list of parameters
                    model.PackageProperties = new Dictionary <string, string>();
                }

                // Configure the metadata properties
                var metadata = new
                {
                    properties = new[] {
                        new {
                            name           = "",
                            caption        = "",
                            description    = "",
                            editor         = "",
                            editorSettings = "",
                        }
                    }
                };

                var metadataProperties = JsonConvert.DeserializeAnonymousType(package.PropertiesMetadata, metadata);
                model.MetadataProperties = metadataProperties.properties.ToDictionary(
                    i => i.name,
                    i => new MetadataProperty
                {
                    Name           = i.name,
                    Caption        = i.caption,
                    Description    = i.description,
                    Editor         = i.editor,
                    EditorSettings = i.editorSettings
                });

                model.MetadataPropertiesJson = JsonConvert.SerializeObject(model.MetadataProperties);

                // Get the service description content
                var contentPage = context.ContentPages.FirstOrDefault(cp => cp.Id == "system/pages/ProvisioningIntro.md");

                if (contentPage != null)
                {
                    model.ProvisionDescription = contentPage.Content;
                }

                // Get the pre-reqs Header content
                var preReqsHeaderPage = context.ContentPages.FirstOrDefault(cp => cp.Id == "system/pages/CanProvisionPreReqsHeader.md");
                if (preReqsHeaderPage != null)
                {
                    model.MissingPreReqsHeader = preReqsHeaderPage.Content;
                }

                // Get the pre-reqs Footer content
                var preReqsFooterPage = context.ContentPages.FirstOrDefault(cp => cp.Id == "system/pages/CanProvisionPreReqsFooter.md");
                if (preReqsFooterPage != null)
                {
                    model.MissingPreReqsFooter = preReqsFooterPage.Content;
                }
            }
            else
            {
                throw new ApplicationException("Invalid request, the requested package/template is not available!");
            }
        }
コード例 #9
0
        private static void LogReporting(ProvisioningActionModel action, string provisioningEnvironment, DateTime startProvisioning, DomainModel.Package package, Int32 outcome, String details = null)
        {
            // Prepare the reporting event
            var provisioningEvent = new
            {
                EventId             = action.CorrelationId,
                EventStartDateTime  = startProvisioning,
                EventEndDateTime    = DateTime.Now,
                EventOutcome        = outcome,
                EventDetails        = details,
                EventFromProduction = provisioningEnvironment.ToUpper() == "PROD" ? 1 : 0,
                TemplateId          = action.PackageId,
                TemplateDisplayName = package?.DisplayName,
            };

            try
            {
                // Make the Azure Function call for reporting
                HttpHelper.MakePostRequest(ConfigurationManager.AppSettings["SPPA:ReportingFunctionUrl"],
                                           provisioningEvent, "application/json", null);
            }
            catch
            {
                // Intentionally ignore any reporting issue
            }
        }
コード例 #10
0
        private async Task <DomainModel.Package> GetPackageAsync(ITemplateFolder folder, ProvisioningAppDBContext context)
        {
            var items = await _cloneProvider.GetAsync(folder.Path, WriteLog);

            // Read settings file
            ITemplateFile settingsFile = items.OfType <ITemplateFile>().FindFile(SETTINGS_NAME);

            if (settingsFile == null)
            {
                WriteLog($"Cannot find file {SETTINGS_NAME}");
                return(null);
            }

            #region Prepare the settings file and its outline

            var settings = await settingsFile.DownloadAsJsonAsync(new TemplateSettings());

            #endregion

            // Read the package file
            ITemplateFile packageFile = items.FindFile(settings.packageFile);
            if (packageFile == null)
            {
                WriteLog($"Cannot find file {settings.packageFile}");
                return(null);
            }

            #region Fix the Preview Image URLs

            // Fix the URLs in the metadata settings
            if (settings?.metadata?.displayInfo?.previewImages != null)
            {
                int previewImagesCount = settings.metadata.displayInfo.previewImages.Length;
                for (var n = 0; n < previewImagesCount; n++)
                {
                    var previewImageUrl = settings.metadata.displayInfo.previewImages[n].url;
                    settings.metadata.displayInfo.previewImages[n].url =
                        ChangeUri(packageFile.DownloadUri, previewImageUrl);
                }
            }

            if (settings?.metadata?.displayInfo?.detailItemCategories != null)
            {
                int detailItemCategoriesCount = settings.metadata.displayInfo.detailItemCategories.Length;
                for (var n = 0; n < detailItemCategoriesCount; n++)
                {
                    if (settings.metadata.displayInfo.detailItemCategories[n].items != null)
                    {
                        var detailItemCategoryItemsCount = settings.metadata.displayInfo.detailItemCategories[n].items.Length;
                        for (var m = 0; m < detailItemCategoryItemsCount; m++)
                        {
                            var detailItemCategoryItemPreviewImageUrl = settings.metadata.displayInfo.detailItemCategories[n].items[m].previewImage;
                            if (!String.IsNullOrEmpty(detailItemCategoryItemPreviewImageUrl))
                            {
                                settings.metadata.displayInfo.detailItemCategories[n].items[m].previewImage =
                                    ChangeUri(packageFile.DownloadUri, detailItemCategoryItemPreviewImageUrl);
                            }
                        }
                    }
                }
            }

            #endregion

            var package = new DomainModel.Package
            {
                Id         = Guid.NewGuid(),
                PackageUrl = packageFile.DownloadUri.ToString(),
                // New properties for Wave2
                Promoted           = settings.promoted,
                Preview            = settings.preview,
                TimesApplied       = 0,
                PropertiesMetadata = JsonConvert.SerializeObject(settings.metadata),
                // New properties for Wave 5
                Abstract                   = settings.@abstract,
                SortOrder                  = settings.sortOrder,
                SortOrderPromoted          = settings.sortOrderPromoted,
                RepositoryRelativeUrl      = folder.Path,
                MatchingSiteBaseTemplateId = settings.matchingSiteBaseTemplateId,
                ForceNewSite               = settings.forceNewSite,
                Visible        = settings.visible,
                PageTemplateId = settings.metadata?.displayInfo?.pageTemplateId,
            };

            // Read the instructions.md and the provisioning.md files
            String instructionsContent = await GetHtmlContentAsync(folder.Path, INSTRUCTIONS_NAME);

            String provisioningContent = await GetHtmlContentAsync(folder.Path, PROVISIONING_NAME);

            package.Instructions   = instructionsContent;
            package.ProvisionRecap = provisioningContent;

            // Find the categories to apply
            if (settings.categories != null && settings.categories.Length > 0)
            {
                var dbCategories = settings.categories.Select(c =>
                {
                    Category dbCategory = context.Categories.Find(c);
                    if (dbCategory == null)
                    {
                        WriteLog($"Cannot find category with id {c}");
                    }

                    return(dbCategory);
                }).ToArray();
                package.Categories.AddRange(dbCategories);
            }

            // Find the platforms to apply
            if (settings.platforms != null && settings.platforms.Length > 0)
            {
                var dbPlatforms = settings.platforms.Select(p =>
                {
                    Platform dbPlatform = context.Platforms.Find(p);
                    if (dbPlatform == null)
                    {
                        WriteLog($"Cannot find platform with id {p}");
                    }

                    return(dbPlatform);
                }).ToArray();
                package.TargetPlatforms.AddRange(dbPlatforms);
            }

            // Find then author and fill his informations
            await FillAuthorAsync(package, packageFile.Path);

            // Open the package and set info
            await FillPackageAsync(package, packageFile);

            return(package);
        }