359 lines
16 KiB
C#
359 lines
16 KiB
C#
using Google.Apis.Auth.OAuth2;
|
|
using Google.Apis.Gmail.v1;
|
|
using Google.Apis.Services;
|
|
using Google.Apis.Sheets.v4;
|
|
using Google.Apis.Sheets.v4.Data;
|
|
using Google.Apis.Util.Store;
|
|
using System.Net.Mail;
|
|
using System.Net.Mime;
|
|
using System.Reflection;
|
|
|
|
namespace AiQ_GUI
|
|
{
|
|
internal class GoogleAPI
|
|
{
|
|
public static UserCredential credential;
|
|
public static SheetsService service = new();
|
|
const string ApplicationName = "Google Sheets API .NET Quickstart";
|
|
static readonly string credPath = Environment.GetFolderPath(Environment.SpecialFolder.Personal);
|
|
public const string spreadsheetId_ModelInfo = "1bCcCr4OYqfjmydt6UqtmN4FQETezXmZRSStJdCCcqZM";
|
|
public const string DrivePath = @"G:\Shared drives\MAV Production GUI's\"; // Path to google shared drive
|
|
|
|
// Startup and make necessary connections to Google servers and make sure user is logged in
|
|
public static bool Setup()
|
|
{
|
|
try
|
|
{
|
|
string streamPath = $"{DrivePath}R50IQ\\client_secret.json";
|
|
string[] Scopes = [SheetsService.Scope.Spreadsheets];
|
|
FileStream stream = new(streamPath, FileMode.Open, FileAccess.Read);
|
|
credential = GoogleWebAuthorizationBroker.AuthorizeAsync(GoogleClientSecrets.FromStream(stream).Secrets, Scopes, "user", CancellationToken.None, new FileDataStore(credPath, true)).Result;
|
|
service = new SheetsService(new BaseClientService.Initializer()
|
|
{
|
|
HttpClientInitializer = credential,
|
|
ApplicationName = ApplicationName,
|
|
});
|
|
return true;
|
|
}
|
|
catch
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
|
|
// Write a 1D array range to a spreadsheet
|
|
public static void WriteToSS(List<object> ToWrite, string Range, string SSID)
|
|
{
|
|
ValueRange ValueRange = new() { Values = [ToWrite] };
|
|
SpreadsheetsResource.ValuesResource.UpdateRequest Update = service.Spreadsheets.Values.Update(ValueRange, SSID, Range);
|
|
Update.ValueInputOption = SpreadsheetsResource.ValuesResource.UpdateRequest.ValueInputOptionEnum.RAW;
|
|
Update.Execute();
|
|
}
|
|
|
|
// Read a range from a spreadsheet, always returns a 2D object even if 1D is requested
|
|
public static IList<IList<object>> ReadSS(string sheet, string Location)
|
|
{
|
|
return service.Spreadsheets.Values.Get(sheet, Location).Execute().Values;
|
|
}
|
|
|
|
// Checks the WIP columns of a given serial number
|
|
public static bool CheckWIP(string SerialNumber, string spreadsheetId)
|
|
{
|
|
int Row = CheckSerialNumRow(spreadsheetId, SerialNumber); // Get row of serial number - 1 because don't want next row in this case
|
|
IList<IList<object>> valuesRow = ReadSS(spreadsheetId, $"S{Row}"); // Check if that row is WIP or not
|
|
return Convert.ToBoolean(valuesRow[0][0]);
|
|
}
|
|
|
|
// Update serial number register with relevant details about the camera that has passed
|
|
public static string UpdateSpreadSheetPreTest(string spreadsheetId, Versions Vers, string CamDesc, string ModelOnTest)
|
|
{
|
|
try
|
|
{
|
|
// Finds next row to be used by length of returned array and add 1
|
|
IList<IList<object>> values = service.Spreadsheets.Values.Get(spreadsheetId, "B1:B").Execute().Values;
|
|
int nextRow = values != null ? values.Count + 1 : 0;
|
|
|
|
if (values?.Count > 0)
|
|
{
|
|
// Serial number location = nextRow - 2 (Array starts at 0 but spreadsheet starts at 1 & next row has already added one so need to get rid)
|
|
string lastSerialNumber = Convert.ToString(values[nextRow - 2][0]);
|
|
int NewSerialNumberInt = Convert.ToInt32(lastSerialNumber.Substring(1)) + 1; // Generate new serial number knowing the last
|
|
string newSerialNumber = "K" + NewSerialNumberInt.ToString();
|
|
|
|
// Send data to spreadsheet and set WIP to TRUE
|
|
List<object> oblistAE = // Write columns A-E
|
|
[
|
|
ModelOnTest,
|
|
newSerialNumber,
|
|
CamDesc,
|
|
"Pre Test: " + DateTime.Now.ToString("dd/MM/yyyy"),
|
|
Vers.version + " - " + Vers.revision + Environment.NewLine + Vers.buildtime + Environment.NewLine + Vers.proquint,
|
|
];
|
|
WriteToSS(oblistAE, $"A{nextRow}:E{nextRow}", spreadsheetId);
|
|
|
|
// Write MAC to column H
|
|
List<object> oblistH = [Vers.MAC];
|
|
WriteToSS(oblistH, $"H{nextRow}", spreadsheetId);
|
|
|
|
List<object> oblistN = [$"GUI Version: {GUIUpdate.GUIVerShort}"]; // Write column N
|
|
WriteToSS(oblistN, $"N{nextRow}", spreadsheetId);
|
|
|
|
// Write TRUE to WIP checkbox in column S
|
|
List<object> oblistS = ["TRUE"];
|
|
WriteToSS(oblistS, $"S{nextRow}", spreadsheetId);
|
|
|
|
return newSerialNumber;
|
|
}
|
|
else
|
|
{
|
|
return "Last serial number not found";
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
return $"ERROR: {ex.Message}";
|
|
}
|
|
}
|
|
|
|
// Update serial number register with relevant details about the camera that has passed
|
|
public static string UpdateSpreadSheetRePreTest(string spreadsheetId, Versions Vers)
|
|
{
|
|
try
|
|
{
|
|
int CamRow = CheckSerialNumRow(spreadsheetId, Vers.Serial);
|
|
|
|
if (CamRow != 0)
|
|
{
|
|
// Send data to spreadsheet and set WIP to TRUE
|
|
List<object> oblistDE = // Write columns D-E
|
|
[
|
|
"Pre Test: " + DateTime.Now.ToString("dd/MM/yyyy"),
|
|
Vers.version + " - " + Vers.revision + Environment.NewLine + Vers.buildtime + Environment.NewLine + Vers.proquint,
|
|
];
|
|
WriteToSS(oblistDE, $"D{CamRow}:E{CamRow}", spreadsheetId);
|
|
|
|
// Write MAC to column H
|
|
List<object> oblistH = [Vers.MAC];
|
|
WriteToSS(oblistH, $"H{CamRow}", spreadsheetId);
|
|
|
|
List<object> oblistN = [$"GUI Version: {GUIUpdate.GUIVerShort}"]; // Write column N
|
|
WriteToSS(oblistN, $"N{CamRow}", spreadsheetId);
|
|
|
|
// Write TRUE to WIP checkbox in column S
|
|
List<object> oblistS = ["TRUE"];
|
|
WriteToSS(oblistS, $"S{CamRow}", spreadsheetId);
|
|
|
|
return "OK";
|
|
}
|
|
else
|
|
{
|
|
return "Serial number not found";
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
return $"ERROR: {ex.Message}";
|
|
}
|
|
}
|
|
|
|
// Update serial number register with relevant details about the camera that has passed
|
|
public static string UpdateSpreadSheetFinalTest(string spreadsheetId, Diags DiagsAPI, SSHData sshData, int RMANum)
|
|
{
|
|
try
|
|
{
|
|
int CamRow = CheckSerialNumRow(spreadsheetId, DiagsAPI.serialNumber);
|
|
|
|
IList<IList<object>> valuesRow = ReadSS(spreadsheetId, $"D{CamRow}");
|
|
string TestDate = Convert.ToString(valuesRow[0][0]) + Environment.NewLine + "Final Test: " + DateTime.Now.ToString("dd/MM/yyyy");
|
|
|
|
if (RMANum != 0)
|
|
TestDate = TestDate.Replace("Final", "RMA"); // So it will say RMA Test in the spreadsheet.
|
|
|
|
// Write column D
|
|
List<object> oblistD = [TestDate];
|
|
WriteToSS(oblistD, $"D{CamRow}", spreadsheetId);
|
|
|
|
List<object> oblistFG = // Write columns F-G
|
|
[
|
|
DiagsAPI.licenses.raptorKeyID,
|
|
sshData.packages
|
|
];
|
|
WriteToSS(oblistFG, $"F{CamRow}:G{CamRow}", spreadsheetId);
|
|
|
|
List<object> oblistNR = // Write columns N-S
|
|
[
|
|
$"GUI Version: {GUIUpdate.GUIVerShort}",
|
|
DiagsAPI.licenses.saf1,
|
|
DiagsAPI.licenses.audit,
|
|
DiagsAPI.licenses.stream,
|
|
sshData.tailscale,
|
|
"FALSE" // Write FALSE to WIP checkbox in column S
|
|
];
|
|
WriteToSS(oblistNR, $"N{CamRow}:S{CamRow}", spreadsheetId);
|
|
|
|
return string.Empty;
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
return "Failed to update spreadsheet data, please check manually" + ex.Message;
|
|
}
|
|
}
|
|
|
|
// Update Vaxtor spreadsheet
|
|
public static string UpdateSpreadSheetVaxtor(VaxtorLic VaxtorLicResp, string serial, string model)
|
|
{
|
|
try
|
|
{
|
|
string spreadsheetId = "1n5zhmI4Tz6JFr0stLNFOR6GsxGEKBEhrVKQ6yncM-LA";
|
|
int nextRow = CheckNextFree(spreadsheetId);
|
|
|
|
List<object> oblistCF = // Write columns C-F
|
|
[
|
|
model,
|
|
serial,
|
|
DateTime.Now.ToString("dd/MM/yyyy"),
|
|
VaxtorLicResp.protectionKeyId,
|
|
];
|
|
WriteToSS(oblistCF, $"C{nextRow}:F{nextRow}", spreadsheetId);
|
|
|
|
// Write PROD to column H
|
|
List<object> oblistH = ["PROD"];
|
|
WriteToSS(oblistH, $"H{nextRow}", spreadsheetId);
|
|
|
|
return string.Empty;
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
return "Failed to update spreadsheet data, please check manually" + ex.Message;
|
|
}
|
|
}
|
|
|
|
// Checks RMA control sheet for a model and serial that match current camera
|
|
public static int CheckRMANum(string serial, string model)
|
|
{
|
|
string spreadsheetId_RMAControl = "1tZhkYrqBQ3BcL7ZS4q3ghzCgHSJ8f5LVSj7nh6fIRC8";
|
|
try
|
|
{
|
|
// Get all info in H and I columns
|
|
IList<IList<object>> valuesRMA = service.Spreadsheets.Values.Get(spreadsheetId_RMAControl, "H2:I").Execute().Values;
|
|
|
|
for (int i = 0; i < valuesRMA.Count; i++)
|
|
{
|
|
try // In case line is blank
|
|
{
|
|
// Checks is serial and model num in RMA control spreadsheet match what is in the camera
|
|
if (valuesRMA[i][0].ToString().Contains(serial) && valuesRMA[i][1].ToString().Contains(model))
|
|
{
|
|
int OnRow = i + 2; // Offset for start of the sheet and starting at 1
|
|
valuesRMA = service.Spreadsheets.Values.Get(spreadsheetId_RMAControl, "A" + OnRow).Execute().Values;
|
|
return Convert.ToInt16(valuesRMA[0][0]); // Once it has found the serial it gusses at the RMA number
|
|
}
|
|
}
|
|
catch { }
|
|
}
|
|
}
|
|
catch { }
|
|
return 0; // If it can't be found
|
|
}
|
|
|
|
// Checks RMA control sheet for a model and serial that match current camera
|
|
public static int CheckSerialNumRow(string spreadsheetId, string serial)
|
|
{
|
|
// Get all info in B column
|
|
IList<IList<object>> valuesRMA = service.Spreadsheets.Values.Get(spreadsheetId, "B:B").Execute().Values;
|
|
|
|
for (int i = 0; i < valuesRMA.Count; i++)
|
|
{
|
|
try // In case line is blank
|
|
{
|
|
// Checks is serial and model num in RMA control spreadsheet match what is in the camera
|
|
if (valuesRMA[i][0].ToString().Contains(serial))
|
|
{
|
|
return i + 1; // Offset for sheet starting at 1
|
|
}
|
|
}
|
|
catch { }
|
|
}
|
|
return 0; // If it can't be found
|
|
}
|
|
|
|
// Checks Vaxtor sheet for next free row
|
|
public static int CheckNextFree(string spreadsheetId)
|
|
{
|
|
IList<IList<object>> valuesRMA = service.Spreadsheets.Values.Get(spreadsheetId, "C2:C").Execute().Values; // Get how many C cows
|
|
return valuesRMA.Count + 2; // Gets the amount of rows, offsets for start from 1 error and adds one to be next row
|
|
}
|
|
|
|
public static void EmailApproval(string ApprovalRow, string User)
|
|
{
|
|
FileStream GmailStream = new($"{DrivePath}R50IQ\\creds.json", FileMode.Open, FileAccess.Read);
|
|
string[] ScopesGmail = [GmailService.Scope.GmailSend];
|
|
|
|
using (GmailStream)
|
|
{
|
|
string credPathGmail = Path.Combine(credPath, ".credentials/gmail-dotnet-quickstart.json");
|
|
credential = GoogleWebAuthorizationBroker.AuthorizeAsync(GoogleClientSecrets.FromStream(GmailStream).Secrets, ScopesGmail, "user", CancellationToken.None, new FileDataStore(credPathGmail, true)).Result;
|
|
GmailStream.Close();
|
|
}
|
|
|
|
// Build the MIME message with attachment
|
|
using MailMessage mail = new MailMessage();
|
|
mail.From = new MailAddress("me");
|
|
mail.To.Add("richard.porter@mav-systems.com");
|
|
mail.To.Add("bradley.relyea@mav-systems.com");
|
|
mail.To.Add("bradley.born@mav-systems.com");
|
|
mail.Subject = "Approval required";
|
|
mail.Body = $"Dear Rich,<br><br>Camera needs approval<br>" +
|
|
$"https://docs.google.com/spreadsheets/d/1bCcCr4OYqfjmydt6UqtmN4FQETezXmZRSStJdCCcqZM/edit#gid=1931079354&range=A{ApprovalRow}" +
|
|
$"<br><br><br>Thanks,<br><br>{User}";
|
|
mail.IsBodyHtml = true;
|
|
|
|
// Attach the log file if it exists
|
|
string logFilePath = LDS.MAVPath + Logging.LogFileName;
|
|
if (File.Exists(logFilePath))
|
|
{
|
|
Attachment logAttachment = new(logFilePath, MediaTypeNames.Text.Plain);
|
|
logAttachment.Name = Logging.LogFileName;
|
|
mail.Attachments.Add(logAttachment);
|
|
}
|
|
|
|
// Save the MIME message to a stream
|
|
using MemoryStream ms = new();
|
|
SmtpClient smtpClient = new(); // Only used to access the internal Write method
|
|
Type mailWriterType = typeof(SmtpClient).Assembly.GetType("System.Net.Mail.MailWriter");
|
|
object? mailWriter = Activator.CreateInstance(
|
|
mailWriterType,
|
|
BindingFlags.Instance | BindingFlags.NonPublic,
|
|
null,
|
|
[ms, true],
|
|
null);
|
|
|
|
typeof(MailMessage).InvokeMember(
|
|
"Send",
|
|
BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.InvokeMethod,
|
|
null,
|
|
mail,
|
|
[mailWriter, true, true]);
|
|
|
|
ms.Position = 0;
|
|
byte[] rawBytes = ms.ToArray();
|
|
|
|
GmailService service = new(new BaseClientService.Initializer()
|
|
{
|
|
HttpClientInitializer = credential,
|
|
ApplicationName = ApplicationName,
|
|
});
|
|
|
|
Google.Apis.Gmail.v1.Data.Message newMsg = new()
|
|
{
|
|
Raw = Convert.ToBase64String(rawBytes)
|
|
.Replace("+", "-")
|
|
.Replace("/", "_")
|
|
.Replace("=", "")
|
|
};
|
|
|
|
service.Users.Messages.Send(newMsg, "me").Execute();
|
|
}
|
|
}
|
|
}
|