From b69e1b4498a98562db4de070673e71d831db0158 Mon Sep 17 00:00:00 2001 From: Exest Date: Fri, 31 Jul 2026 12:58:36 +0300 Subject: [PATCH] Add forced update check against Gitea releases. Block startup when a newer Release exists; keep offline pharmacies working. Co-authored-by: Cursor --- docs/gitea-updates.md | 24 ++ src/ElectronicPharmacy/App.config | 9 + src/ElectronicPharmacy/Classes/AppConfig.cs | 65 ++++ .../Classes/UpdateChecker.cs | 302 ++++++++++++++++++ .../ElectronicPharmacy.csproj | 7 + src/ElectronicPharmacy/Form1.cs | 22 ++ .../HelpForms/HF_UpdateAvailable.Designer.cs | 107 +++++++ .../HelpForms/HF_UpdateAvailable.cs | 65 ++++ .../Properties/AssemblyInfo.cs | 40 +-- .../Properties/Settings.Designer.cs | 36 +++ .../Properties/Settings.settings | 9 + tools/UpdateCheckSmoke/Program.cs | 31 ++ 12 files changed, 697 insertions(+), 20 deletions(-) create mode 100644 docs/gitea-updates.md create mode 100644 src/ElectronicPharmacy/Classes/UpdateChecker.cs create mode 100644 src/ElectronicPharmacy/HelpForms/HF_UpdateAvailable.Designer.cs create mode 100644 src/ElectronicPharmacy/HelpForms/HF_UpdateAvailable.cs create mode 100644 tools/UpdateCheckSmoke/Program.cs diff --git a/docs/gitea-updates.md b/docs/gitea-updates.md new file mode 100644 index 0000000..7d82714 --- /dev/null +++ b/docs/gitea-updates.md @@ -0,0 +1,24 @@ +# Gitea + принудительные обновления десктопа + +Полная инструкция по установке Gitea: в репозитории `source` → `docs/gitea/`. + +Клиент при старте (`ElectroPharmacy_Load`) вызывает Gitea API: + +`GET {UpdateCheckBaseUrl}/api/v1/repos/{UpdateRepo}/releases/latest` + +Настройки (можно сменить без пересборки через user settings): + +| Ключ | По умолчанию | +|------|----------------| +| `UpdateCheckBaseUrl` | `https://git.24pharmdata.ru` | +| `UpdateRepo` | `pharmdata/elfisa-pharmacy` | +| `UpdateApiToken` | пусто (нужен для private releases) | + +## Регламент релиза + +1. Поднять `AssemblyVersion` / `AssemblyFileVersion` в `Properties/AssemblyInfo.cs`. +2. `git tag vX.Y.Z && git push gitea master --tags` +3. `powershell -File dist\build-release.ps1` +4. Gitea → Releases → New Release → прикрепить ZIP. + +Старый клиент с меньшей версией увидит модалку «Доступно новое обновление» и не пустит в работу. diff --git a/src/ElectronicPharmacy/App.config b/src/ElectronicPharmacy/App.config index 262f9c5..40c70be 100644 --- a/src/ElectronicPharmacy/App.config +++ b/src/ElectronicPharmacy/App.config @@ -42,6 +42,15 @@ + + https://git.24pharmdata.ru + + + pharmdata/elfisa-pharmacy + + + + \ No newline at end of file diff --git a/src/ElectronicPharmacy/Classes/AppConfig.cs b/src/ElectronicPharmacy/Classes/AppConfig.cs index 195d2f1..6fa57c2 100644 --- a/src/ElectronicPharmacy/Classes/AppConfig.cs +++ b/src/ElectronicPharmacy/Classes/AppConfig.cs @@ -10,6 +10,8 @@ namespace Электронная_Фармация.Classes public static class AppConfig { public const string DefaultApiBaseUrl = "https://24pharmdata.ru"; + public const string DefaultUpdateCheckBaseUrl = "https://git.24pharmdata.ru"; + public const string DefaultUpdateRepo = "pharmdata/elfisa-pharmacy"; private const string LegacyApiBaseUrl = "http://195.34.241.84:9988"; private const string ApiBaseUrlEnvVar = "ELF_API_BASE_URL"; private static bool _sqliteInteropPrepared; @@ -126,6 +128,69 @@ namespace Электронная_Фармация.Classes Settings.Default.Save(); } + /// + /// Gitea base URL for forced update checks (no trailing slash). + /// + public static string UpdateCheckBaseUrl + { + get + { + var fromEnv = Environment.GetEnvironmentVariable("ELF_UPDATE_CHECK_BASE_URL"); + if (!string.IsNullOrWhiteSpace(fromEnv)) + { + return NormalizeApiBaseUrl(fromEnv); + } + + var fromSettings = Settings.Default.UpdateCheckBaseUrl; + if (!string.IsNullOrWhiteSpace(fromSettings)) + { + return NormalizeApiBaseUrl(fromSettings); + } + + return DefaultUpdateCheckBaseUrl; + } + } + + /// + /// owner/repo on Gitea, e.g. pharmdata/elfisa-pharmacy. + /// + public static string UpdateRepo + { + get + { + var fromEnv = Environment.GetEnvironmentVariable("ELF_UPDATE_REPO"); + if (!string.IsNullOrWhiteSpace(fromEnv)) + { + return fromEnv.Trim().Trim('/'); + } + + var fromSettings = Settings.Default.UpdateRepo; + if (!string.IsNullOrWhiteSpace(fromSettings)) + { + return fromSettings.Trim().Trim('/'); + } + + return DefaultUpdateRepo; + } + } + + /// + /// Optional read-only Gitea token for private release repos. + /// + public static string UpdateApiToken + { + get + { + var fromEnv = Environment.GetEnvironmentVariable("ELF_UPDATE_API_TOKEN"); + if (!string.IsNullOrWhiteSpace(fromEnv)) + { + return fromEnv.Trim(); + } + + return Settings.Default.UpdateApiToken ?? string.Empty; + } + } + private static void EnsureSQLiteInteropInBaseDir() { // System.Data.SQLite ожидает SQLite.Interop.dll рядом с exe. diff --git a/src/ElectronicPharmacy/Classes/UpdateChecker.cs b/src/ElectronicPharmacy/Classes/UpdateChecker.cs new file mode 100644 index 0000000..1c780e6 --- /dev/null +++ b/src/ElectronicPharmacy/Classes/UpdateChecker.cs @@ -0,0 +1,302 @@ +using System; +using System.Linq; +using System.Net.Http; +using System.Net.Http.Headers; +using System.Reflection; +using System.Text.Json; +using System.Text.Json.Serialization; +using System.Threading.Tasks; + +namespace Электронная_Фармация.Classes +{ + public sealed class UpdateCheckResult + { + public bool CheckedOk { get; set; } + public bool UpdateRequired { get; set; } + public string LocalVersion { get; set; } + public string LatestVersion { get; set; } + public string ReleaseUrl { get; set; } + public string DownloadUrl { get; set; } + public string ErrorMessage { get; set; } + } + + /// + /// Checks Gitea Releases API for a newer desktop build. + /// + public static class UpdateChecker + { + private static readonly JsonSerializerOptions JsonOptions = new JsonSerializerOptions + { + PropertyNameCaseInsensitive = true + }; + + public static UpdateCheckResult CheckForUpdate() + { + return CheckForUpdate(null, null, null, null); + } + + /// + /// Overload for tests / smoke scripts (null = use AppConfig). + /// + public static UpdateCheckResult CheckForUpdate( + string baseUrl, + string repo, + string token, + string localVersionOverride) + { + try + { + return CheckForUpdateAsync(baseUrl, repo, token, localVersionOverride) + .GetAwaiter().GetResult(); + } + catch (Exception ex) + { + AppDebugLog.Info("UpdateChecker", $"Проверка обновлений пропущена: {ex.Message}"); + return new UpdateCheckResult + { + CheckedOk = false, + UpdateRequired = false, + LocalVersion = localVersionOverride ?? GetLocalVersionString(), + ErrorMessage = ex.Message + }; + } + } + + public static async Task CheckForUpdateAsync() + { + return await CheckForUpdateAsync(null, null, null, null).ConfigureAwait(false); + } + + public static async Task CheckForUpdateAsync( + string baseUrlOverride, + string repoOverride, + string tokenOverride, + string localVersionOverride) + { + var localVersion = string.IsNullOrWhiteSpace(localVersionOverride) + ? GetLocalVersionString() + : NormalizeVersion(localVersionOverride); + var result = new UpdateCheckResult + { + LocalVersion = localVersion + }; + + var baseUrl = (baseUrlOverride ?? AppConfig.UpdateCheckBaseUrl).TrimEnd('/'); + var repo = (repoOverride ?? AppConfig.UpdateRepo).Trim('/'); + if (string.IsNullOrWhiteSpace(baseUrl) || string.IsNullOrWhiteSpace(repo)) + { + result.CheckedOk = false; + result.ErrorMessage = "UpdateCheckBaseUrl/UpdateRepo не заданы"; + return result; + } + + var url = $"{baseUrl}/api/v1/repos/{repo}/releases/latest"; + using (var client = new HttpClient { Timeout = TimeSpan.FromSeconds(8) }) + { + var token = tokenOverride ?? AppConfig.UpdateApiToken; + if (!string.IsNullOrWhiteSpace(token)) + { + client.DefaultRequestHeaders.Authorization = + new AuthenticationHeaderValue("token", token.Trim()); + } + + client.DefaultRequestHeaders.Accept.Add( + new MediaTypeWithQualityHeaderValue("application/json")); + + AppDebugLog.Info("UpdateChecker", $"GET {url}"); + HttpResponseMessage response; + try + { + response = await client.GetAsync(url).ConfigureAwait(false); + } + catch (Exception ex) + { + // Offline pharmacies must continue working. + AppDebugLog.Info("UpdateChecker", $"Сеть недоступна, обновление не блокируем: {ex.Message}"); + result.CheckedOk = false; + result.ErrorMessage = ex.Message; + return result; + } + + var body = await response.Content.ReadAsStringAsync().ConfigureAwait(false); + if (!response.IsSuccessStatusCode) + { + AppDebugLog.Info("UpdateChecker", + $"releases/latest HTTP {(int)response.StatusCode}: {Truncate(body, 200)}"); + result.CheckedOk = false; + result.ErrorMessage = $"HTTP {(int)response.StatusCode}"; + return result; + } + + var release = JsonSerializer.Deserialize(body, JsonOptions); + if (release == null || string.IsNullOrWhiteSpace(release.TagName)) + { + result.CheckedOk = false; + result.ErrorMessage = "Пустой ответ releases/latest"; + return result; + } + + var latest = NormalizeVersion(release.TagName); + result.LatestVersion = latest; + result.ReleaseUrl = string.IsNullOrWhiteSpace(release.HtmlUrl) + ? $"{baseUrl}/{repo}/releases/tag/{release.TagName}" + : release.HtmlUrl; + result.DownloadUrl = PickZipAssetUrl(release) ?? result.ReleaseUrl; + result.CheckedOk = true; + result.UpdateRequired = IsRemoteNewer(latest, localVersion); + + AppDebugLog.Info("UpdateChecker", + $"Локально={localVersion}, latest={latest}, updateRequired={result.UpdateRequired}"); + return result; + } + } + + public static string GetLocalVersionString() + { + try + { + var asm = Assembly.GetExecutingAssembly(); + var file = asm.GetCustomAttribute()?.Version; + if (!string.IsNullOrWhiteSpace(file)) + { + return NormalizeVersion(file); + } + + return NormalizeVersion(asm.GetName().Version?.ToString() ?? "0.0.0.0"); + } + catch + { + return "0.0.0.0"; + } + } + + /// + /// Returns true when remoteTag is strictly newer than localVersion. + /// Accepts "v1.0.9", "1.0.9", "1.0.9.0". + /// + public static bool IsRemoteNewer(string remoteTag, string localVersion) + { + if (!TryParseVersion(remoteTag, out var remote) || + !TryParseVersion(localVersion, out var local)) + { + return false; + } + + return remote > local; + } + + public static string NormalizeVersion(string value) + { + if (string.IsNullOrWhiteSpace(value)) + { + return "0.0.0.0"; + } + + value = value.Trim(); + if (value.StartsWith("v", StringComparison.OrdinalIgnoreCase)) + { + value = value.Substring(1); + } + + // Drop pre-release suffix: 1.0.9-beta -> 1.0.9 + var dash = value.IndexOf('-'); + if (dash > 0) + { + value = value.Substring(0, dash); + } + + if (TryParseVersion(value, out var v)) + { + return v.ToString(); + } + + return value; + } + + public static bool TryParseVersion(string value, out Version version) + { + version = null; + if (string.IsNullOrWhiteSpace(value)) + { + return false; + } + + value = value.Trim(); + if (value.StartsWith("v", StringComparison.OrdinalIgnoreCase)) + { + value = value.Substring(1); + } + + var dash = value.IndexOf('-'); + if (dash > 0) + { + value = value.Substring(0, dash); + } + + var parts = value.Split('.'); + if (parts.Length == 1) + { + value = value + ".0.0.0"; + } + else if (parts.Length == 2) + { + value = value + ".0.0"; + } + else if (parts.Length == 3) + { + value = value + ".0"; + } + + return Version.TryParse(value, out version); + } + + private static string PickZipAssetUrl(GiteaRelease release) + { + if (release?.Assets == null || release.Assets.Length == 0) + { + return null; + } + + var zip = release.Assets.FirstOrDefault(a => + !string.IsNullOrWhiteSpace(a?.Name) && + a.Name.EndsWith(".zip", StringComparison.OrdinalIgnoreCase)); + if (zip == null) + { + zip = release.Assets.FirstOrDefault(a => !string.IsNullOrWhiteSpace(a?.BrowserDownloadUrl)); + } + + return zip?.BrowserDownloadUrl; + } + + private static string Truncate(string s, int max) + { + if (string.IsNullOrEmpty(s) || s.Length <= max) + { + return s ?? string.Empty; + } + + return s.Substring(0, max) + "..."; + } + + private sealed class GiteaRelease + { + [JsonPropertyName("tag_name")] + public string TagName { get; set; } + + [JsonPropertyName("html_url")] + public string HtmlUrl { get; set; } + + [JsonPropertyName("assets")] + public GiteaAsset[] Assets { get; set; } + } + + private sealed class GiteaAsset + { + [JsonPropertyName("name")] + public string Name { get; set; } + + [JsonPropertyName("browser_download_url")] + public string BrowserDownloadUrl { get; set; } + } + } +} diff --git a/src/ElectronicPharmacy/ElectronicPharmacy.csproj b/src/ElectronicPharmacy/ElectronicPharmacy.csproj index 46400ed..176bf79 100644 --- a/src/ElectronicPharmacy/ElectronicPharmacy.csproj +++ b/src/ElectronicPharmacy/ElectronicPharmacy.csproj @@ -129,6 +129,7 @@ + Form @@ -201,6 +202,12 @@ HF_Settings.cs + + Form + + + HF_UpdateAvailable.cs + Form diff --git a/src/ElectronicPharmacy/Form1.cs b/src/ElectronicPharmacy/Form1.cs index 1ce1d3e..1bde269 100644 --- a/src/ElectronicPharmacy/Form1.cs +++ b/src/ElectronicPharmacy/Form1.cs @@ -67,6 +67,28 @@ namespace Электронная_Фармация { FinalizeModernShell(); + // Принудительное обновление: если на Gitea есть более новый Release — не пускаем в работу. + // При недоступной сети не блокируем (офлайн-аптека должна открываться). + try + { + var update = UpdateChecker.CheckForUpdate(); + if (update != null && update.UpdateRequired) + { + using (var dlg = new HF_UpdateAvailable(update)) + { + UiThemeHelper.ApplyToControlTree(dlg); + dlg.ShowDialog(this); + } + + Application.Exit(); + return; + } + } + catch (Exception ex) + { + AppDebugLog.Info("App", $"Проверка обновлений пропущена: {ex.Message}"); + } + FCheckDatabaseIntegrary fCheckDatabaseIntegrary = new FCheckDatabaseIntegrary(); UiThemeHelper.ApplyToControlTree(fCheckDatabaseIntegrary); fCheckDatabaseIntegrary.ShowDialog(); diff --git a/src/ElectronicPharmacy/HelpForms/HF_UpdateAvailable.Designer.cs b/src/ElectronicPharmacy/HelpForms/HF_UpdateAvailable.Designer.cs new file mode 100644 index 0000000..07d26ce --- /dev/null +++ b/src/ElectronicPharmacy/HelpForms/HF_UpdateAvailable.Designer.cs @@ -0,0 +1,107 @@ +namespace Электронная_Фармация.HelpForms +{ + partial class HF_UpdateAvailable + { + private System.ComponentModel.IContainer components = null; + + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + private void InitializeComponent() + { + this.panelHeader = new System.Windows.Forms.Panel(); + this.lblTitle = new System.Windows.Forms.Label(); + this.lblMessage = new System.Windows.Forms.Label(); + this.btnDownload = new Elfisa.UI.Controls.ModernButton(); + this.btnExit = new Elfisa.UI.Controls.ModernButton(); + this.panelHeader.SuspendLayout(); + this.SuspendLayout(); + // + // panelHeader + // + this.panelHeader.Controls.Add(this.lblTitle); + this.panelHeader.Dock = System.Windows.Forms.DockStyle.Top; + this.panelHeader.Location = new System.Drawing.Point(0, 0); + this.panelHeader.Name = "panelHeader"; + this.panelHeader.Size = new System.Drawing.Size(520, 56); + this.panelHeader.TabIndex = 0; + // + // lblTitle + // + this.lblTitle.Font = new System.Drawing.Font("Segoe UI Semibold", 13.8F, System.Drawing.FontStyle.Bold); + this.lblTitle.ForeColor = System.Drawing.Color.White; + this.lblTitle.Location = new System.Drawing.Point(12, 10); + this.lblTitle.Name = "lblTitle"; + this.lblTitle.Size = new System.Drawing.Size(480, 36); + this.lblTitle.TabIndex = 0; + this.lblTitle.Text = "Доступно новое обновление"; + this.lblTitle.TextAlign = System.Drawing.ContentAlignment.MiddleLeft; + // + // lblMessage + // + this.lblMessage.Font = new System.Drawing.Font("Segoe UI", 11F); + this.lblMessage.Location = new System.Drawing.Point(24, 72); + this.lblMessage.Name = "lblMessage"; + this.lblMessage.Size = new System.Drawing.Size(472, 120); + this.lblMessage.TabIndex = 1; + this.lblMessage.Text = "Доступно новое обновление"; + // + // btnDownload + // + this.btnDownload.Font = new System.Drawing.Font("Segoe UI", 11F); + this.btnDownload.Location = new System.Drawing.Point(24, 220); + this.btnDownload.Name = "btnDownload"; + this.btnDownload.Size = new System.Drawing.Size(180, 40); + this.btnDownload.TabIndex = 2; + this.btnDownload.Text = "Скачать"; + this.btnDownload.Click += new System.EventHandler(this.btnDownload_Click); + // + // btnExit + // + this.btnExit.Font = new System.Drawing.Font("Segoe UI", 11F); + this.btnExit.Location = new System.Drawing.Point(316, 220); + this.btnExit.Name = "btnExit"; + this.btnExit.Size = new System.Drawing.Size(180, 40); + this.btnExit.TabIndex = 3; + this.btnExit.Text = "Выход"; + this.btnExit.Click += new System.EventHandler(this.btnExit_Click); + // + // HF_UpdateAvailable + // + this.AutoScaleDimensions = new System.Drawing.SizeF(8F, 16F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.ClientSize = new System.Drawing.Size(520, 290); + this.Controls.Add(this.btnExit); + this.Controls.Add(this.btnDownload); + this.Controls.Add(this.lblMessage); + this.Controls.Add(this.panelHeader); + this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog; + this.MaximizeBox = false; + this.MinimizeBox = false; + this.Name = "HF_UpdateAvailable"; + this.ShowIcon = false; + this.ShowInTaskbar = false; + this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent; + this.Text = "Обновление"; + this.FormClosing += new System.Windows.Forms.FormClosingEventHandler(this.HF_UpdateAvailable_FormClosing); + this.panelHeader.ResumeLayout(false); + this.ResumeLayout(false); + } + + #endregion + + private System.Windows.Forms.Panel panelHeader; + private System.Windows.Forms.Label lblTitle; + private System.Windows.Forms.Label lblMessage; + private Elfisa.UI.Controls.ModernButton btnDownload; + private Elfisa.UI.Controls.ModernButton btnExit; + } +} diff --git a/src/ElectronicPharmacy/HelpForms/HF_UpdateAvailable.cs b/src/ElectronicPharmacy/HelpForms/HF_UpdateAvailable.cs new file mode 100644 index 0000000..85b762a --- /dev/null +++ b/src/ElectronicPharmacy/HelpForms/HF_UpdateAvailable.cs @@ -0,0 +1,65 @@ +using System; +using System.Diagnostics; +using System.Windows.Forms; +using Электронная_Фармация.Classes; + +namespace Электронная_Фармация.HelpForms +{ + public partial class HF_UpdateAvailable : Form + { + private readonly UpdateCheckResult _result; + + public HF_UpdateAvailable(UpdateCheckResult result) + { + _result = result ?? throw new ArgumentNullException(nameof(result)); + InitializeComponent(); + UiThemeHelper.ApplyToControlTree(this); + + var latest = string.IsNullOrWhiteSpace(_result.LatestVersion) ? "?" : _result.LatestVersion; + var local = string.IsNullOrWhiteSpace(_result.LocalVersion) ? "?" : _result.LocalVersion; + lblMessage.Text = + $"Доступно новое обновление {latest} (у вас {local}).{Environment.NewLine}{Environment.NewLine}" + + "Для продолжения работы необходимо установить новую версию."; + } + + private void btnDownload_Click(object sender, EventArgs e) + { + var url = !string.IsNullOrWhiteSpace(_result.DownloadUrl) + ? _result.DownloadUrl + : _result.ReleaseUrl; + if (string.IsNullOrWhiteSpace(url)) + { + UiDialogs.ShowError("Ссылка на обновление не задана.", "Обновление", this); + return; + } + + try + { + Process.Start(new ProcessStartInfo + { + FileName = url, + UseShellExecute = true + }); + } + catch (Exception ex) + { + UiDialogs.ShowError($"Не удалось открыть ссылку:{Environment.NewLine}{ex.Message}", "Обновление", this); + } + } + + private void btnExit_Click(object sender, EventArgs e) + { + DialogResult = DialogResult.Abort; + Close(); + } + + private void HF_UpdateAvailable_FormClosing(object sender, FormClosingEventArgs e) + { + // Крестик / Alt+F4 — тоже выход из приложения (не пускать в работу). + if (DialogResult != DialogResult.Abort) + { + DialogResult = DialogResult.Abort; + } + } + } +} diff --git a/src/ElectronicPharmacy/Properties/AssemblyInfo.cs b/src/ElectronicPharmacy/Properties/AssemblyInfo.cs index db6856a..3251393 100644 --- a/src/ElectronicPharmacy/Properties/AssemblyInfo.cs +++ b/src/ElectronicPharmacy/Properties/AssemblyInfo.cs @@ -1,36 +1,36 @@ -using System.Reflection; +using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; -// Общие сведения об этой сборке предоставляются следующим набором -// набора атрибутов. Измените значения этих атрибутов для изменения сведений, -// связанных со сборкой. -[assembly: AssemblyTitle("Электронная Фармация")] +// +// . , +// . +[assembly: AssemblyTitle(" ")] [assembly: AssemblyDescription("")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("")] -[assembly: AssemblyProduct("Электронная Фармация")] -[assembly: AssemblyCopyright("Copyright © 2023")] +[assembly: AssemblyProduct(" ")] +[assembly: AssemblyCopyright("Copyright 2023")] [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] -// Установка значения False для параметра ComVisible делает типы в этой сборке невидимыми -// для компонентов COM. Если необходимо обратиться к типу в этой сборке через -// COM, следует установить атрибут ComVisible в TRUE для этого типа. +// False ComVisible +// COM. +// COM, ComVisible TRUE . [assembly: ComVisible(false)] -// Следующий GUID служит для идентификации библиотеки типов, если этот проект будет видимым для COM +// GUID , COM [assembly: Guid("145d8060-4187-4871-b4fb-8df795727b66")] -// Сведения о версии сборки состоят из указанных ниже четырех значений: +// : // -// Основной номер версии -// Дополнительный номер версии -// Номер сборки -// Редакция +// +// +// +// // -// Можно задать все значения или принять номера сборки и редакции по умолчанию -// используя "*", как показано ниже: +// +// "*", : // [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("1.0.3.0")] -[assembly: AssemblyFileVersion("1.0.3.0")] +[assembly: AssemblyVersion("1.0.10.0")] +[assembly: AssemblyFileVersion("1.0.10.0")] diff --git a/src/ElectronicPharmacy/Properties/Settings.Designer.cs b/src/ElectronicPharmacy/Properties/Settings.Designer.cs index bd579f2..d574351 100644 --- a/src/ElectronicPharmacy/Properties/Settings.Designer.cs +++ b/src/ElectronicPharmacy/Properties/Settings.Designer.cs @@ -167,5 +167,41 @@ namespace Электронная_Фармация.Properties { } } + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("https://git.24pharmdata.ru")] + public string UpdateCheckBaseUrl { + get { + return ((string)(this["UpdateCheckBaseUrl"])); + } + set { + this["UpdateCheckBaseUrl"] = value; + } + } + + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("pharmdata/elfisa-pharmacy")] + public string UpdateRepo { + get { + return ((string)(this["UpdateRepo"])); + } + set { + this["UpdateRepo"] = value; + } + } + + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("")] + public string UpdateApiToken { + get { + return ((string)(this["UpdateApiToken"])); + } + set { + this["UpdateApiToken"] = value; + } + } + } } diff --git a/src/ElectronicPharmacy/Properties/Settings.settings b/src/ElectronicPharmacy/Properties/Settings.settings index 83ffe4b..995ccdf 100644 --- a/src/ElectronicPharmacy/Properties/Settings.settings +++ b/src/ElectronicPharmacy/Properties/Settings.settings @@ -38,5 +38,14 @@ 01.01.0001 00:00:00 + + https://git.24pharmdata.ru + + + pharmdata/elfisa-pharmacy + + + + \ No newline at end of file diff --git a/tools/UpdateCheckSmoke/Program.cs b/tools/UpdateCheckSmoke/Program.cs new file mode 100644 index 0000000..1bacc34 --- /dev/null +++ b/tools/UpdateCheckSmoke/Program.cs @@ -0,0 +1,31 @@ +using System; +using Электронная_Фармация.Classes; + +namespace UpdateCheckSmoke +{ + internal static class Program + { + private static int Main(string[] args) + { + // args: baseUrl repo localVersion + var baseUrl = args.Length > 0 ? args[0] : "http://127.0.0.1:18765"; + var repo = args.Length > 1 ? args[1] : "pharmdata/elfisa-pharmacy"; + var local = args.Length > 2 ? args[2] : "1.0.3.0"; + + var result = UpdateChecker.CheckForUpdate(baseUrl, repo, null, local); + Console.WriteLine("CheckedOk=" + result.CheckedOk); + Console.WriteLine("UpdateRequired=" + result.UpdateRequired); + Console.WriteLine("Local=" + result.LocalVersion); + Console.WriteLine("Latest=" + result.LatestVersion); + Console.WriteLine("Download=" + result.DownloadUrl); + Console.WriteLine("Error=" + result.ErrorMessage); + + if (!result.CheckedOk) + { + return 2; + } + + return result.UpdateRequired ? 0 : 1; + } + } +}