Rewrite as standalone C# WinForms app
Replace the Office Web Add-in with a native Windows application. The web add-in required Exchange/M365 for registration which is not available in all customer environments (standalone Office, POP/IMAP only). The new app: - Uses COM Interop to access Outlook contacts directly - Communicates with Starface REST API (accepts self-signed certs) - Runs as System Tray app with optional auto-sync - Profile-based config stored in %AppData% - No webserver, no certificates, no Exchange, no M365 needed - Inno Setup installer for clean MSI-style deployment - Works with any Outlook version (Classic and New) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,122 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using Newtonsoft.Json;
|
||||
using StarfaceOutlookSync.Models;
|
||||
|
||||
namespace StarfaceOutlookSync.Services
|
||||
{
|
||||
public class ProfileManager
|
||||
{
|
||||
private readonly string _dataDir;
|
||||
private readonly string _profilesFile;
|
||||
private readonly string _mappingsDir;
|
||||
|
||||
public ProfileManager()
|
||||
{
|
||||
_dataDir = Path.Combine(
|
||||
Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData),
|
||||
"StarfaceOutlookSync");
|
||||
_mappingsDir = Path.Combine(_dataDir, "mappings");
|
||||
_profilesFile = Path.Combine(_dataDir, "profiles.json");
|
||||
|
||||
Directory.CreateDirectory(_dataDir);
|
||||
Directory.CreateDirectory(_mappingsDir);
|
||||
}
|
||||
|
||||
public List<SyncProfile> GetProfiles()
|
||||
{
|
||||
try
|
||||
{
|
||||
if (!File.Exists(_profilesFile)) return new List<SyncProfile>();
|
||||
var json = File.ReadAllText(_profilesFile);
|
||||
return JsonConvert.DeserializeObject<List<SyncProfile>>(json) ?? new List<SyncProfile>();
|
||||
}
|
||||
catch { return new List<SyncProfile>(); }
|
||||
}
|
||||
|
||||
public void SaveProfiles(List<SyncProfile> profiles)
|
||||
{
|
||||
var json = JsonConvert.SerializeObject(profiles, Formatting.Indented);
|
||||
File.WriteAllText(_profilesFile, json);
|
||||
}
|
||||
|
||||
public SyncProfile GetProfile(string id)
|
||||
{
|
||||
return GetProfiles().FirstOrDefault(p => p.Id == id);
|
||||
}
|
||||
|
||||
public void AddProfile(SyncProfile profile)
|
||||
{
|
||||
var profiles = GetProfiles();
|
||||
profiles.Add(profile);
|
||||
SaveProfiles(profiles);
|
||||
}
|
||||
|
||||
public void UpdateProfile(SyncProfile profile)
|
||||
{
|
||||
var profiles = GetProfiles();
|
||||
var idx = profiles.FindIndex(p => p.Id == profile.Id);
|
||||
if (idx >= 0)
|
||||
{
|
||||
profiles[idx] = profile;
|
||||
SaveProfiles(profiles);
|
||||
}
|
||||
}
|
||||
|
||||
public void DeleteProfile(string id)
|
||||
{
|
||||
var profiles = GetProfiles().Where(p => p.Id != id).ToList();
|
||||
SaveProfiles(profiles);
|
||||
var mappingFile = Path.Combine(_mappingsDir, $"{id}.json");
|
||||
if (File.Exists(mappingFile)) File.Delete(mappingFile);
|
||||
}
|
||||
|
||||
public void UpdateLastSync(string profileId)
|
||||
{
|
||||
var profiles = GetProfiles();
|
||||
var profile = profiles.FirstOrDefault(p => p.Id == profileId);
|
||||
if (profile != null)
|
||||
{
|
||||
profile.LastSync = DateTime.Now.ToString("o");
|
||||
SaveProfiles(profiles);
|
||||
}
|
||||
}
|
||||
|
||||
public List<SyncMapping> GetMappings(string profileId)
|
||||
{
|
||||
try
|
||||
{
|
||||
var file = Path.Combine(_mappingsDir, $"{profileId}.json");
|
||||
if (!File.Exists(file)) return new List<SyncMapping>();
|
||||
return JsonConvert.DeserializeObject<List<SyncMapping>>(File.ReadAllText(file))
|
||||
?? new List<SyncMapping>();
|
||||
}
|
||||
catch { return new List<SyncMapping>(); }
|
||||
}
|
||||
|
||||
public void SaveMappings(string profileId, List<SyncMapping> mappings)
|
||||
{
|
||||
var file = Path.Combine(_mappingsDir, $"{profileId}.json");
|
||||
File.WriteAllText(file, JsonConvert.SerializeObject(mappings, Formatting.Indented));
|
||||
}
|
||||
|
||||
public void AddOrUpdateMapping(SyncMapping mapping)
|
||||
{
|
||||
var mappings = GetMappings(mapping.ProfileId);
|
||||
var existing = mappings.FindIndex(m =>
|
||||
m.OutlookEntryId == mapping.OutlookEntryId || m.StarfaceId == mapping.StarfaceId);
|
||||
if (existing >= 0)
|
||||
mappings[existing] = mapping;
|
||||
else
|
||||
mappings.Add(mapping);
|
||||
SaveMappings(mapping.ProfileId, mappings);
|
||||
}
|
||||
|
||||
public string GenerateId()
|
||||
{
|
||||
return DateTime.Now.Ticks.ToString("x") + Guid.NewGuid().ToString("N").Substring(0, 8);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user