public JObject getProductAvailability(JObject request)
        {
            //Get arguments
            request.TryGetValue("products", out JToken productValue);
            if (productValue == null || (productValue.Type != JTokenType.String && productValue.Type != JTokenType.Array))
            {
                return(Templates.MissingArguments("statType"));
            }

            //Parse arguments
            List <string> productIDs = new List <string>();

            if (productValue.Type == JTokenType.String)
            {
                //TODO Allow * to be used as value, selecting all products
                productIDs.Add(productValue.ToObject <string>());
            }
            else if (productValue.Type == JTokenType.Array)
            {
                productIDs = productValue.ToObject <List <string> >();
            }

            // Build condition that matches all relevant productItems and get said productItems
            // The lookup groups the productItems and loanItems to a single product id.
            var condition         = new MySqlConditionBuilder("product", MySqlDbType.String, productIDs.ToArray());
            var productItemsArray = Connection.Select <ProductItem>(condition).ToArray();
            var productItems      = productItemsArray.ToLookup(x => x.ProductId);

            // Build condition that matches all relevand loanItems and get said loanItems
            condition = new MySqlConditionBuilder("product_item", MySqlDbType.Int32, productItemsArray.Select(x => x.Id.Value).Cast <object>().ToArray());
            var loanItems = Connection.Select <LoanItem>(condition).ToLookup(x => productItemsArray.First(y => y.Id == x.ProductItem).ProductId);

            // DateTimeSpan representing now->midnight for filtering relevant loans
            DateTimeSpan today = new DateTimeSpan(DateTime.Now, DateTime.Now.Date.AddDays(1));

            // Build response data
            var responseData = new JObject();

            foreach (var productID in productIDs)
            {
                var items         = productItems[productID];
                var loans         = loanItems[productID];
                var relevantLoans = loans.Where(x => today.Overlaps(x.Start, x.End)).ToArray();

                var entry = new JObject()
                {
                    { "total", items.Count() },
                    { "totalReservations", loans.Count() },
                    { "reservations", relevantLoans.Length },
                    { "loanedOut", relevantLoans.Count(x => x.IsAcquired) },
                    { "inStock", items.Count() - relevantLoans.Count(x => x.IsAcquired) },
                    { "available", items.Count() - relevantLoans.Length }
                };

                responseData.Add(productID, entry);
            }

            //Return response
            return(new JObject()
            {
                { "reason", null },
                { "responseData", responseData }
            });
        }
