Esempio n. 1
0
        public RedmineController(
            ILogger <TestController> logger,
            IConfigurationService configuration,
            IServiceProvider services,
            RedmineXmlImporter importer
            )
        {
            _logger   = logger;
            _config   = configuration;
            _services = services;
            _importer = importer;

            // Init
            _redmineUrl    = _config.Get("Redmine:Url");
            _redmineApiKey = _config.Get("Redmine:ApiKey");

            var _reservedThreads = 2;

            _opts = new ExecutionDataflowBlockOptions();

            if (Environment.ProcessorCount > _reservedThreads)
            {
                _opts.MaxDegreeOfParallelism = Environment.ProcessorCount - _reservedThreads;
            }

            // Checks
            if (string.IsNullOrWhiteSpace(_redmineUrl))
            {
                throw new Exception("Не настроен адрес сайта Redmine");
            }
            if (string.IsNullOrWhiteSpace(_redmineApiKey))
            {
                throw new Exception("Не настроен Apikey для доступа к Redmine");
            }
        }
Esempio n. 2
0
        /// <summary>
        /// Imports custom fields
        /// </summary>
        /// <returns></returns>
        private async Task <ImportStats> _importCustomFields()
        {
            _logger.LogDebug($"Custom fields import. Start.");

            using var client = RedmineXmlImporter.CreateWebClient();

            var uri  = new Uri($"{_redmineUrl}custom_fields.json?key={_redmineApiKey}");
            var json = await client.DownloadStringTaskAsync(uri);

            var result = new ImportStats();

            var opts = new JsonSerializerOptions
            {
                PropertyNameCaseInsensitive = true
            };

            var list = JsonSerializer.Deserialize <Models.RedmineJson.CustomFieldResponse>(json, opts);

            using var scope = _services.CreateScope();
            using var _db   = scope.ServiceProvider.GetRequiredService <DB>();

            var types = _db.CustomField.ToList();

            result.total = list.FieldList.Count;
            foreach (var item in list.FieldList)
            {
                var dbItem = types.FirstOrDefault(d => d.Id == item.Id);

                if (dbItem == null)
                {
                    dbItem = new Redmine.Models.CustomField
                    {
                        Id      = item.Id,
                        Created = DateTimeOffset.Now
                    };

                    await _db.AddAsync(dbItem);

                    result.added++;
                }

                dbItem.Name       = item.Name;
                dbItem.Type       = item.Type;
                dbItem.Format     = item.Format;
                dbItem.IsRequired = item.IsRequired;
                dbItem.IsMultiple = item.IsMultiple;

                if (_db.Entry(dbItem).State != EntityState.Unchanged)
                {
                    dbItem.Updated = DateTimeOffset.Now;
                    result.updated++;
                }
            }
            await _db.SaveChangesAsync();

            _logger.LogInformation($"Custom fields import. Finish. {list.FieldList.Count} processed.");

            return(result);
        }
Esempio n. 3
0
        /// <summary>
        /// Gets pages count and starts receiver-processor job for all pages
        /// </summary>
        /// <param name="uri">Base uri to fetch data from</param>
        /// <param name="processor">Processor function for fetched xml</param>
        /// <returns>Child elements in received xml</returns>
        private async Task <ImportStats> _doPagedJob(string uri, Func <XDocument, Task <ImportStats> > processor)
        {
            var pages = await RedmineXmlImporter.GetPageList(uri, _limit);

            var uriList = new List <string>();

            foreach (var page in pages)
            {
                uriList.Add(uri + $"&limit={_limit}&offset={page * _limit}");
            }

            return(await _doJob(uriList, processor));
        }
Esempio n. 4
0
        /// <summary>
        /// Starts received-processor job for passed list of uris
        /// </summary>
        /// <param name="uriList">Uri list to fetch and process</param>
        /// <param name="processor">Processor function for fetched xml</param>
        /// <returns>Child elements in received xml</returns>
        private async Task <ImportStats> _doJob(List <string> uriList, Func <XDocument, Task <ImportStats> > processor)
        {
            var result = new ImportStats();

            var receiveBlock = new TransformBlock <string, XDocument>(
                async(uri) =>
            {
                XDocument xDoc = null;
                try
                {
                    xDoc = await RedmineXmlImporter.ReceiveXmlAsync(uri, 0, 0);
                }
                catch (Exception e)
                {
                    var we = e as WebException;
                    if (we == null)
                    {
                        throw;
                    }

                    var resp = we.Response as HttpWebResponse;
                    if (resp?.StatusCode != HttpStatusCode.Forbidden)
                    {
                        throw;
                    }

                    // we've got 403 responsse. It's a project with disabled something.
                }
                return(xDoc);
            },
                _opts
                );

            var processBlock = new ActionBlock <XDocument>(
                async xDoc =>
            {
                if (xDoc == null)
                {
                    return;
                }
                result.Add(await processor(xDoc));
            }
                );

            receiveBlock.LinkTo(processBlock, new DataflowLinkOptions {
                PropagateCompletion = true
            });

            foreach (var uri in uriList)
            {
                receiveBlock.Post(uri);
            }

            receiveBlock.Complete();

            await receiveBlock.Completion;

            _logger.LogDebug($"Received all. {processBlock.InputCount} pages waiting for process");
            await processBlock.Completion;

            return(result);
        }
Esempio n. 5
0
        /// <summary>
        /// Imports issues priorities
        /// </summary>
        /// <returns></returns>
        private async Task <ImportStats> _importIssuePriorities()
        {
            _logger.LogDebug($"Priorities import. Start.");

            using var client = RedmineXmlImporter.CreateWebClient();

            var uri  = new Uri($"{_redmineUrl}enumerations/issue_priorities.json?key={_redmineApiKey}");
            var json = await client.DownloadStringTaskAsync(uri);

            var result = new ImportStats();

            var opts = new JsonSerializerOptions
            {
                PropertyNameCaseInsensitive = true
            };

            var list = JsonSerializer.Deserialize <Models.RedmineJson.IssuePriorityResponse>(json, opts);

            // priorities are sorted from lowest to highest
            list.PriorityList.Reverse();

            using var scope = _services.CreateScope();
            using var _db   = scope.ServiceProvider.GetRequiredService <DB>();

            var prios = _db.IssuePriority.ToList();

            _logger.LogDebug($"priorities");

            result.total = list.PriorityList.Count;
            foreach (var item in list.PriorityList)
            {
                var dbItem = prios.FirstOrDefault(d => d.Id == item.Id);

                if (dbItem == null)
                {
                    dbItem = new Redmine.Models.IssuePriority
                    {
                        Id      = item.Id,
                        Sort    = list.PriorityList.IndexOf(item) + 1, // 1 .. 5
                        Created = DateTimeOffset.Now
                    };

                    dbItem.Name = item.Name;

                    var code = $"prio{dbItem.Sort}";
                    if (!prios.Any(d => d.Code == code))
                    {
                        dbItem.Code = code;
                    }

                    await _db.AddAsync(dbItem);

                    result.added++;
                }

                if (_db.Entry(dbItem).State != EntityState.Unchanged)
                {
                    dbItem.Updated = DateTimeOffset.Now;
                    result.updated++;
                }
            }
            await _db.SaveChangesAsync();

            _logger.LogInformation($"Priorities import. Finish. {list.PriorityList.Count} processed.");

            return(result);
        }