From 8335556e5f34681232fc382e5926a5f690d80e90 Mon Sep 17 00:00:00 2001 From: John Cardinal Date: Tue, 7 Jan 2020 18:41:50 +0000 Subject: [PATCH] --- docs/8.0/ayanova/docs/api-console.md | 10 ++- docs/8.0/ayanova/docs/api-request-format.md | 14 +++- server/AyaNova/biz/FilterSpecialTokens.cs | 21 ++++- .../AyaNova/biz/FilterSqlCriteriaBuilder.cs | 84 ++++++++++++++++++- 4 files changed, 116 insertions(+), 13 deletions(-) diff --git a/docs/8.0/ayanova/docs/api-console.md b/docs/8.0/ayanova/docs/api-console.md index 009fefb4..0fec9f79 100644 --- a/docs/8.0/ayanova/docs/api-console.md +++ b/docs/8.0/ayanova/docs/api-console.md @@ -8,9 +8,11 @@ You can access the api explorer console by navigating with your browser to this For example if your AyaNova server were located on port 7575 of the local computer you would connect to it via this url: `http://localhost:7575/api-docs/` +Using this console you can see real working examples of exactly what is required for headers and body contents of requests and the responses returned to use with your own development environment. + ## Authentication -Most of the API endpoints in AyaNova require authentication to use them. The API console supports the ability to set a authorization token so you can fully test all routes. +Most of the API endpoints in AyaNova require a [JSON web token](https://jwt.io/introduction/) authentication to use them. The API console supports the ability to set a authorization token so you can fully test all routes. To obtain a token expand the "Auth" route in the main console and enter a value for login and password and click on the "Try it out" button to obtain an API token. @@ -21,16 +23,16 @@ The "response body" section will contain the return value, something similar to "ok": 1, "issued": 1518034370, "expires": 1520626370, - "token": "xyGhbGciOiJIUzI1NiIsInR4cCI6IkpXVCJ9.utJpYXQ4OiIxNqE4MDM0MzcfIiwiZXhwjjoiMTUyMDYyNjM8MCIsImlocyI0IkF53U5vdmEiLCJpZCI6IjEifQ.z7QaHKt2VbcysunIvsfa-51X7owB1EYcyhpkdkfaqzy", + "token": "xyGhbGciOiJIUzI1NiIsInR4cCI6IkpXVCJ9.utJpqE4MDM0............fQ.z7QaHKt2VbcysunIvsfa-51X7owB1EYcyhpkdkfaqzy", "id": 1 } ``` -The highlighted line above contains the token you require, copy the token value not including the quotation marks. This is your access token. +The highlighted line above contains the token (shortened for illustration) you require, copy the token *value* not including the quotation marks. This is your access token. Click on the "Authorize" button at the top of the API console and a popup dialog box will open. In the "Value" box the dialog enter your api token, for example using the above you would paste in: -`xyGhbGciOiJIUzI1NiIsInR4cCI6IkpXVCJ9.utJpYXQ4OiIxNqE4MDM0MzcfIiwiZXhwjjoiMTUyMDYyNjM8MCIsImlocyI0IkF53U5vdmEiLCJpZCI6IjEifQ.z7QaHKt2VbcysunIvsfa-51X7owB1EYcyhpkdkfaqzy` +`xyGhbGciOiJIUzI1NiIsInR4cCI6IkpXVCJ9.utJpqE4MDM0............fQ.z7QaHKt2VbcysunIvsfa-51X7owB1EYcyhpkdkfaqzy` then click on the "Authorize" button inside the popup dialog box. diff --git a/docs/8.0/ayanova/docs/api-request-format.md b/docs/8.0/ayanova/docs/api-request-format.md index 4f7ab550..35809fae 100644 --- a/docs/8.0/ayanova/docs/api-request-format.md +++ b/docs/8.0/ayanova/docs/api-request-format.md @@ -92,7 +92,7 @@ The `value` property is usually a direct comparison type value such as a date or In most cases tokens are for date ranges however there is one special token that applies to any data type `{[null]}`. When this token is specified as the `value` property value the list will be filtered by null (empty) values for all data types using the `op` comparison Equality operator `=` or in any other operator case it will be treated as if the operator was `!=` Not equal. -Tokens for date ranges generally provide a *relative* to the current moment (and time zone) pre-defined range of dates. This means the filter can be saved and re-used and the date range will always filter *relative* to the current date and time in the user's own time zone (as specified in their UserOptions object). So, for example, if two users are set to two different time zones they will get different results for some of these filters depending on whether that token is a relative one or absolute. +Tokens for date ranges generally provide a *relative* to the current moment (and time zone) pre-defined range of dates. This means the filter can be saved and re-used and the date range will always filter *relative* to the current date and time in the *user's own time zone* (as specified in their UserOptions object). So, for example, if two users are set to two different time zones they will get different results for some of these filters depending on whether that token is a relative one or absolute. For example the `{[past]}` token is relative to the current date and time but it is unaffected by any time zone considerations whereas the `{[yesterday]}` token takes into consideration the user's time zone when filtering. @@ -121,6 +121,18 @@ These are the available tokens for date filters: | {[past90days]} | Include records where `fld` contains a date and time from now minus 90 days to now | | {[past30days]} | Include records where `fld` contains a date and time from now minus 30 days to now | | {[past24hours]} | Include records where `fld` contains a date and time from now minus 24 hours to now | +| {[january]} | Include records where `fld` contains a date and time between 12:00 am January 1st this year and 12:00 am February 1st this year | +| {[february]} | Include records where `fld` contains a date and time between 12:00 am February 1st this year and 12:00 am March 1st this year | +| {[march]} | Include records where `fld` contains a date and time between 12:00 am March 1st this year and 12:00 am April 1st this year | +| {[april]} | Include records where `fld` contains a date and time between 12:00 am April 1st this year and 12:00 am May 1st this year | +| {[may]} | Include records where `fld` contains a date and time between 12:00 am May 1st this year and 12:00 am June 1st this year | +| {[june]} | Include records where `fld` contains a date and time between 12:00 am June 1st this year and 12:00 am July 1st this year | +| {[july]} | Include records where `fld` contains a date and time between 12:00 am July 1st this year and 12:00 am August 1st this year | +| {[august]} | Include records where `fld` contains a date and time between 12:00 am August 1st this year and 12:00 am September 1st this year | +| {[september]} | Include records where `fld` contains a date and time between 12:00 am September 1st this year and 12:00 am October 1st this year | +| {[october]} | Include records where `fld` contains a date and time between 12:00 am October 1st this year and 12:00 am November 1st this year | +| {[november]} | Include records where `fld` contains a date and time between 12:00 am November 1st this year and 12:00 am December 1st this year | +| {[december]} | Include records where `fld` contains a date and time between 12:00 am December 1st this year and 12:00 am January 1st next year | diff --git a/server/AyaNova/biz/FilterSpecialTokens.cs b/server/AyaNova/biz/FilterSpecialTokens.cs index c3f54ece..a2201da3 100644 --- a/server/AyaNova/biz/FilterSpecialTokens.cs +++ b/server/AyaNova/biz/FilterSpecialTokens.cs @@ -24,6 +24,19 @@ namespace AyaNova.Biz public const string InTheLast6Months = "{[last6months]}"; public const string InTheLastYear = "{[lastcalendaryear]}"; + //Months THIS year + public const string January = "{[january]}"; + public const string February = "{[february]}"; + public const string March = "{[march]}"; + public const string April = "{[april]}"; + public const string May = "{[may]}"; + public const string June = "{[june]}"; + public const string July = "{[july]}"; + public const string August = "{[august]}"; + public const string September = "{[september]}"; + public const string October = "{[october]}"; + public const string November = "{[november]}"; + public const string December = "{[december]}"; //These TEXT filter tokens were more for paging purposes than anything else //however paging is done by numeric range now so will not implement for now @@ -41,16 +54,16 @@ namespace AyaNova.Biz //public const string GreaterThanZero = "{[>0]}"; //https://www.klipfolio.com/resources/articles/kpi-timeframe-comparison-metrics - + //More business time frames - + public const string YearToDate = "{[yeartodate]}"; - + public const string Past90Days = "{[past90days]}"; public const string Past30Days = "{[past30days]}"; public const string Past24Hours = "{[past24hours]}"; - + diff --git a/server/AyaNova/biz/FilterSqlCriteriaBuilder.cs b/server/AyaNova/biz/FilterSqlCriteriaBuilder.cs index 2ed61379..2213c9af 100644 --- a/server/AyaNova/biz/FilterSqlCriteriaBuilder.cs +++ b/server/AyaNova/biz/FilterSqlCriteriaBuilder.cs @@ -10,7 +10,7 @@ using Microsoft.Extensions.Logging; namespace AyaNova.Biz { public static class FilterSqlCriteriaBuilder - { + { public static string DataFilterToSQLCriteria(AyaNova.Models.DataFilter dataFilter, FilterOptions filterOptions, long userId) { @@ -442,9 +442,9 @@ namespace AyaNova.Biz break; case FilterSpecialToken.NextMonth: - //BUGBUG? - //SERVER thinks midnight UTC is 7am our time on January 1st 2020 - //TEST thinks midnight UTC is 8am our time on January 1st 2020 + //BUGBUG? + //SERVER thinks midnight UTC is 7am our time on January 1st 2020 + //TEST thinks midnight UTC is 8am our time on January 1st 2020 //start with the first day of this month dtAfter = new DateTime(RelativeToday.Year, RelativeToday.Month, 1, RelativeToday.Hour, RelativeToday.Minute, 00); //Add a Month @@ -564,6 +564,82 @@ namespace AyaNova.Biz BuildBetweenTwoDatesFragment(sColumn, sb, dtAfter, dtBefore); break; + case FilterSpecialToken.January: + //From zero hour january 1 this year + dtAfter = new DateTime(RelativeNow.Year, 1, 1, 00, 00, 00).AddSeconds(-1).AddHours(TimeZoneAdjustment); + //To zero hour feb 1 this year + dtBefore = new DateTime(RelativeNow.Year, 2, 1, 00, 00, 00).AddHours(TimeZoneAdjustment); + BuildBetweenTwoDatesFragment(sColumn, sb, dtAfter, dtBefore); + break; + + case FilterSpecialToken.February: + dtAfter = new DateTime(RelativeNow.Year, 2, 1, 00, 00, 00).AddSeconds(-1).AddHours(TimeZoneAdjustment); + dtBefore = new DateTime(RelativeNow.Year, 3, 1, 00, 00, 00).AddHours(TimeZoneAdjustment); + BuildBetweenTwoDatesFragment(sColumn, sb, dtAfter, dtBefore); + break; + + case FilterSpecialToken.March: + dtAfter = new DateTime(RelativeNow.Year, 3, 1, 00, 00, 00).AddSeconds(-1).AddHours(TimeZoneAdjustment); + dtBefore = new DateTime(RelativeNow.Year, 4, 1, 00, 00, 00).AddHours(TimeZoneAdjustment); + BuildBetweenTwoDatesFragment(sColumn, sb, dtAfter, dtBefore); + break; + + case FilterSpecialToken.April: + dtAfter = new DateTime(RelativeNow.Year, 4, 1, 00, 00, 00).AddSeconds(-1).AddHours(TimeZoneAdjustment); + dtBefore = new DateTime(RelativeNow.Year, 5, 1, 00, 00, 00).AddHours(TimeZoneAdjustment); + BuildBetweenTwoDatesFragment(sColumn, sb, dtAfter, dtBefore); + break; + + case FilterSpecialToken.May: + dtAfter = new DateTime(RelativeNow.Year, 5, 1, 00, 00, 00).AddSeconds(-1).AddHours(TimeZoneAdjustment); + dtBefore = new DateTime(RelativeNow.Year, 6, 1, 00, 00, 00).AddHours(TimeZoneAdjustment); + BuildBetweenTwoDatesFragment(sColumn, sb, dtAfter, dtBefore); + break; + + case FilterSpecialToken.June: + dtAfter = new DateTime(RelativeNow.Year, 6, 1, 00, 00, 00).AddSeconds(-1).AddHours(TimeZoneAdjustment); + dtBefore = new DateTime(RelativeNow.Year, 7, 1, 00, 00, 00).AddHours(TimeZoneAdjustment); + BuildBetweenTwoDatesFragment(sColumn, sb, dtAfter, dtBefore); + break; + + case FilterSpecialToken.July: + dtAfter = new DateTime(RelativeNow.Year, 7, 1, 00, 00, 00).AddSeconds(-1).AddHours(TimeZoneAdjustment); + dtBefore = new DateTime(RelativeNow.Year, 8, 1, 00, 00, 00).AddHours(TimeZoneAdjustment); + BuildBetweenTwoDatesFragment(sColumn, sb, dtAfter, dtBefore); + break; + + case FilterSpecialToken.August: + dtAfter = new DateTime(RelativeNow.Year, 8, 1, 00, 00, 00).AddSeconds(-1).AddHours(TimeZoneAdjustment); + dtBefore = new DateTime(RelativeNow.Year, 9, 1, 00, 00, 00).AddHours(TimeZoneAdjustment); + BuildBetweenTwoDatesFragment(sColumn, sb, dtAfter, dtBefore); + break; + + case FilterSpecialToken.September: + dtAfter = new DateTime(RelativeNow.Year, 9, 1, 00, 00, 00).AddSeconds(-1).AddHours(TimeZoneAdjustment); + dtBefore = new DateTime(RelativeNow.Year, 10, 1, 00, 00, 00).AddHours(TimeZoneAdjustment); + BuildBetweenTwoDatesFragment(sColumn, sb, dtAfter, dtBefore); + break; + + case FilterSpecialToken.October: + dtAfter = new DateTime(RelativeNow.Year, 10, 1, 00, 00, 00).AddSeconds(-1).AddHours(TimeZoneAdjustment); + dtBefore = new DateTime(RelativeNow.Year, 11, 1, 00, 00, 00).AddHours(TimeZoneAdjustment); + BuildBetweenTwoDatesFragment(sColumn, sb, dtAfter, dtBefore); + break; + + case FilterSpecialToken.November: + dtAfter = new DateTime(RelativeNow.Year, 11, 1, 00, 00, 00).AddSeconds(-1).AddHours(TimeZoneAdjustment); + dtBefore = new DateTime(RelativeNow.Year, 12, 1, 00, 00, 00).AddHours(TimeZoneAdjustment); + BuildBetweenTwoDatesFragment(sColumn, sb, dtAfter, dtBefore); + break; + + case FilterSpecialToken.December: + //From zero hour dec 1 this year + dtAfter = new DateTime(RelativeNow.Year, 12, 1, 00, 00, 00).AddSeconds(-1).AddHours(TimeZoneAdjustment); + //To zero hour Jan 1 next year + dtBefore = new DateTime(RelativeNow.AddYears(1).Year, 1, 1, 00, 00, 00).AddHours(TimeZoneAdjustment); + BuildBetweenTwoDatesFragment(sColumn, sb, dtAfter, dtBefore); + break; + default: throw new System.ArgumentOutOfRangeException("TOKEN", sOperator, "GridToSqlCriteria invalid filter TOKEN type [" + sValue + "] IN DATE_TIME");