Esempio n. 2
0
        public JObject addProduct(JObject request)
        {
            //Get arguments
            string productID;
            string manufacturer;
            string categoryID;

            request.TryGetValue("productID", out JToken productIDValue);
            request.TryGetValue("categoryID", out JToken categoryIDValue);
            request.TryGetValue("manufacturer", out JToken manufacturerValue);
            request.TryGetValue("description", out JToken descriptionValue);
            request.TryGetValue("name", out JToken nameValue);

            // Verify presence of arguments
            List <string> failedVerifications = new List <string>();

            if (productIDValue == null)
            {
                failedVerifications.Add("productID");
            }
            if (categoryIDValue == null)
            {
                failedVerifications.Add("categoryID");
            }
            if (manufacturerValue == null)
            {
                failedVerifications.Add("manufacturer");
            }
            if (nameValue == null)
            {
                failedVerifications.Add("name");
            }

            if (failedVerifications.Any())
            {
                return(Templates.MissingArguments(failedVerifications.ToArray()));
            }

            // Verify arguments
            if (productIDValue.Type != JTokenType.String)
            {
                failedVerifications.Add("productID");
            }
            if (categoryIDValue.Type != JTokenType.String)
            {
                failedVerifications.Add("categoryID");
            }
            if (manufacturerValue.Type != JTokenType.String)
            {
                failedVerifications.Add("manufacturer");
            }
            if (nameValue.Type != JTokenType.Object)
            {
                failedVerifications.Add("name");
            }

            if (failedVerifications.Any())
            {
                return(Templates.InvalidArguments(failedVerifications.ToArray()));
            }

            // Prepare values
            productID    = productIDValue.ToObject <string>();
            manufacturer = manufacturerValue.ToObject <string>();
            categoryID   = categoryIDValue.ToObject <string>();

            // Get image
            request.TryGetValue("image", out JToken imageValue);
            string extension = null;

            byte[] imageData = null;
            if (imageValue != null && imageValue.Type == JTokenType.Object)
            {
                JObject image = imageValue.ToObject <JObject>();
                image.TryGetValue("data", out JToken dataValue);
                image.TryGetValue("extension", out JToken extensionValue);
                if (extensionValue != null && extensionValue.Type == JTokenType.String &&
                    dataValue != null && dataValue.Type == JTokenType.String)
                {
                    extension = extensionValue.ToObject <string>();
                    imageData = (byte[])dataValue;
                    if (!Image.ImageFormats.Contains(extension))
                    {
                        return(Templates.InvalidArgument("extension"));
                    }
                }
                else
                {
                    return(Templates.MissingArguments("data, extension"));
                }
            }

            // Get languages
            string  en;
            string  nl    = null;
            string  ar    = null;
            JObject names = nameValue.ToObject <JObject>();

            names.TryGetValue("en", out JToken nameEnValue);
            names.TryGetValue("nl", out JToken nameNlValue);
            names.TryGetValue("ar", out JToken nameArValue);
            if (nameEnValue != null && nameEnValue.Type == JTokenType.String)
            {
                en = names["en"].ToObject <string>();
            }
            else
            {
                return(Templates.MissingArguments("name: en"));
            }
            if (nameNlValue != null && nameNlValue.Type == JTokenType.String)
            {
                nl = names["nl"].ToObject <string>();
            }
            if (nameArValue != null && nameArValue.Type == JTokenType.String)
            {
                ar = names["ar"].ToObject <string>();
            }
            LanguageItem name = new LanguageItem(productID + "_name", en, nl, ar);

            LanguageItem description;

            if (descriptionValue != null && descriptionValue.Type == JTokenType.Object)
            {
                //Get description
                JObject desc = descriptionValue.ToObject <JObject>();
                desc.TryGetValue("en", out JToken descEnValue);
                desc.TryGetValue("nl", out JToken descNlValue);
                desc.TryGetValue("ar", out JToken descArValue);
                if (descEnValue != null && descEnValue.Type == JTokenType.String)
                {
                    en = desc["en"].ToObject <string>();
                }
                else
                {
                    return(Templates.MissingArguments("description: en"));
                }
                if (descNlValue != null && descNlValue.Type == JTokenType.String)
                {
                    nl = desc["nl"].ToObject <string>();
                }
                if (descArValue != null && descArValue.Type == JTokenType.String)
                {
                    ar = desc["ar"].ToObject <string>();
                }
                description = new LanguageItem(productID + "_description", en, nl, ar);
            }
            else
            {
                description = new LanguageItem(productID + "_description", null);
            }

            //Check if product already exists
            Product product = GetObject <Product>(productID);

            if (product != null)
            {
                return(Templates.AlreadyExists(productID));
            }

            //Check if category exists
            ProductCategory category = GetObject <ProductCategory>(categoryID);

            if (category == null)
            {
                return(Templates.NoSuchProductCategory(categoryID));
            }

            //Create product, languageItem, image
            name.Upload(Connection);
            description.Upload(Connection);
            if (imageData != null)
            {
                Image image = new Image(productID + "_image", imageData, extension);
                image.Upload(Connection);
                product = new Product(productID, manufacturer, categoryID, productID + "_name", productID + "_description", image.Id);
            }
            else
            {
                product = new Product(productID, manufacturer, categoryID, productID + "_name", productID + "_description");
            }
            product.Upload(Connection);

            //Create response
            return(new JObject()
            {
                { "reason", null },
            });
        }
        public JObject getProductCategories(JObject request)
        {
            // Get request arguments
            request.TryGetValue("columns", out JToken requestColumns);
            request.TryGetValue("criteria", out JToken requestCriteria);
            request.TryGetValue("language", out JToken requestLanguages);
            request.TryGetValue("start", out JToken requestRangeStart);
            request.TryGetValue("amount", out JToken requestRangeAmount);

            MySqlConditionBuilder condition = null;

            // Verify the types of the arguments
            List <string> failedVerifications = new List <string>();

            if (requestColumns != null && (requestColumns.Type != JTokenType.Array || requestColumns.Any(x => x.Type != JTokenType.String)))
            {
                failedVerifications.Add("colums");
            }

            if (requestCriteria != null)
            {
                try { Misc.CreateCondition((JObject)requestCriteria, condition); } catch (Exception) { failedVerifications.Add("criteria"); }
            }

            if (requestLanguages != null && (requestLanguages.Type != JTokenType.Array || requestLanguages.Any(x => x.Type != JTokenType.String)))
            {
                failedVerifications.Add("language");
            }

            if (requestRangeStart != null && (requestRangeStart.Type != JTokenType.Integer))
            {
                failedVerifications.Add("start");
            }

            if (requestRangeAmount != null && (requestRangeAmount.Type != JTokenType.Integer))
            {
                failedVerifications.Add("amount");
            }

            if (failedVerifications.Any())
            {
                return(Templates.InvalidArguments(failedVerifications.ToArray()));
            }

            //Create base response
            var     responseData = new JArray();
            JObject response     = new JObject()
            {
                { "reason", null },
                { "responseData", responseData }
            };

            // Prepare values for database call
            (ulong, ulong)range = (requestRangeStart?.ToObject <ulong>() ?? 0, requestRangeAmount?.ToObject <ulong>() ?? ulong.MaxValue);
            if (requestColumns == null || requestColumns.Count() == 0)
            {
                requestColumns = new JArray(ProductCategory.metadata.Select(x => x.Column));
            }
            else if (requestLanguages != null && !requestColumns.Contains("name"))
            {
                ((JArray)requestColumns).Add("name");
            }

            // Remove unknown language columns
            requestLanguages = new JArray(requestLanguages.Where(x => LanguageItem.metadata.Select(y => y.Column).Contains(x.ToString())));

            // Request category data from database
            List <object[]> categoryData = Connection.Select <ProductCategory>(requestColumns.ToObject <string[]>(), condition, range).ToList();

            // Add all categories as dictionaries to responseData
            foreach (var data in categoryData)
            {
                var item = new JObject();
                for (int i = 0; i < requestColumns.Count(); i++)
                {
                    item[(string)requestColumns[i]] = new JValue(data[i]);
                }

                responseData.Add(item);
            }

            // Add translations if specified in the arguments
            if (requestLanguages != null)
            {
                List <string> nameIds = responseData.Select(x => x["name"].ToString()).ToList();

                // Build a condition to get all language items in one query
                bool first         = true;
                var  nameCondition = new MySqlConditionBuilder();
                foreach (var name in nameIds)
                {
                    if (!first)
                    {
                        nameCondition.Or();
                    }

                    nameCondition.Column("id");
                    nameCondition.Equals(name, MySql.Data.MySqlClient.MySqlDbType.String);
                    first = false;
                }

                // Get the specified translations
                var languageColumns = requestLanguages.ToObject <List <string> >();
                if (languageColumns.Count == 0)
                {
                    languageColumns.Add("*");
                }
                else
                {
                    languageColumns.Insert(0, "id");
                }

                List <object[]> names = Connection.Select <LanguageItem>(languageColumns.ToArray(), nameCondition).ToList();
                for (int i = 0; i < responseData.Count; i++)
                {
                    var nameData     = names.First(x => x[0].Equals(nameIds[i]));
                    var translations = new JObject();
                    for (int j = 1; j < languageColumns.Count; j++)
                    {
                        if (nameData[j] != null)
                        {
                            translations[languageColumns[j]] = new JValue(nameData[j]);
                        }
                    }
                    responseData[i]["name"] = translations;
                }
            }

            return(response);
        }
