diff --git a/csharp/App/Backend/Controller.cs b/csharp/App/Backend/Controller.cs index d78e83773..2dac5f879 100644 --- a/csharp/App/Backend/Controller.cs +++ b/csharp/App/Backend/Controller.cs @@ -281,11 +281,24 @@ public class Controller : ControllerBase return Unauthorized(); return user - .AccessibleInstallations() + .AccessibleInstallations(product:0) .Select(i => i.FillOrderNumbers().HideParentIfUserHasNoAccessToParent(user).HideWriteKeyIfUserIsNotAdmin(user.UserType)) .ToList(); } + [HttpGet(nameof(GetAllSalidomoInstallations))] + public ActionResult> GetAllSalidomoInstallations(Token authToken) + { + var user = Db.GetSession(authToken)?.User; + + if (user is null) + return Unauthorized(); + + return user + .AccessibleInstallations(product:1) + .ToList(); + } + [HttpGet(nameof(GetAllFolders))] @@ -309,7 +322,7 @@ public class Controller : ControllerBase return Unauthorized(); var foldersAndInstallations = user - .AccessibleFoldersAndInstallations() + .AccessibleFoldersAndInstallations(product:0) .Do(o => o.FillOrderNumbers()) .Select(o => o.HideParentIfUserHasNoAccessToParent(user)) .OfType(); // Important! JSON serializer must see Objects otherwise @@ -342,6 +355,7 @@ public class Controller : ControllerBase [HttpPost(nameof(CreateInstallation))] public async Task> CreateInstallation([FromBody] Installation installation, Token authToken) { + var session = Db.GetSession(authToken); if (! await session.Create(installation)) @@ -452,8 +466,13 @@ public class Controller : ControllerBase if (!session.Update(installation)) return Unauthorized(); + + if (installation.Product == 0) + { + return installation.FillOrderNumbers().HideParentIfUserHasNoAccessToParent(session!.User).HideWriteKeyIfUserIsNotAdmin(session.User.UserType); + } - return installation.FillOrderNumbers().HideParentIfUserHasNoAccessToParent(session!.User).HideWriteKeyIfUserIsNotAdmin(session.User.UserType); + return installation.HideParentIfUserHasNoAccessToParent(session!.User); } [HttpPost(nameof(AcknowledgeError))] diff --git a/csharp/App/Backend/DataTypes/Installation.cs b/csharp/App/Backend/DataTypes/Installation.cs index ada9c68dd..3975ea939 100644 --- a/csharp/App/Backend/DataTypes/Installation.cs +++ b/csharp/App/Backend/DataTypes/Installation.cs @@ -7,15 +7,7 @@ public class Installation : TreeNode public String Location { get; set; } = ""; public String Region { get; set; } = ""; public String Country { get; set; } = ""; - public String InstallationName { get; set; } = ""; public String VpnIp { get; set; } = ""; - - // TODO: make relation - //public IReadOnlyList OrderNumbers { get; set; } = Array.Empty(); - // public String? OrderNumbers { get; set; } = ""; - - public Double Lat { get; set; } - public Double Long { get; set; } public String S3Region { get; set; } = "sos-ch-dk-2"; public String S3Provider { get; set; } = "exo.io"; @@ -25,10 +17,11 @@ public class Installation : TreeNode public String S3Secret { get; set; } = ""; public String ReadRoleId { get; set; } = ""; public String WriteRoleId { get; set; } = ""; - - + + public int Product { get; set; } = 0; [Ignore] public String OrderNumbers { get; set; } - + public String VrmLink { get; set; } = ""; + } \ No newline at end of file diff --git a/csharp/App/Backend/DataTypes/Methods/ExoCmd.cs b/csharp/App/Backend/DataTypes/Methods/ExoCmd.cs index 8f9d62667..25513343a 100644 --- a/csharp/App/Backend/DataTypes/Methods/ExoCmd.cs +++ b/csharp/App/Backend/DataTypes/Methods/ExoCmd.cs @@ -80,6 +80,7 @@ public static class ExoCmd public static async Task<(String,String)> CreateReadKey(this Installation installation) { var readRoleId = installation.ReadRoleId; + if (String.IsNullOrEmpty(readRoleId) ||! await CheckRoleExists(readRoleId)) @@ -113,9 +114,8 @@ public static class ExoCmd { var url = "https://api-ch-dk-2.exoscale.com/v2/api-key"; var method = "api-key"; - var contentString = $$"""{"role-id": "{{roleName}}", "name":"{{installation.BucketName()}}"}"""; + var contentString = $$"""{"role-id": "{{roleName}}", "name":"{{ installation.BucketName()}}"}"""; var unixtime = DateTimeOffset.UtcNow.ToUnixTimeSeconds() + 60; - var authheader = "credential=" + S3Credentials.Key + ",expires=" + unixtime + ",signature=" + @@ -165,7 +165,6 @@ public static class ExoCmd """; var unixtime = DateTimeOffset.UtcNow.ToUnixTimeSeconds()+60; - var authheader = "credential="+S3Credentials.Key+",signed-query-args="+",expires="+unixtime+",signature="+BuildSignature("POST", method, contentString, unixtime); var client = new HttpClient(); @@ -294,6 +293,7 @@ public static class ExoCmd return await s3Region.PutBucket(installation.BucketName()) != null; } + public static async Task SendConfig(this Installation installation, Configuration config) { @@ -316,7 +316,7 @@ public static class ExoCmd // return result.ExitCode == 200; - var maxRetransmissions = 2; + var maxRetransmissions = 4; UdpClient udpClient = new UdpClient(); udpClient.Client.ReceiveTimeout = 2000; int port = 9000; diff --git a/csharp/App/Backend/DataTypes/Methods/Folder.cs b/csharp/App/Backend/DataTypes/Methods/Folder.cs index b6f8afd78..778bbab89 100644 --- a/csharp/App/Backend/DataTypes/Methods/Folder.cs +++ b/csharp/App/Backend/DataTypes/Methods/Folder.cs @@ -53,6 +53,7 @@ public static class FolderMethods .Where(f => f.ParentId == parent.Id); } + public static IEnumerable DescendantFolders(this Folder parent) { return parent diff --git a/csharp/App/Backend/DataTypes/Methods/Installation.cs b/csharp/App/Backend/DataTypes/Methods/Installation.cs index f2f9a8bab..253eaa438 100644 --- a/csharp/App/Backend/DataTypes/Methods/Installation.cs +++ b/csharp/App/Backend/DataTypes/Methods/Installation.cs @@ -1,9 +1,5 @@ -using System.Net; -using System.Text.Json.Nodes; -using CliWrap; using InnovEnergy.App.Backend.Database; using InnovEnergy.App.Backend.Relations; -using InnovEnergy.Lib.S3Utils; using InnovEnergy.Lib.Utils; namespace InnovEnergy.App.Backend.DataTypes.Methods; @@ -12,20 +8,29 @@ namespace InnovEnergy.App.Backend.DataTypes.Methods; public static class InstallationMethods { private static readonly String BucketNameSalt = - Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT") == "" - ? "stage" - :"3e5b3069-214a-43ee-8d85-57d72000c19d"; + // Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT") == "" + // ? "stage" :"3e5b3069-214a-43ee-8d85-57d72000c19d"; + "3e5b3069-214a-43ee-8d85-57d72000c19d"; + + private static readonly String SalidomoBucketNameSalt = "c0436b6a-d276-4cd8-9c44-1eae86cf5d0e"; public static String BucketName(this Installation installation) { - return $"{installation.Id}-{BucketNameSalt}"; - } + if (installation.Product == 0) + { + return $"{installation.Id}-{BucketNameSalt}"; + } + return $"{installation.Id}-{SalidomoBucketNameSalt}"; + + } + public static async Task RenewS3Credentials(this Installation installation) { if(!installation.S3Key.IsNullOrEmpty()) await installation.RevokeReadKey(); + var (key,secret) = await installation.CreateReadKey(); installation.S3Key = key; @@ -40,7 +45,7 @@ public static class InstallationMethods return Db.Update(installation); } - + public static async Task DeleteBucket(this Installation installation) { diff --git a/csharp/App/Backend/DataTypes/Methods/Session.cs b/csharp/App/Backend/DataTypes/Methods/Session.cs index a202abbd1..93ffa1ef7 100644 --- a/csharp/App/Backend/DataTypes/Methods/Session.cs +++ b/csharp/App/Backend/DataTypes/Methods/Session.cs @@ -117,48 +117,81 @@ public static class SessionMethods public static async Task Create(this Session? session, Installation? installation) { var user = session?.User; - - return user is not null - && installation is not null - && user.UserType !=0 - && user.HasAccessToParentOf(installation) - && Db.Create(installation) // TODO: these two in a transaction - && installation.SetOrderNumbers() - && Db.Create(new InstallationAccess { UserId = user.Id, InstallationId = installation.Id }) - && await installation.CreateBucket() - && await installation.RenewS3Credentials(); // generation of access _after_ generation of - // bucket to prevent "zombie" access-rights. - // This might ** us over if the creation of access rights fails, - // as bucket-names are unique and bound to the installation id... -K + + //Salimax installation + if (installation.Product==0) + { + return user is not null + && user.UserType != 0 + && user.HasAccessToParentOf(installation) + && Db.Create(installation) // TODO: these two in a transaction + && installation.SetOrderNumbers() + && Db.Create(new InstallationAccess { UserId = user.Id, InstallationId = installation.Id }) + && await installation.CreateBucket() + && await installation.RenewS3Credentials(); + + } + + if (installation.Product==1) + { + return user is not null + && user.UserType != 0 + && user.HasAccessToParentOf(installation) + && Db.Create(installation) + && await installation.CreateBucket() + && await installation.RenewS3Credentials(); + } + return false; } + public static Boolean Update(this Session? session, Installation? installation) { var user = session?.User; var original = Db.GetInstallationById(installation?.Id); + //Salimax installation + if (installation.Product==0) + { - return user is not null - && installation is not null - && original is not null - && user.UserType !=0 - && user.HasAccessTo(installation) - && installation.SetOrderNumbers() - && installation - .WithParentOf(original) // prevent moving - .Apply(Db.Update); + return user is not null + && installation is not null + && original is not null + && user.UserType !=0 + && user.HasAccessTo(installation) + && installation.SetOrderNumbers() + && installation + .WithParentOf(original) // prevent moving + .Apply(Db.Update); + } + + if (installation.Product==1) + { + return user is not null + && installation is not null + && original is not null + && user.UserType !=0 + && user.HasAccessToParentOf(installation) + && installation + .Apply(Db.Update); + } + + return false; } public static async Task Delete(this Session? session, Installation? installation) { var user = session?.User; - return user is not null - && installation is not null - && user.UserType !=0 - && user.HasAccessTo(installation) - && Db.Delete(installation) - && await installation.DeleteBucket(); + + return user is not null + && installation is not null + && user.UserType != 0 + && user.HasAccessTo(installation) + && Db.Delete(installation) + && await installation.DeleteBucket(); + + } public static Boolean Create(this Session? session, User newUser) diff --git a/csharp/App/Backend/DataTypes/Methods/User.cs b/csharp/App/Backend/DataTypes/Methods/User.cs index ecd698385..38a2b4eba 100644 --- a/csharp/App/Backend/DataTypes/Methods/User.cs +++ b/csharp/App/Backend/DataTypes/Methods/User.cs @@ -12,17 +12,18 @@ namespace InnovEnergy.App.Backend.DataTypes.Methods; public static class UserMethods { - public static IEnumerable AccessibleInstallations(this User user) + public static IEnumerable AccessibleInstallations(this User user,int product) { - var direct = user.DirectlyAccessibleInstallations().ToList(); + var direct = user.DirectlyAccessibleInstallations().ToList().Where(f=>f.Product==product); var fromFolders = user .AccessibleFolders() - .SelectMany(u => u.ChildInstallations()).ToList(); + .SelectMany(u => u.ChildInstallations()).ToList().Where(f=>f.Product==product); return direct .Concat(fromFolders) .Distinct(); } + public static IEnumerable AccessibleFolders(this User user) { @@ -32,12 +33,12 @@ public static class UserMethods .Distinct(); } - public static IEnumerable AccessibleFoldersAndInstallations(this User user) + public static IEnumerable AccessibleFoldersAndInstallations(this User user,int product) { var folders = user.AccessibleFolders() as IEnumerable; - user.AccessibleInstallations().ForEach(i => i.FillOrderNumbers()); - var installations = user.AccessibleInstallations(); + user.AccessibleInstallations(product).ForEach(i => i.FillOrderNumbers()); + var installations = user.AccessibleInstallations(product); return folders.Concat(installations); } @@ -157,7 +158,8 @@ public static class UserMethods .Ancestors() .Any(user.HasDirectAccessTo); } - + + public static Boolean HasAccessTo(this User user, User? other) { if (other is null) @@ -168,20 +170,11 @@ public static class UserMethods .Ancestors() .Contains(user); } - - public static Boolean HasAccessTo(this User user, TreeNode? other) - { - return other?.Type switch - { - "installation" => user.HasAccessTo((Installation)other), - "user" => user.HasAccessTo((User)other), - "folder" => user.HasAccessTo((Folder)other), - _ => false - }; - } + public static Boolean HasAccessToParentOf(this User user, TreeNode? other) { + return other?.Type switch { "Installation" => user.HasAccessTo(Db.GetFolderById(other.ParentId)), diff --git a/csharp/App/Backend/Database/Db.cs b/csharp/App/Backend/Database/Db.cs index f4a879c7e..3253a08bb 100644 --- a/csharp/App/Backend/Database/Db.cs +++ b/csharp/App/Backend/Database/Db.cs @@ -1,5 +1,3 @@ -using System.Reactive.Concurrency; -using System.Reactive.Linq; using InnovEnergy.App.Backend.DataTypes; using InnovEnergy.App.Backend.DataTypes.Methods; using InnovEnergy.App.Backend.Relations; @@ -142,11 +140,15 @@ public static partial class Db .Select(i => i.S3Key) .Distinct() .ToList(); + + var validWriteKeys = Installations .Select(i => i.S3WriteKey) .Distinct() .ToList(); + + const String provider = "exo.io"; var S3keys = await ExoCmd.GetAccessKeys(); @@ -243,6 +245,7 @@ public static partial class Db { await installation.RenewS3Credentials(); } + } } diff --git a/csharp/App/Backend/Database/Delete.cs b/csharp/App/Backend/Database/Delete.cs index ca1da79de..f50fa3761 100644 --- a/csharp/App/Backend/Database/Delete.cs +++ b/csharp/App/Backend/Database/Delete.cs @@ -73,9 +73,15 @@ public static partial class Db Boolean DeleteInstallationAndItsDependencies() { - InstallationAccess.Delete(i => i.InstallationId == installation.Id); - OrderNumber2Installation.Delete(i => i.InstallationId == installation.Id); + if (installation.Product == 0) + { + InstallationAccess.Delete(i => i.InstallationId == installation.Id); + OrderNumber2Installation.Delete(i => i.InstallationId == installation.Id); + + } + return Installations.Delete(i => i.Id == installation.Id) > 0; + } } diff --git a/csharp/App/SaliMax/HostList.txt b/csharp/App/SaliMax/HostList.txt index 1e63aaa61..f4e744b20 100755 --- a/csharp/App/SaliMax/HostList.txt +++ b/csharp/App/SaliMax/HostList.txt @@ -9,4 +9,5 @@ Salimax0005 ie-entwicklung@10.2.4.36 Schreinerei Schönthal (Thu Salimax0006 ie-entwicklung@10.2.4.35 Steakhouse Mettmenstetten Salimax0007 ie-entwicklung@10.2.4.154 LerchenhofHerr Twannberg Salimax0008 ie-entwicklung@10.2.4.113 Wittmann Kottingbrunn +Salimax0010 ie-entwicklung@10.2.4.211 Mahotech 1 SalidomoServer ig@134.209.238.170 \ No newline at end of file diff --git a/typescript/frontend-marios2/src/App.tsx b/typescript/frontend-marios2/src/App.tsx index 77abadedb..9dda2d8b3 100644 --- a/typescript/frontend-marios2/src/App.tsx +++ b/typescript/frontend-marios2/src/App.tsx @@ -20,6 +20,7 @@ import { axiosConfigWithoutToken } from './Resources/axiosConfig'; import InstallationsContextProvider from './contexts/InstallationsContextProvider'; import AccessContextProvider from './contexts/AccessContextProvider'; import WebSocketContextProvider from './contexts/WebSocketContextProvider'; +import SalidomoInstallationTabs from './content/dashboards/SalidomoInstallations'; function App() { const context = useContext(UserContext); @@ -146,6 +147,18 @@ function App() { } /> + + + + + + + } + /> + } /> { + const { name, value } = e.target; + setFormValues({ + ...formValues, + [name]: value + }); + }; + const handleSubmit = () => { + setLoading(true); + setError(false); + updateInstallation(formValues, props.type); + }; + + const handleDelete = () => { + setLoading(true); + setError(false); + setOpenModalDeleteInstallation(true); + }; + + const deleteInstallationModalHandle = () => { + setOpenModalDeleteInstallation(false); + deleteInstallation(formValues, props.type); + setLoading(false); + + navigate(routes.salidomo_installations + routes.list, { + replace: true + }); + }; + + const deleteInstallationModalHandleCancel = () => { + setOpenModalDeleteInstallation(false); + setLoading(false); + }; + + const areRequiredFieldsFilled = () => { + for (const field of requiredFields) { + if (!formValues[field]) { + return false; + } + } + return true; + }; + + return ( + <> + {openModalDeleteInstallation && ( + + + + Do you want to delete this installation? + + +
+ + +
+
+
+ )} + + + + + + +
+ + } + name="installationName" + value={formValues.name} + onChange={handleChange} + variant="outlined" + fullWidth + /> +
+
+ + } + name="region" + value={formValues.region} + onChange={handleChange} + variant="outlined" + fullWidth + required + error={formValues.region === ''} + /> +
+
+ + } + name="location" + value={formValues.location} + onChange={handleChange} + variant="outlined" + fullWidth + required + error={formValues.location === ''} + /> +
+
+ + } + name="country" + value={formValues.country} + onChange={handleChange} + variant="outlined" + fullWidth + required + error={formValues.country === ''} + /> +
+ +
+ + } + name="vpnIp" + value={formValues.vpnIp} + onChange={handleChange} + variant="outlined" + fullWidth + /> +
+ +
+ + } + name="information" + value={formValues.information} + onChange={handleChange} + variant="outlined" + fullWidth + /> +
+ +
+ +
+ +
+ + + + + {loading && ( + + )} + {error && ( + + + setError(false)} + sx={{ marginLeft: '4px' }} + > + + + + )} + {updated && ( + + + + setUpdated(false)} // Set error state to false on click + sx={{ marginLeft: '4px' }} + > + + + + )} +
+
+
+
+
+
+ + ); +} + +export default InformationSalidomo; diff --git a/typescript/frontend-marios2/src/content/dashboards/Installations/Installation.tsx b/typescript/frontend-marios2/src/content/dashboards/Installations/Installation.tsx index c29619146..b66b309c7 100644 --- a/typescript/frontend-marios2/src/content/dashboards/Installations/Installation.tsx +++ b/typescript/frontend-marios2/src/content/dashboards/Installations/Installation.tsx @@ -52,8 +52,11 @@ function Installation(props: singleInstallationProps) { }; const s3Bucket = - props.current_installation.id.toString() + - '-3e5b3069-214a-43ee-8d85-57d72000c19d'; + props.current_installation.product === 0 + ? props.current_installation.id.toString() + + '-3e5b3069-214a-43ee-8d85-57d72000c19d' + : props.current_installation.id.toString() + + '-c0436b6a-d276-4cd8-9c44-1eae86cf5d0e'; const s3Credentials = { s3Bucket, ...S3data }; diff --git a/typescript/frontend-marios2/src/content/dashboards/Installations/index.tsx b/typescript/frontend-marios2/src/content/dashboards/Installations/index.tsx index 69e321315..197a141dc 100644 --- a/typescript/frontend-marios2/src/content/dashboards/Installations/index.tsx +++ b/typescript/frontend-marios2/src/content/dashboards/Installations/index.tsx @@ -30,7 +30,7 @@ function InstallationTabs() { ]; const [currentTab, setCurrentTab] = useState(undefined); - const { installations, fetchAllInstallations } = + const { salimaxInstallations, fetchAllInstallations } = useContext(InstallationsContext); const webSocketsContext = useContext(WebSocketContext); @@ -50,16 +50,16 @@ function InstallationTabs() { }, [location]); useEffect(() => { - if (!socket && installations.length > 0) { - openSocket(installations); + if (!socket && salimaxInstallations.length > 0) { + openSocket(salimaxInstallations); } - }, [installations]); + }, [salimaxInstallations]); useEffect(() => { - if (installations.length === 0) { + if (salimaxInstallations.length === 0) { fetchAllInstallations(); } - }, [installations]); + }, [salimaxInstallations]); const handleTabsChange = (_event: ChangeEvent<{}>, value: string): void => { setCurrentTab(value); @@ -270,7 +270,7 @@ function InstallationTabs() { } ]; - return installations.length > 1 ? ( + return salimaxInstallations.length > 1 ? ( <> @@ -312,7 +312,9 @@ function InstallationTabs() { element={ - + } @@ -330,7 +332,7 @@ function InstallationTabs() {