Esempio n. 4
0
        public JObject updateUser(JObject request)
        {
            //Get arguments
            string username;
            string password;
            int    permission = -2;

            request.TryGetValue("username", out JToken usernameValue);
            request.TryGetValue("password", out JToken passwordValue);
            request.TryGetValue("permission", out JToken permissionValue);
            if (usernameValue == null || usernameValue.Type != JTokenType.String)
            {
                return(Templates.MissingArguments("username"));
            }
            else
            {
                username = usernameValue.ToObject <string>();
            }
            if (passwordValue == null || passwordValue.Type != JTokenType.String)
            {
                password = null;
            }
            else
            {
                password = passwordValue.ToObject <string>();
                if (password.Length != 128 && !System.Text.RegularExpressions.Regex.IsMatch(password, @"\A\b[0-9a-fA-F]+\b\Z"))
                {
                    return(Templates.InvalidPassword);
                }
            }
            if (permissionValue != null && permissionValue.Type == JTokenType.Integer)
            {
                permission = permissionValue.ToObject <int>();
            }

            //Check permission
            User currentUser = GetObject <User>(request["username"].ToObject <string>(), "Username");

            if (currentUser.Username != username)
            {
                if (currentUser.Permission != UserPermission.Admin)
                {
                    return(Templates.AccessDenied);
                }
            }
            else if (permission != -2)
            {
                return(Templates.AccessDenied);
            }

            //Get user
            User user = GetObject <User>(username, "Username");

            if (user == null)
            {
                return(Templates.NoSuchUser(username));
            }

            //Edit user
            if (password != null)
            {
                user.Password = password;
            }
            if (permission != -2)
            {
                user.Permission = (UserPermission)permission;
            }
            user.Update(Connection);

            //Create response
            return(new JObject()
            {
                { "reason", null },
            });
        }
        public JObject getUnavailableDates(JObject request)
        {
            // Get arguments
            request.TryGetValue("productId", out JToken requestProductId);
            request.TryGetValue("start", out JToken requestStart);
            request.TryGetValue("end", out JToken requestEnd);

            // Verify arguments
            List <string> failedVerifications = new List <string>();

            if (requestProductId == null || requestProductId.Type != JTokenType.String)
            {
                return(Templates.InvalidArgument("productId"));
            }
            if (requestStart == null)
            {
                return(Templates.InvalidArgument("start"));
            }
            if (requestEnd == null)
            {
                return(Templates.InvalidArgument("end"));
            }

            if (failedVerifications.Any())
            {
                return(Templates.InvalidArguments(failedVerifications.ToArray()));
            }

            // Parse arguments
            DateTime start;
            DateTime end;

            try { start = requestStart == null ? new DateTime() : DateTime.Parse(requestStart.ToString()); }
            catch (Exception) { return(Templates.InvalidArgument("Unable to parse 'start'")); }
            try { end = requestEnd == null ? new DateTime() : DateTime.Parse(requestEnd.ToString()); }
            catch (Exception) { return(Templates.InvalidArgument("Unable to parse 'end'")); }
            var range = new DateTimeSpan(start, end);

            if (range.Duration.Days > 122)
            {
                return(Templates.InvalidArgument("start and end may not be more than 122 days apart."));
            }

            // Get all items
            var condition    = new MySqlConditionBuilder("product", MySqlDbType.String, requestProductId.ToString());
            var productItems = Connection.Select <ProductItem>(condition).ToArray();

            // Return empty response if no items were found
            if (!productItems.Any())
            {
                return new JObject()
                       {
                           { "reason", null },
                           { "responseData", new JArray() }
                       }
            }
            ;

            // Get all loans within the specified range
            condition = new MySqlConditionBuilder("product_item", MySqlDbType.Int32, productItems.Select(x => x.Id).Cast <object>().ToArray());
            condition.And()
            .Column("end")
            .GreaterThanOrEqual()
            .Operand(range.Start, MySqlDbType.DateTime);
            condition.And()
            .Column("start")
            .LessThanOrEqual()
            .Operand(range.End, MySqlDbType.DateTime);
            var loanItems = Connection.Select <LoanItem>(condition).ToArray();

            // No idea if this is the most efficient way, but it basically iterates
            // through all dates of a loan and slaps them in a cache. If the cache
            // already contains the date, it increases the counter.
            // If the counter is larger or equal to the total amount of items, we
            // consider that date unavailable.
            var dateCache = new Dictionary <DateTime, int>();

            foreach (var loan in loanItems)
            {
                while (loan.Start < loan.End)
                {
                    if (loan.Start < range.Start)
                    {
                        loan.Start = loan.Start.AddDays(1);
                        continue;
                    }
                    if (loan.End > range.End)
                    {
                        break;
                    }
                    if (dateCache.ContainsKey(loan.Start))
                    {
                        dateCache[loan.Start]++;
                    }
                    else
                    {
                        dateCache[loan.Start] = 1;
                    }
                    loan.Start = loan.Start.AddDays(1);
                }
            }

            // Build base response
            var     responseData = new JArray();
            JObject response     = new JObject()
            {
                { "reason", null },
                { "responseData", responseData }
            };

            // Add all dates with an amount of loans greater or equal to the max available items
            foreach ((DateTime date, int count) in dateCache)
            {
                if (count >= productItems.Length)
                {
                    responseData.Add((long)(date.ToUniversalTime() - Epoch).TotalMilliseconds);
                }
            }

            return(response);
        }
    }
        public JObject deleteProductItems(JObject request)
        {
            //Get arguments
            request.TryGetValue("productID", out JToken requestProductId);
            request.TryGetValue("count", out JToken requestCount);

            // Verify presence of arguments
            var failedVerifications = new List <string>();

            if (requestProductId == null)
            {
                failedVerifications.Add("productID");
            }
            if (requestCount == null)
            {
                failedVerifications.Add("count");
            }

            if (failedVerifications.Any())
            {
                return(Templates.MissingArguments(failedVerifications.ToArray()));
            }

            // Verify arguments
            if (requestProductId.Type != JTokenType.String)
            {
                failedVerifications.Add("productId");
            }
            if (requestCount.Type != JTokenType.Integer || ((int)requestCount) < 0)
            {
                failedVerifications.Add("count");
            }

            if (failedVerifications.Any())
            {
                return(Templates.InvalidArguments(failedVerifications.ToArray()));
            }

            // Get all productItems
            var condition    = new MySqlConditionBuilder("product", MySqlDbType.String, requestProductId.ToString());
            var productItems = Connection.Select <ProductItem>(condition).ToArray();

            // Return bare response if no items exist
            if (!productItems.Any())
            {
                return(new JObject()
                {
                    { "reason", null },
                    { "responseData", new JObject()
                      {
                          { "deleted", 0 },
                          { "ignored", 0 }
                      } }
                });
            }

            // Get all aquired loans that have yet to end
            condition = new MySqlConditionBuilder("product_item", MySqlDbType.Int32, productItems.Select(x => x.Id).Cast <object>().ToArray());
            condition.And()
            .Column("end")
            .GreaterThanOrEqual()
            .Operand(DateTime.Now, MySqlDbType.DateTime);
            condition.And()
            .Column("is_item_acquired")
            .Equals().True();
            var loans = Connection.Select <LoanItem>(condition).ToArray();

            // Create function to track how many product items were ignored and how many weren't
            int ignored    = 0;
            int notIgnored = 0;

            bool shouldIgnoreLoanedItem(ProductItem item)
            {
                bool b = loans.FirstOrDefault(x => x.ProductItem == item.Id) != null;

                if (notIgnored != (int)requestCount)
                {
                    if (b)
                    {
                        ignored++;
                    }
                    else
                    {
                        notIgnored++;
                    }
                }
                return(b);
            }

            // Filter out items that are loaned out
            var deletableItems = productItems.Where(x => !shouldIgnoreLoanedItem(x)).Take((int)requestCount).ToArray();

            // Delete all items
            foreach (var item in deletableItems)
            {
                Connection.Delete(item);
            }

            //Create base response
            return(new JObject()
            {
                { "reason", null },
                { "responseData", new JObject()
                  {
                      { "deleted", notIgnored },
                      { "ignored", ignored }
                  } }
            });
        }
Esempio n. 7
0
        public JObject deleteProduct(JObject request)
        {
            //Get arguments
            request.TryGetValue("productID", out JToken idValue);
            if (idValue == null || idValue.Type != JTokenType.String)
            {
                return(Templates.MissingArguments("productID"));
            }

            // Prepare values
            string productID = idValue.ToString();


            //Check if product exists
            Product product = GetObject <Product>(productID);

            if (product == null)
            {
                return(Templates.NoSuchProduct(productID));
            }

            // Check if items or acquired loans exist
            var condition = new MySqlConditionBuilder("product", MySqlDbType.String, productID);
            var items     = Connection.Select <ProductItem>(condition).ToList();

            // Check for associated loans if any items exist
            if (items.Any())
            {
                // Get associated loans that are acquired and end after today
                condition = new MySqlConditionBuilder("product_item", MySqlDbType.Int32, items.Select(x => x.Id).Cast <object>().ToArray());
                condition.And()
                .Column("end")
                .GreaterThanOrEqual()
                .Operand(DateTime.Now, MySqlDbType.DateTime);
                condition.And()
                .Column("is_item_acquired")
                .Equals().True();
                List <bool> loans_isAcquired = Connection.Select <LoanItem>(new string[] { "is_item_acquired" }, condition).Select(x => (bool)x[0]).ToList();

                // If any active loans are aquired, respond with CannotDelete
                if (loans_isAcquired.Any())
                {
                    return(Templates.CannotDelete("This product still has active loans."));
                }
            }

            // Delete image if it isnt the default image
            product.Delete(Connection);
            if (product.Image != "default")
            {
                product.GetImage(Connection)?.Delete(Connection);
            }
            // Delete name languageItem if it isnt the default languageItem
            if (product.Name != "0")
            {
                product.GetName(Connection)?.Delete(Connection);
            }
            // Delete description languageItem if it isnt the default languageItem
            if (product.Description != "0")
            {
                product.GetDescription(Connection)?.Delete(Connection);
            }

            //Create base response
            return(new JObject()
            {
                { "reason", null },
            });
        }
        public JObject updateProductCategory(JObject request)
        {
            //Validate arguments
            string  categoryID;
            string  newCategoryID = null;
            JObject names         = null;

            request.TryGetValue("categoryID", out JToken categoryIDValue);
            request.TryGetValue("newCategoryID", out JToken newCategoryIDValue);
            request.TryGetValue("name", out JToken nameValue);
            if (categoryIDValue == null || categoryIDValue.Type != JTokenType.String)
            {
                return(Templates.MissingArguments("categoryID"));
            }
            else
            {
                categoryID = categoryIDValue.ToObject <string>();
                if (categoryID == "default" || categoryID == "uncategorized")
                {
                    return(Templates.InvalidArgument("categoryID"));
                }
            }
            if (newCategoryIDValue != null && newCategoryIDValue.Type == JTokenType.String)
            {
                newCategoryID = newCategoryIDValue.ToObject <string>();
            }
            if (nameValue != null && nameValue.Type == JTokenType.Object)
            {
                names = nameValue.ToObject <JObject>();
            }

            //Get product, if it exists
            ProductCategory category = GetObject <ProductCategory>(categoryID);

            if (category == null)
            {
                return(Templates.NoSuchProductCategory(categoryID));
            }

            ///////////////LanguageItem
            //Edit the LanguageItem if needed;
            LanguageItem item = category.GetName(Connection);

            if (names != null)
            {
                if (names.TryGetValue("en", out JToken enValue))
                {
                    if (enValue.Type == JTokenType.String)
                    {
                        item.en = enValue.ToObject <string>();
                    }
                }
                if (names.TryGetValue("nl", out JToken nlValue))
                {
                    if (nlValue.Type == JTokenType.String)
                    {
                        item.nl = nlValue.ToObject <string>();
                    }
                }
                if (names.TryGetValue("ar", out JToken arValue))
                {
                    if (arValue.Type == JTokenType.String)
                    {
                        item.ar = arValue.ToObject <string>();
                    }
                }
                item.Update(Connection);
            }

            //If a new product ID was specified, check if it already exists. If it doesn't, change the product ID.
            if (newCategoryID != null)
            {
                ProductCategory newProduct = GetObject <ProductCategory>(newCategoryID);
                if (newProduct != null)
                {
                    return(Templates.AlreadyExists(categoryID));
                }
                else
                {
                    item.Id = newCategoryID + "_name";
                    item.Update(Connection);
                    category.Name = item.Id;
                    category.UpdateTrace();
                    category.Id = newCategoryID;
                }
            }

            category.Update(Connection);

            //Create response
            return(new JObject()
            {
                { "reason", null },
                { "success", true }
            });
        }