Compare commits
	
		
			354 Commits
		
	
	
		
			v2.7.0
			...
			release/v3
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
|   | e7b8ff7674 | ||
|   | 4e189980e5 | ||
|   | 3c139374a9 | ||
|   | 1bd1cf0af6 | ||
|   | 6ce0f2fb51 | ||
|   | 020ff8641a | ||
|   | 342c6900ef | ||
|   | 83ce648020 | ||
|   | dba50327b0 | ||
|   | b15808d1e0 | ||
|   | a549024a29 | ||
|   | 6f84eeb901 | ||
|   | 6cb71d4cdf | ||
|   | c44dabe2f3 | ||
|   | c78888372c | ||
|   | 4ae0b99f55 | ||
|   | 41e172be25 | ||
|   | d7e05eac60 | ||
|   | fd25e19095 | ||
|   | 3b8a8bafff | ||
|   | 20785d82ce | ||
|   | 1327b29d7b | ||
|   | 226cd3e9e9 | ||
|   | de512f0e2c | ||
|   | 7a845e2f8c | ||
|   | b0f925a7c0 | ||
|   | 984c8fafac | ||
|   | da23ff1192 | ||
|   | 4b07db924d | ||
|   | 10a39f2f50 | ||
|   | 8fc7ce7ca8 | ||
|   | da015b2ea0 | ||
|   | cd9fdc7a91 | ||
|   | a619c0dbe1 | ||
|   | 2575fa628a | ||
|   | 3529f86788 | ||
|   | 0a846e45c4 | ||
|   | 01b1107bac | ||
|   | 9412c0094b | ||
|   | d6e3701ca3 | ||
|   | 5ac7b92f1f | ||
|   | 74557c1600 | ||
|   | c6535500f2 | ||
|   | 2e8a2fe1c8 | ||
|   | 102e240c7e | ||
|   | fd85c70c2f | ||
|   | ec11708046 | ||
|   | eed9525845 | ||
|   | 4ded8997cd | ||
|   | 4ab9a1d6ac | ||
|   | bc116c1d82 | ||
|   | b7b58196e6 | ||
|   | f5b5b3eb13 | ||
|   | 5a8d5a1fa1 | ||
|   | 4e92a19b90 | ||
|   | 713b995d01 | ||
|   | 8eb60b00ad | ||
|   | eb241d9be4 | ||
|   | 836fb44991 | ||
|   | 3eb579038c | ||
|   | 0121ed5073 | ||
|   | 51d7e599fb | ||
|   | fc307dace5 | ||
|   | 5a646ebd49 | ||
|   | a296c31127 | ||
|   | f506b6e2ab | ||
|   | f5676b0917 | ||
|   | 5094157f98 | ||
|   | dee0f1fc01 | ||
|   | 43e9d8a775 | ||
|   | 951164128c | ||
|   | 1caa757a77 | ||
|   | 7972b7cd6a | ||
|   | 6eb50d1318 | ||
|   | 1bb9f492d2 | ||
|   | 0ecf5fdef9 | ||
|   | a20dd5ad47 | ||
|   | 09351c4bbb | ||
|   | e5999a3810 | ||
|   | 52e698c5db | ||
|   | 8735dafbb0 | ||
|   | 60ff1e76d3 | ||
|   | c1fbac422b | ||
|   | 089edd2864 | ||
|   | 09306f8547 | ||
|   | 885619e5ae | ||
|   | 3d32768bd4 | ||
|   | 5300b56ab7 | ||
|   | d9eb14c962 | ||
|   | c7043fa12c | ||
|   | 541266f7cf | ||
|   | ecf660e568 | ||
|   | f82739688b | ||
|   | 969bcb0c25 | ||
|   | d74e791fae | ||
|   | 08976831f2 | ||
|   | eb4722d944 | ||
|   | bf17e99ccf | ||
|   | 4af09f15cf | ||
|   | f74a3877ae | ||
|   | cf2f3f57e9 | ||
|   | c3938921ce | ||
|   | 174f62992c | ||
|   | 8ba53d416b | ||
|   | 2c7b9cf1bd | ||
|   | 91826d136a | ||
|   | a6ac483ec3 | ||
|   | ce3ae0650f | ||
|   | a0c0efff73 | ||
|   | ae9c464fb3 | ||
|   | 6575e47c74 | ||
|   | 507ece011f | ||
|   | 7f5fb52157 | ||
|   | e6bc329e7b | ||
|   | acf3c060c2 | ||
|   | 0437a8ed6a | ||
|   | 3b2d94172d | ||
|   | c573601a91 | ||
|   | fcd9c48569 | ||
|   | ad31dedf22 | ||
|   | 6ff4308f7e | ||
|   | 5bb9c1f427 | ||
|   | e1af5adccb | ||
|   | aec31441d4 | ||
|   | 14efffa612 | ||
|   | 25ebd7f203 | ||
|   | 8cb6d58573 | ||
|   | 6d9b9747a0 | ||
|   | a951cb0549 | ||
|   | 27f6d7c552 | ||
|   | 9ed74e0149 | ||
|   | b8ca24183d | ||
|   | af6a30d248 | ||
|   | 3469b20c28 | ||
|   | 65e5669bd5 | ||
|   | a8581f8f95 | ||
|   | fcce87d160 | ||
|   | e5f9759667 | ||
|   | 817aeb405c | ||
|   | 3292649808 | ||
|   | a8da1a4223 | ||
|   | 69e507a5bd | ||
|   | 7dd33ca841 | ||
|   | 3029fbd596 | ||
|   | b7cb91b022 | ||
|   | 4658f046d9 | ||
|   | 9afdf685a4 | ||
|   | b4f5f8bde1 | ||
|   | 05ddc258ac | ||
|   | 23120feb82 | ||
|   | 16f8f788d5 | ||
|   | 0e54497c57 | ||
|   | 2c612ab136 | ||
|   | 48d3831052 | ||
|   | 8388d12c88 | ||
|   | bc8e7e8ac9 | ||
|   | 74ba4d8d8c | ||
|   | 87c4b714b1 | ||
|   | 91d833b669 | ||
|   | 30e38c21fc | ||
|   | 723e20de44 | ||
|   | 03bd284183 | ||
|   | 9ea65ebe5d | ||
|   | 26a1d5df44 | ||
|   | dfc97ee8f9 | ||
|   | 8e07eeb000 | ||
|   | 3ed97e6c18 | ||
|   | e71b83ced7 | ||
|   | 1d077b945d | ||
|   | ba46c1558c | ||
|   | ca1cf64fa2 | ||
|   | 1948c50ad4 | ||
|   | c5737de2fc | ||
|   | 5a3ce59073 | ||
|   | 26fc29ac12 | ||
|   | 19314815cd | ||
|   | 5b040d132f | ||
|   | 5bdcbe8423 | ||
|   | 1ce856f222 | ||
|   | 9068eb32b7 | ||
|   | 4c9dbd76e1 | ||
|   | 4c2ba2ec28 | ||
|   | a1176e7f4d | ||
|   | f2b1169d8c | ||
|   | 5650e0decc | ||
|   | 98f37d4748 | ||
|   | 2065bd872d | ||
|   | 96cfaf5051 | ||
|   | 63f49db54c | ||
|   | 7b524aa974 | ||
|   | 7d995e7cb1 | ||
|   | 94ce329143 | ||
|   | f9af051ce9 | ||
|   | 87653e1e4b | ||
|   | 4b78e64eb5 | ||
|   | 3dadc191d5 | ||
|   | 8a12becd2b | ||
|   | 74de9188d2 | ||
|   | cb7ad596e2 | ||
|   | 19528133a3 | ||
|   | 043c167d3d | ||
|   | 1d14018470 | ||
|   | 5660689d68 | ||
|   | 4fecee46ac | ||
|   | 797a7f20bc | ||
|   | 5390d1fcec | ||
|   | bf20fc27eb | ||
|   | 69dce68d1a | ||
|   | ca7c618c16 | ||
|   | 8826031939 | ||
|   | 21f8742bd8 | ||
|   | 5cc00a2e72 | ||
|   | b950694753 | ||
|   | 3ce14e5efe | ||
|   | 7f860eb633 | ||
|   | 2628fe1b6a | ||
|   | 29a48f6753 | ||
|   | f8220e3a5e | ||
|   | 8dde169148 | ||
|   | 0437031d78 | ||
|   | 2242b02f0f | ||
|   | 8287628583 | ||
|   | 7b3de5d5ef | ||
|   | 6007c1f06f | ||
|   | 74916abdbd | ||
|   | 0899c6f2d9 | ||
|   | f51b2bd11e | ||
|   | 8b21ef16a1 | ||
|   | 7ad4de4960 | ||
|   | c5e63ce95b | ||
|   | ba3607bd87 | ||
|   | ba526f85a8 | ||
|   | ecea2a1fb4 | ||
|   | e2e5687b47 | ||
|   | 5c0150b81c | ||
|   | ea4b1677f4 | ||
|   | 38b9d6c231 | ||
|   | a7fa58b72a | ||
|   | 8e014eaeba | ||
|   | 3c6730ee44 | ||
|   | a8dec654eb | ||
|   | f722389f74 | ||
|   | 54518912a3 | ||
|   | 5bf58812a1 | ||
|   | de364a1ffe | ||
|   | 593bee9a94 | ||
|   | d431e777a1 | ||
|   | d3639cf5a0 | ||
|   | 8424910f0e | ||
|   | ac6780d094 | ||
|   | bf6f5389d7 | ||
|   | 3c8400ba97 | ||
|   | 8957fde7bd | ||
|   | a1dc0b38cc | ||
|   | a25b90ec82 | ||
|   | 315cbaf3c1 | ||
|   | 1ca3c0ade4 | ||
|   | 93224f609f | ||
|   | cb2f9a91b5 | ||
|   | 865ad612e6 | ||
|   | 19b4f9edd1 | ||
|   | 350553bd86 | ||
|   | 3b45abd604 | ||
|   | df2f5bb21b | ||
|   | b1a489fa8f | ||
|   | 9235bf7b73 | ||
|   | 0b35942ef6 | ||
|   | d5e0687ade | ||
|   | b54a914c0d | ||
|   | 3e03b127fe | ||
|   | 15f91dc667 | ||
|   | 3e9663bcf4 | ||
|   | 6b4d9e1720 | ||
|   | d86d15ffe1 | ||
|   | ba36df0182 | ||
|   | ac5c8bf531 | ||
|   | 513fa9264b | ||
|   | 8d6a9f6d5b | ||
|   | 8b249f6f92 | ||
|   | 93da8d1229 | ||
|   | 4d3ed84e5c | ||
|   | 4b104c961a | ||
|   | db367133a8 | ||
|   | 5baf3b1b19 | ||
|   | 6a923375ad | ||
|   | 39b1352d4e | ||
|   | df9d05bd69 | ||
|   | ca63e3cae6 | ||
|   | fe14eaac58 | ||
|   | 5172d95aac | ||
|   | 5e2ab7a37b | ||
|   | 12ff4adc41 | ||
|   | 6e88403685 | ||
|   | 174b209065 | ||
|   | 0d380f9585 | ||
|   | c249911f9c | ||
|   | 1cc9ef6466 | ||
|   | 6aee513a45 | ||
|   | 66ca992fee | ||
|   | cd216c7949 | ||
|   | 1f0366335b | ||
|   | 38b4d82e79 | ||
|   | 601c75bccb | ||
|   | 325801b583 | ||
|   | b1fba48ed1 | ||
|   | 9ab2b5ee60 | ||
|   | 7a5d484932 | ||
|   | f623368923 | ||
|   | 188ecabd33 | ||
|   | 5326fbf390 | ||
|   | 6ee055adff | ||
|   | 5d66fe0d56 | ||
|   | 378ff98bfb | ||
|   | 01cbb382d1 | ||
|   | 1cba12b934 | ||
|   | 9b8de5efd2 | ||
|   | 01d7a048dd | ||
|   | da31483c78 | ||
|   | a22fac8b86 | ||
|   | fe50daf627 | ||
|   | 711f1808d8 | ||
|   | 23aa41dd8d | ||
|   | 30385a5cc3 | ||
|   | 0145aa3e52 | ||
|   | 97575715a3 | ||
|   | 125800e78a | ||
|   | 606a806d62 | ||
|   | 46b5daed8f | ||
|   | d1edab2bcf | ||
|   | 2bf972cec6 | ||
|   | d706dba60a | ||
|   | 8b23197359 | ||
|   | 4f4dcc9071 | ||
|   | a30b4e1dae | ||
|   | 21aa3ef685 | ||
|   | a6a9daa8a1 | ||
|   | 5b546ea381 | ||
|   | be8805e86d | ||
|   | efe9076c35 | ||
|   | 4a55483f90 | ||
|   | af336e5ddf | ||
|   | 222674ae1b | ||
|   | ec684090ae | ||
|   | c0004dc804 | ||
|   | d08d64ae27 | ||
|   | 9a9d25f045 | ||
|   | fdded83221 | ||
|   | 8a98844bac | ||
|   | a9105f06aa | ||
|   | ac885295ae | ||
|   | 5a0132e174 | ||
|   | 9daee84f88 | ||
|   | d7469cf0b7 | ||
|   | 8d8d52adf2 | 
							
								
								
									
										178
									
								
								.clang-format
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,178 @@ | ||||
| --- | ||||
| Language:        Cpp | ||||
| # BasedOnStyle:  LLVM | ||||
| AccessModifierOffset: -2 | ||||
| AlignAfterOpenBracket: Align | ||||
| AlignArrayOfStructures: None | ||||
| AlignConsecutiveMacros: None | ||||
| AlignConsecutiveAssignments: None | ||||
| AlignConsecutiveBitFields: None | ||||
| AlignConsecutiveDeclarations: None | ||||
| AlignEscapedNewlines: Right | ||||
| AlignOperands:   Align | ||||
| AlignTrailingComments: true | ||||
| AllowAllArgumentsOnNextLine: true | ||||
| AllowAllConstructorInitializersOnNextLine: true | ||||
| AllowAllParametersOfDeclarationOnNextLine: true | ||||
| AllowShortEnumsOnASingleLine: true | ||||
| AllowShortBlocksOnASingleLine: Never | ||||
| AllowShortCaseLabelsOnASingleLine: false | ||||
| AllowShortFunctionsOnASingleLine: All | ||||
| AllowShortLambdasOnASingleLine: All | ||||
| AllowShortIfStatementsOnASingleLine: Never | ||||
| AllowShortLoopsOnASingleLine: false | ||||
| AlwaysBreakAfterDefinitionReturnType: None | ||||
| AlwaysBreakAfterReturnType: None | ||||
| AlwaysBreakBeforeMultilineStrings: false | ||||
| AlwaysBreakTemplateDeclarations: MultiLine | ||||
| AttributeMacros: | ||||
|   - __capability | ||||
| BinPackArguments: true | ||||
| BinPackParameters: true | ||||
| BraceWrapping: | ||||
|   AfterCaseLabel:  false | ||||
|   AfterClass:      false | ||||
|   AfterControlStatement: Never | ||||
|   AfterEnum:       false | ||||
|   AfterFunction:   false | ||||
|   AfterNamespace:  false | ||||
|   AfterObjCDeclaration: false | ||||
|   AfterStruct:     false | ||||
|   AfterUnion:      false | ||||
|   AfterExternBlock: false | ||||
|   BeforeCatch:     false | ||||
|   BeforeElse:      false | ||||
|   BeforeLambdaBody: false | ||||
|   BeforeWhile:     false | ||||
|   IndentBraces:    false | ||||
|   SplitEmptyFunction: true | ||||
|   SplitEmptyRecord: true | ||||
|   SplitEmptyNamespace: true | ||||
| BreakBeforeBinaryOperators: None | ||||
| BreakBeforeConceptDeclarations: true | ||||
| BreakBeforeBraces: Attach | ||||
| BreakBeforeInheritanceComma: false | ||||
| BreakInheritanceList: BeforeColon | ||||
| BreakBeforeTernaryOperators: true | ||||
| BreakConstructorInitializersBeforeComma: false | ||||
| BreakConstructorInitializers: BeforeColon | ||||
| BreakAfterJavaFieldAnnotations: false | ||||
| BreakStringLiterals: true | ||||
| ColumnLimit:     100 | ||||
| CommentPragmas:  '^ IWYU pragma:' | ||||
| CompactNamespaces: false | ||||
| ConstructorInitializerAllOnOneLineOrOnePerLine: false | ||||
| ConstructorInitializerIndentWidth: 4 | ||||
| ContinuationIndentWidth: 4 | ||||
| Cpp11BracedListStyle: true | ||||
| DeriveLineEnding: true | ||||
| DerivePointerAlignment: false | ||||
| DisableFormat:   false | ||||
| EmptyLineAfterAccessModifier: Never | ||||
| EmptyLineBeforeAccessModifier: LogicalBlock | ||||
| ExperimentalAutoDetectBinPacking: false | ||||
| FixNamespaceComments: true | ||||
| ForEachMacros: | ||||
|   - foreach | ||||
|   - Q_FOREACH | ||||
|   - BOOST_FOREACH | ||||
| IfMacros: | ||||
|   - KJ_IF_MAYBE | ||||
| IncludeBlocks:   Preserve | ||||
| IncludeCategories: | ||||
|   - Regex:           '^"(llvm|llvm-c|clang|clang-c)/' | ||||
|     Priority:        2 | ||||
|     SortPriority:    0 | ||||
|     CaseSensitive:   false | ||||
|   - Regex:           '^(<|"(gtest|gmock|isl|json)/)' | ||||
|     Priority:        3 | ||||
|     SortPriority:    0 | ||||
|     CaseSensitive:   false | ||||
|   - Regex:           '.*' | ||||
|     Priority:        1 | ||||
|     SortPriority:    0 | ||||
|     CaseSensitive:   false | ||||
| IncludeIsMainRegex: '(Test)?$' | ||||
| IncludeIsMainSourceRegex: '' | ||||
| IndentAccessModifiers: false | ||||
| IndentCaseLabels: false | ||||
| IndentCaseBlocks: false | ||||
| IndentGotoLabels: true | ||||
| IndentPPDirectives: None | ||||
| IndentExternBlock: AfterExternBlock | ||||
| IndentRequires:  false | ||||
| IndentWidth:     4 | ||||
| IndentWrappedFunctionNames: false | ||||
| InsertTrailingCommas: None | ||||
| JavaScriptQuotes: Leave | ||||
| JavaScriptWrapImports: true | ||||
| KeepEmptyLinesAtTheStartOfBlocks: true | ||||
| LambdaBodyIndentation: Signature | ||||
| MacroBlockBegin: '' | ||||
| MacroBlockEnd:   '' | ||||
| MaxEmptyLinesToKeep: 1 | ||||
| NamespaceIndentation: All | ||||
| ObjCBinPackProtocolList: Auto | ||||
| ObjCBlockIndentWidth: 2 | ||||
| ObjCBreakBeforeNestedBlockParam: true | ||||
| ObjCSpaceAfterProperty: false | ||||
| ObjCSpaceBeforeProtocolList: true | ||||
| PenaltyBreakAssignment: 2 | ||||
| PenaltyBreakBeforeFirstCallParameter: 19 | ||||
| PenaltyBreakComment: 300 | ||||
| PenaltyBreakFirstLessLess: 120 | ||||
| PenaltyBreakString: 1000 | ||||
| PenaltyBreakTemplateDeclaration: 10 | ||||
| PenaltyExcessCharacter: 1000000 | ||||
| PenaltyReturnTypeOnItsOwnLine: 60 | ||||
| PenaltyIndentedWhitespace: 0 | ||||
| PointerAlignment: Right | ||||
| PPIndentWidth:   -1 | ||||
| ReferenceAlignment: Pointer | ||||
| ReflowComments:  true | ||||
| ShortNamespaceLines: 1 | ||||
| SortIncludes:    CaseSensitive | ||||
| SortJavaStaticImport: Before | ||||
| SortUsingDeclarations: true | ||||
| SpaceAfterCStyleCast: false | ||||
| SpaceAfterLogicalNot: false | ||||
| SpaceAfterTemplateKeyword: true | ||||
| SpaceBeforeAssignmentOperators: true | ||||
| SpaceBeforeCaseColon: false | ||||
| SpaceBeforeCpp11BracedList: false | ||||
| SpaceBeforeCtorInitializerColon: true | ||||
| SpaceBeforeInheritanceColon: true | ||||
| SpaceBeforeParens: ControlStatements | ||||
| SpaceAroundPointerQualifiers: Default | ||||
| SpaceBeforeRangeBasedForLoopColon: true | ||||
| SpaceInEmptyBlock: false | ||||
| SpaceInEmptyParentheses: false | ||||
| SpacesBeforeTrailingComments: 1 | ||||
| SpacesInAngles:  Never | ||||
| SpacesInConditionalStatement: false | ||||
| SpacesInContainerLiterals: true | ||||
| SpacesInCStyleCastParentheses: false | ||||
| SpacesInLineCommentPrefix: | ||||
|   Minimum:         1 | ||||
|   Maximum:         -1 | ||||
| SpacesInParentheses: false | ||||
| SpacesInSquareBrackets: false | ||||
| SpaceBeforeSquareBrackets: false | ||||
| BitFieldColonSpacing: Both | ||||
| Standard:        Latest | ||||
| StatementAttributeLikeMacros: | ||||
|   - Q_EMIT | ||||
| StatementMacros: | ||||
|   - Q_UNUSED | ||||
|   - QT_REQUIRE_VERSION | ||||
| TabWidth:        4 | ||||
| UseCRLF:         false | ||||
| UseTab:          Always | ||||
| WhitespaceSensitiveMacros: | ||||
|   - STRINGIZE | ||||
|   - PP_STRINGIZE | ||||
|   - BOOST_PP_STRINGIZE | ||||
|   - NS_SWIFT_NAME | ||||
|   - CF_SWIFT_NAME | ||||
| ... | ||||
|  | ||||
							
								
								
									
										8
									
								
								.github/workflows/ci.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						| @@ -27,7 +27,7 @@ jobs: | ||||
|       DOCKER_REGISTRY_USERNAME: ucentral | ||||
|     steps: | ||||
|     - name: Checkout actions repo | ||||
|       uses: actions/checkout@v2 | ||||
|       uses: actions/checkout@v3 | ||||
|       with: | ||||
|         repository: Telecominfraproject/.github | ||||
|         path: github | ||||
| @@ -58,11 +58,11 @@ jobs: | ||||
|     - name: Get base branch name and set as output | ||||
|       id: get_base_branch | ||||
|       run: | | ||||
|         echo ::set-output name=branch::$(echo ${GITHUB_BASE_REF##*/}) | ||||
|         echo ::set-output name=owgw_branch::$(echo ${GITHUB_BASE_REF##*/} | sed 's/main/master/g') | ||||
|         echo "branch=$(echo ${GITHUB_BASE_REF##*/})" >> $GITHUB_OUTPUT | ||||
|         echo "owgw_branch=$(echo ${GITHUB_BASE_REF##*/} | sed 's/main/master/g')" >> $GITHUB_OUTPUT | ||||
|  | ||||
|     - name: Checkout actions repo | ||||
|       uses: actions/checkout@v2 | ||||
|       uses: actions/checkout@v3 | ||||
|       with: | ||||
|         repository: Telecominfraproject/.github | ||||
|         path: github | ||||
|   | ||||
							
								
								
									
										2
									
								
								.github/workflows/enforce-jira-issue-key.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						| @@ -11,7 +11,7 @@ jobs: | ||||
|     runs-on: ubuntu-latest | ||||
|     steps: | ||||
|       - name: Checkout actions repo | ||||
|         uses: actions/checkout@v2 | ||||
|         uses: actions/checkout@v3 | ||||
|         with: | ||||
|           repository: Telecominfraproject/.github | ||||
|           path: github | ||||
|   | ||||
							
								
								
									
										41
									
								
								.github/workflows/openapi-pages.yml
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,41 @@ | ||||
| name: Update OpenAPI docs on GitHub Pages | ||||
|  | ||||
| on: | ||||
|   push: | ||||
|     paths: | ||||
|       - 'openapi/**' | ||||
|     branches: | ||||
|       - main | ||||
|   workflow_dispatch: | ||||
|  | ||||
| defaults: | ||||
|   run: | ||||
|     shell: bash | ||||
|  | ||||
| jobs: | ||||
|   docsgen: | ||||
|     runs-on: ubuntu-latest | ||||
|     steps: | ||||
|       - uses: actions/checkout@v3 | ||||
|  | ||||
|       - name: Generate static HTML page with docs from OpenAPI definition | ||||
|         run: | | ||||
|           docker run --rm -v "${PWD}:/local" openapitools/openapi-generator-cli:v6.2.1 generate -i https://raw.githubusercontent.com/Telecominfraproject/wlan-cloud-owprov/main/openapi/owprov.yaml -g html2 --skip-validate-spec -o /local/ | ||||
|  | ||||
|       - name: Update OpenAPI docs | ||||
|         run: | | ||||
|           mkdir tmp-docs | ||||
|           mv index.html tmp-docs/index.html | ||||
|           mkdir -p ~/.ssh | ||||
|           ssh-keyscan -H github.com >> ~/.ssh/known_hosts | ||||
|           echo https://tip-automation:${{ secrets.GIT_PUSH_PAT }}@github.com > ~/.git-credentials | ||||
|           git config --global credential.helper store | ||||
|           git config --global user.email "tip-automation@telecominfraproject.com" | ||||
|           git config --global user.name "TIP Automation User" | ||||
|           git pull | ||||
|           git checkout gh-pages || git checkout -b gh-pages | ||||
|           rm -rf docs | ||||
|           mv tmp-docs docs | ||||
|           git add docs | ||||
|           git commit -m'Update OpenAPI docs for GitHub pages' | ||||
|           git push --set-upstream origin gh-pages | ||||
							
								
								
									
										2
									
								
								.github/workflows/release.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						| @@ -17,7 +17,7 @@ jobs: | ||||
|       HELM_REPO_USERNAME: ucentral | ||||
|     steps: | ||||
|       - name: Checkout uCentral assembly chart repo | ||||
|         uses: actions/checkout@v2 | ||||
|         uses: actions/checkout@v3 | ||||
|         with: | ||||
|           path: wlan-cloud-owprov | ||||
|  | ||||
|   | ||||
							
								
								
									
										194
									
								
								BUILDING.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,194 @@ | ||||
| # Building from source | ||||
| In order to build OWPROV, you will need to install its dependencies, which includes the following: | ||||
| - cmake | ||||
| - boost | ||||
| - POCO 1.10.1 or later | ||||
| - a C++17 compiler | ||||
| - openssl | ||||
| - libpq-dev (PortgreSQL development libraries) | ||||
| - mysql-client (MySQL client) | ||||
| - librdkafka | ||||
| - cppkafka | ||||
|  | ||||
| The build is done in 2 parts. The first part is to build a local copy of the framework tailored to your environment. This | ||||
| framework is called [Poco](https://github.com/pocoproject/poco). The version used in this project has a couple of fixes | ||||
| from the master copy needed for cmake. Please use the version of this [Poco fix](https://github.com/Telecominfraproject/wlan-cloud-lib-poco). Building | ||||
| Poco may take several minutes depending on the platform you are building on. | ||||
|  | ||||
| ## Ubuntu | ||||
| These instructions have proven to work on Ubuntu 20.4. | ||||
| ```bash | ||||
| sudo apt install git cmake g++ libssl-dev libmariadb-dev | ||||
| sudo apt install libpq-dev libaprutil1-dev apache2-dev libboost-all-dev | ||||
| sudo apt install librdkafka-dev // default-libmysqlclient-dev | ||||
| sudo apt install nlohmann-json-dev | ||||
|  | ||||
| cd ~ | ||||
| git clone https://github.com/Telecominfraproject/wlan-cloud-lib-poco --branch poco-tip-v1 poco | ||||
| cd poco | ||||
| mkdir cmake-build | ||||
| cd cmake-build | ||||
| cmake .. | ||||
| cmake --build . --config Release | ||||
| sudo cmake --build . --target install | ||||
|  | ||||
| cd ~ | ||||
| git clone https://github.com/Telecominfraproject/wlan-cloud-lib-cppkafka --branch tip-v1 cppkafka | ||||
| cd cppkafka | ||||
| mkdir cmake-build | ||||
| cd cmake-build | ||||
| cmake .. | ||||
| cmake --build . --config Release | ||||
| sudo cmake --build . --target install | ||||
|  | ||||
| cd ~ | ||||
| git clone https://github.com/Telecominfraproject/wlan-cloud-lib-valijson --branch tip-v1 valijson | ||||
| cd valijson | ||||
| mkdir cmake-build | ||||
| cd cmake-build | ||||
| cmake .. | ||||
| cmake --build . --config Release | ||||
| sudo cmake --build . --target install | ||||
|  | ||||
| cd ~ | ||||
| git clone https://github.com/fmtlib/fmt --branch 9.0.0 fmtlib | ||||
| cd fmtlib | ||||
| mkdir cmake-build | ||||
| cd cmake-build | ||||
| cmake .. | ||||
| make | ||||
| make install | ||||
|  | ||||
| cd ~ | ||||
| git clone https://github.com/Telecominfraproject/wlan-cloud-owprov | ||||
| cd wlan-cloud-owprov | ||||
| mkdir cmake-build | ||||
| cd cmake-build | ||||
| cmake .. | ||||
| make -j 8 | ||||
| ``` | ||||
|  | ||||
| ## Fedora | ||||
| The following instructions have proven to work on Fedora 33 | ||||
| ```bash | ||||
| sudo yum install cmake g++ openssl-devel mysql-devel mysql apr-util-devel boost boost-devel | ||||
| sudo yum install yaml-cpp-devel lua-devel | ||||
| sudo dnf install postgresql.x86_64 librdkafka-devel | ||||
| sudo dnf install postgresql-devel json-devel | ||||
|  | ||||
| git clone https://github.com/Telecominfraproject/wlan-cloud-lib-poco --branch poco-tip-v1 poco | ||||
| cd poco | ||||
| mkdir cmake-build | ||||
| cd cmake-build | ||||
| cmake .. | ||||
| cmake --build . --config Release | ||||
| sudo cmake --build . --target install | ||||
|  | ||||
| cd ~ | ||||
| git clone https://github.com/Telecominfraproject/wlan-cloud-lib-cppkafka --branch tip-v1 cppkafka | ||||
| cd cppkafka | ||||
| mkdir cmake-build | ||||
| cd cmake-build | ||||
| cmake .. | ||||
| cmake --build . --config Release | ||||
| sudo cmake --build . --target install | ||||
|  | ||||
| cd ~ | ||||
| git clone https://github.com/Telecominfraproject/wlan-cloud-lib-valijson --branch tip-v1 valijson | ||||
| cd valijson | ||||
| mkdir cmake-build | ||||
| cd cmake-build | ||||
| cmake .. | ||||
| cmake --build . --config Release | ||||
| sudo cmake --build . --target install | ||||
|  | ||||
| cd ~ | ||||
| git clone https://github.com/Telecominfraproject/wlan-cloud-owprov | ||||
| cd wlan-cloud-owprov | ||||
| mkdir cmake-build | ||||
| cd cmake-build | ||||
| cmake .. | ||||
| make | ||||
| ``` | ||||
|  | ||||
| ## macOS Build | ||||
| The following instructions have proven to work on macOS Big Sur. You need to install [Homebrew](https://brew.sh/). You must also have installed [XCode for OS X](https://www.freecodecamp.org/news/how-to-download-and-install-xcode/). | ||||
| ```bash | ||||
| brew install openssl \ | ||||
| 	cmake \ | ||||
| 	libpq \ | ||||
| 	mysql-client \ | ||||
| 	apr \ | ||||
| 	apr-util \ | ||||
| 	boost \ | ||||
| 	yaml-cpp \ | ||||
| 	postgresql \ | ||||
| 	librdkafka \ | ||||
| 	nlohmann-json \ | ||||
| 	fmt | ||||
|  | ||||
| git clone https://github.com/Telecominfraproject/wlan-cloud-lib-poco --branch poco-tip-v1 poco | ||||
| pushd poco | ||||
| mkdir cmake-build | ||||
| push cmake-build | ||||
| cmake -DOPENSSL_ROOT_DIR=</path/to/openssl> -DENABLE_NETSSL=1 -DENABLE_JWT=1 -DENABLE_CRYPTO=1 .. | ||||
| cmake --build . --config Release | ||||
| sudo cmake --build . --target install | ||||
| popd | ||||
| popd | ||||
|  | ||||
| git clone https://github.com/Telecominfraproject/wlan-cloud-lib-cppkafka --branch tip-v1 cppkafka | ||||
| pushd cppkafka | ||||
| mkdir cmake-build | ||||
| pushd cmake-build | ||||
| cmake .. | ||||
| cmake --build . --config Release | ||||
| sudo cmake --build . --target install | ||||
| popd | ||||
| popd | ||||
|  | ||||
| git clone https://github.com/Telecominfraproject/wlan-cloud-lib-valijson --branch tip-v1 valijson | ||||
| cd valijson | ||||
| mkdir cmake-build | ||||
| cd cmake-build | ||||
| cmake .. | ||||
| cmake --build . --config Release | ||||
| sudo cmake --build . --target install | ||||
| popd | ||||
| popd | ||||
|  | ||||
| git clone https://github.com/Telecominfraproject/wlan-cloud-owprov | ||||
| pushd wlan-cloud-owprov | ||||
| mkdir cmake-build | ||||
| pushd cmake-build | ||||
| cmake .. | ||||
| make -j | ||||
| popd | ||||
| popd | ||||
| ``` | ||||
|  | ||||
| ## Raspberry | ||||
| The build on a rPI takes a while. You can shorten that build time and requirements by disabling all the larger database | ||||
| support. You can build with only SQLite support by not installing the packages for PostgreSQL, and MySQL by | ||||
| adding -DSMALL_BUILD=1 on the cmake build line. | ||||
|  | ||||
| ```bash | ||||
| sudo apt install git cmake g++ libssl-dev libaprutil1-dev apache2-dev libboost-all-dev libyaml-cpp-dev | ||||
|  | ||||
| cd ~ | ||||
| git clone https://github.com/stephb9959/poco | ||||
| cd poco | ||||
| mkdir cmake-build | ||||
| cd cmake-build | ||||
| cmake .. | ||||
| cmake --build . --config Release | ||||
| sudo cmake --build . --target install | ||||
|  | ||||
| cd ~ | ||||
| git clone https://github.com/Telecominfraproject/wlan-cloud-owprov | ||||
| cd wlan-cloud-owprov | ||||
| mkdir cmake-build | ||||
| cd cmake-build | ||||
| cmake -DSMALL_BUILD=1 .. | ||||
| make | ||||
| ``` | ||||
							
								
								
									
										136
									
								
								CMakeLists.txt
									
									
									
									
									
								
							
							
						
						| @@ -1,5 +1,5 @@ | ||||
| cmake_minimum_required(VERSION 3.13) | ||||
| project(owprov VERSION 2.7.0) | ||||
| project(owprov VERSION 3.2.1) | ||||
|  | ||||
| set(CMAKE_CXX_STANDARD 17) | ||||
|  | ||||
| @@ -27,23 +27,24 @@ endif() | ||||
|  | ||||
| find_package(Git QUIET) | ||||
| if(GIT_FOUND AND EXISTS "${PROJECT_SOURCE_DIR}/.git") | ||||
|     execute_process(COMMAND ${GIT_EXECUTABLE} describe --always --tags | ||||
|     execute_process(COMMAND ${GIT_EXECUTABLE} rev-parse --short HEAD | ||||
|             WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} | ||||
|             RESULT_VARIABLE GIT_RESULT | ||||
|             OUTPUT_VARIABLE GIT_HASH) | ||||
|     if(NOT GIT_RESULT EQUAL "0") | ||||
|         message(FATAL_ERROR "git describe --always --tags failed with ${GIT_RESULT}") | ||||
|         message(FATAL_ERROR "git rev-parse --short HEAD failed with ${GIT_RESULT}") | ||||
|     endif() | ||||
|     string(REGEX REPLACE "\n$" "" GIT_HASH "${GIT_HASH}") | ||||
| endif() | ||||
|  | ||||
| add_definitions(-DAWS_CUSTOM_MEMORY_MANAGEMENT) | ||||
| add_definitions(-DAWS_CUSTOM_MEMORY_MANAGEMENT -DBOOST_NO_CXX98_FUNCTION_BASE=1) | ||||
|  | ||||
| find_package(OpenSSL    REQUIRED) | ||||
| find_package(ZLIB       REQUIRED) | ||||
| find_package(Poco       REQUIRED COMPONENTS Crypto JWT Net Util NetSSL Data DataSQLite) | ||||
| find_package(nlohmann_json  REQUIRED) | ||||
| find_package(nlohmann_json_schema_validator REQUIRED) | ||||
| find_package(fmt        REQUIRED) | ||||
| # find_package(valijson   REQUIRED) | ||||
|  | ||||
| if(SMALL_BUILD) | ||||
|     find_package(Poco REQUIRED COMPONENTS Crypto JWT Net Util NetSSL Data DataSQLite) | ||||
| @@ -75,20 +76,64 @@ add_executable(owprov | ||||
|         src/framework/OpenWifiTypes.h | ||||
|         src/framework/orm.h | ||||
|         src/framework/StorageClass.h | ||||
|         src/framework/MicroServiceErrorHandler.h | ||||
|         src/framework/UI_WebSocketClientServer.cpp | ||||
|         src/framework/UI_WebSocketClientServer.h | ||||
|         src/framework/utils.h | ||||
|         src/framework/utils.cpp | ||||
|         src/framework/AppServiceRegistry.h | ||||
|         src/framework/SubSystemServer.cpp | ||||
|         src/framework/SubSystemServer.h | ||||
|         src/framework/RESTAPI_utils.h | ||||
|         src/framework/UI_WebSocketClientNotifications.cpp | ||||
|         src/framework/AuthClient.cpp | ||||
|         src/framework/AuthClient.h | ||||
|         src/framework/MicroServiceNames.h | ||||
|         src/framework/MicroServiceFuncs.h | ||||
|         src/framework/OpenAPIRequests.cpp | ||||
|         src/framework/OpenAPIRequests.h | ||||
|         src/framework/MicroServiceFuncs.cpp | ||||
|         src/framework/ALBserver.cpp | ||||
|         src/framework/ALBserver.h | ||||
|         src/framework/KafkaManager.cpp | ||||
|         src/framework/KafkaManager.h | ||||
|         src/framework/RESTAPI_RateLimiter.h | ||||
|         src/framework/WebSocketLogger.h | ||||
|         src/framework/RESTAPI_GenericServerAccounting.h | ||||
|         src/framework/CIDR.h | ||||
|         src/framework/RESTAPI_Handler.cpp | ||||
|         src/framework/RESTAPI_Handler.h | ||||
|         src/framework/RESTAPI_ExtServer.h | ||||
|         src/framework/RESTAPI_ExtServer.cpp | ||||
|         src/framework/RESTAPI_IntServer.cpp | ||||
|         src/framework/RESTAPI_IntServer.h | ||||
|         src/framework/RESTAPI_SystemCommand.h | ||||
|         src/framework/RESTAPI_WebSocketServer.h | ||||
|         src/framework/RESTAPI_SystemConfiguration.h | ||||
|         src/framework/EventBusManager.cpp | ||||
|         src/framework/EventBusManager.h | ||||
|         src/framework/RESTAPI_PartHandler.h | ||||
|         src/framework/MicroService.cpp | ||||
|         src/framework/MicroServiceExtra.h | ||||
|         src/framework/ConfigurationValidator.cpp | ||||
|         src/framework/ConfigurationValidator.h | ||||
|         src/framework/ow_constants.h | ||||
|         src/framework/MicroServiceErrorHandler.h | ||||
|         src/framework/WebSocketClientNotifications.h | ||||
|         src/framework/MicroServiceErrorHandler.h | ||||
|         src/framework/default_device_types.h | ||||
|         src/UI_Prov_WebSocketNotifications.h | ||||
|         src/UI_Prov_WebSocketNotifications.cpp | ||||
|         src/RESTObjects/RESTAPI_SecurityObjects.h src/RESTObjects/RESTAPI_SecurityObjects.cpp | ||||
|         src/RESTObjects/RESTAPI_ProvObjects.cpp src/RESTObjects/RESTAPI_ProvObjects.h | ||||
|         src/RESTObjects/RESTAPI_GWobjects.h src/RESTObjects/RESTAPI_GWobjects.cpp | ||||
|         src/RESTObjects/RESTAPI_FMSObjects.h src/RESTObjects/RESTAPI_FMSObjects.cpp | ||||
|         src/RESTObjects/RESTAPI_CertObjects.cpp src/RESTObjects/RESTAPI_CertObjects.h | ||||
|         src/RESTObjects/RESTAPI_OWLSobjects.cpp src/RESTObjects/RESTAPI_OWLSobjects.h | ||||
|         src/RESTObjects/RESTAPI_ProvObjects.cpp src/RESTObjects/RESTAPI_ProvObjects.h | ||||
|         src/RESTObjects/RESTAPI_AnalyticsObjects.cpp src/RESTObjects/RESTAPI_AnalyticsObjects.h | ||||
|         src/RESTObjects/RESTAPI_SubObjects.cpp src/RESTObjects/RESTAPI_SubObjects.h | ||||
|  | ||||
|         src/RESTAPI/RESTAPI_routers.cpp | ||||
|         src/Daemon.cpp src/Daemon.h | ||||
|         src/Dashboard.h src/Dashboard.cpp | ||||
|         src/StorageService.cpp src/StorageService.h | ||||
|  | ||||
|         src/storage/storage_entity.cpp src/storage/storage_entity.h | ||||
|         src/storage/storage_policies.cpp src/storage/storage_policies.h | ||||
|         src/storage/storage_venue.cpp src/storage/storage_venue.h | ||||
| @@ -98,6 +143,14 @@ add_executable(owprov | ||||
|         src/storage/storage_management_roles.cpp src/storage/storage_management_roles.h | ||||
|         src/storage/storage_configurations.cpp src/storage/storage_configurations.h | ||||
|         src/storage/storage_tags.cpp src/storage/storage_tags.h | ||||
|         src/storage/storage_operataor.cpp src/storage/storage_operataor.h | ||||
|         src/storage/storage_sub_devices.cpp src/storage/storage_sub_devices.h | ||||
|         src/storage/storage_service_class.cpp src/storage/storage_service_class.h | ||||
|         src/storage/storage_maps.cpp src/storage/storage_maps.h | ||||
|         src/storage/storage_signup.cpp src/storage/storage_signup.h | ||||
|         src/storage/storage_variables.cpp src/storage/storage_variables.h | ||||
|         src/storage/storage_overrides.cpp src/storage/storage_overrides.h | ||||
|  | ||||
|         src/RESTAPI/RESTAPI_entity_handler.cpp src/RESTAPI/RESTAPI_entity_handler.h | ||||
|         src/RESTAPI/RESTAPI_contact_handler.cpp src/RESTAPI/RESTAPI_contact_handler.h | ||||
|         src/RESTAPI/RESTAPI_location_handler.cpp src/RESTAPI/RESTAPI_location_handler.h | ||||
| @@ -117,6 +170,13 @@ add_executable(owprov | ||||
|         src/RESTAPI/RESTAPI_iptocountry_handler.cpp src/RESTAPI/RESTAPI_iptocountry_handler.h | ||||
|         src/RESTAPI/RESTAPI_signup_handler.h src/RESTAPI/RESTAPI_signup_handler.cpp | ||||
|         src/RESTAPI/RESTAPI_asset_server.cpp src/RESTAPI/RESTAPI_asset_server.h | ||||
|         src/RESTAPI/RESTAPI_db_helpers.h | ||||
|         src/RESTAPI/RESTAPI_map_handler.cpp src/RESTAPI/RESTAPI_map_handler.h | ||||
|         src/RESTAPI/RESTAPI_map_list_handler.cpp src/RESTAPI/RESTAPI_map_list_handler.h | ||||
|         src/RESTAPI/RESTAPI_variables_handler.cpp src/RESTAPI/RESTAPI_variables_handler.h | ||||
|         src/RESTAPI/RESTAPI_variables_list_handler.cpp src/RESTAPI/RESTAPI_variables_list_handler.h | ||||
|         src/RESTAPI/RESTAPI_overrides_handler.cpp src/RESTAPI/RESTAPI_overrides_handler.h | ||||
|  | ||||
|         src/FindCountry.h | ||||
|         src/sdks/SDK_gw.cpp src/sdks/SDK_gw.h | ||||
|         src/sdks/SDK_prov.cpp src/sdks/SDK_prov.h | ||||
| @@ -126,32 +186,60 @@ add_executable(owprov | ||||
|         src/AutoDiscovery.cpp src/AutoDiscovery.h | ||||
|         src/ConfigSanityChecker.cpp src/ConfigSanityChecker.h | ||||
|         src/TagServer.cpp src/TagServer.h | ||||
|         src/RESTAPI/RESTAPI_db_helpers.h | ||||
|         src/JobController.cpp src/JobController.h | ||||
|         src/JobRegistrations.cpp | ||||
|         src/storage/storage_maps.cpp src/storage/storage_maps.h | ||||
|         src/RESTAPI/RESTAPI_map_handler.cpp src/RESTAPI/RESTAPI_map_handler.h | ||||
|         src/RESTAPI/RESTAPI_map_list_handler.cpp src/RESTAPI/RESTAPI_map_list_handler.h | ||||
|         src/storage/storage_signup.cpp src/storage/storage_signup.h | ||||
|         src/Signup.cpp src/Signup.h | ||||
|         src/DeviceTypeCache.h | ||||
|         src/storage/storage_variables.cpp src/storage/storage_variables.h | ||||
|         src/RESTAPI/RESTAPI_variables_handler.cpp src/RESTAPI/RESTAPI_variables_handler.h | ||||
|         src/RESTAPI/RESTAPI_variables_list_handler.cpp src/RESTAPI/RESTAPI_variables_list_handler.h | ||||
|         src/FileDownloader.cpp src/FileDownloader.h | ||||
|         src/Tasks/VenueConfigUpdater.h | ||||
|         src/libs/croncpp.h | ||||
|         src/Kafka_ProvUpdater.cpp src/Kafka_ProvUpdater.h | ||||
|         src/storage/storage_operataor.cpp src/storage/storage_operataor.h | ||||
|         src/storage/storage_sub_devices.cpp src/storage/storage_sub_devices.h | ||||
|         src/storage/storage_service_class.cpp src/storage/storage_service_class.h | ||||
|         src/RESTAPI/RESTAPI_sub_devices_list_handler.cpp src/RESTAPI/RESTAPI_sub_devices_list_handler.h src/RESTAPI/RESTAPI_sub_devices_handler.cpp src/RESTAPI/RESTAPI_sub_devices_handler.h src/RESTAPI/RESTAPI_service_class_list_handler.cpp src/RESTAPI/RESTAPI_service_class_list_handler.h src/RESTAPI/RESTAPI_service_class_handler.cpp src/RESTAPI/RESTAPI_service_class_handler.h src/RESTAPI/RESTAPI_operators_list_handler.cpp src/RESTAPI/RESTAPI_operators_list_handler.h src/RESTAPI/RESTAPI_operators_handler.cpp src/RESTAPI/RESTAPI_operators_handler.h src/storage/storage_op_contacts.cpp src/storage/storage_op_contacts.h src/storage/storage_op_locations.cpp src/storage/storage_op_locations.h src/RESTAPI/RESTAPI_op_contact_list_handler.cpp src/RESTAPI/RESTAPI_op_contact_list_handler.h src/RESTAPI/RESTAPI_op_contact_handler.cpp src/RESTAPI/RESTAPI_op_contact_handler.h src/RESTAPI/RESTAPI_op_location_list_handler.cpp src/RESTAPI/RESTAPI_op_location_list_handler.h src/RESTAPI/RESTAPI_op_location_handler.cpp src/RESTAPI/RESTAPI_op_location_handler.h src/ProvWebSocketClient.cpp src/ProvWebSocketClient.h src/Tasks/VenueRebooter.h src/Tasks/VenueUpgrade.h src/sdks/SDK_fms.cpp src/sdks/SDK_fms.h) | ||||
|         src/RESTAPI/RESTAPI_sub_devices_list_handler.cpp src/RESTAPI/RESTAPI_sub_devices_list_handler.h | ||||
|         src/RESTAPI/RESTAPI_sub_devices_handler.cpp src/RESTAPI/RESTAPI_sub_devices_handler.h | ||||
|         src/RESTAPI/RESTAPI_service_class_list_handler.cpp src/RESTAPI/RESTAPI_service_class_list_handler.h | ||||
|         src/RESTAPI/RESTAPI_service_class_handler.cpp src/RESTAPI/RESTAPI_service_class_handler.h | ||||
|         src/RESTAPI/RESTAPI_operators_list_handler.cpp src/RESTAPI/RESTAPI_operators_list_handler.h | ||||
|         src/RESTAPI/RESTAPI_operators_handler.cpp src/RESTAPI/RESTAPI_operators_handler.h | ||||
|         src/storage/storage_op_contacts.cpp src/storage/storage_op_contacts.h | ||||
|         src/storage/storage_op_locations.cpp src/storage/storage_op_locations.h | ||||
|         src/RESTAPI/RESTAPI_op_contact_list_handler.cpp src/RESTAPI/RESTAPI_op_contact_list_handler.h | ||||
|         src/RESTAPI/RESTAPI_op_contact_handler.cpp src/RESTAPI/RESTAPI_op_contact_handler.h | ||||
|         src/RESTAPI/RESTAPI_op_location_list_handler.cpp src/RESTAPI/RESTAPI_op_location_list_handler.h | ||||
|         src/RESTAPI/RESTAPI_op_location_handler.cpp src/RESTAPI/RESTAPI_op_location_handler.h | ||||
|         src/ProvWebSocketClient.cpp src/ProvWebSocketClient.h | ||||
|         src/Tasks/VenueRebooter.h src/Tasks/VenueUpgrade.h | ||||
|         src/sdks/SDK_fms.cpp src/sdks/SDK_fms.h | ||||
|         src/RESTAPI/RESTAPI_overrides_handler.cpp src/RESTAPI/RESTAPI_overrides_handler.h | ||||
|         src/storage/storage_glblraccounts.cpp src/storage/storage_glblraccounts.h | ||||
|         src/storage/storage_glblrcerts.cpp src/storage/storage_glblrcerts.h | ||||
|         src/RESTAPI/RESTAPI_openroaming_gr_list_acct_handler.cpp src/RESTAPI/RESTAPI_openroaming_gr_list_acct_handler.h | ||||
|         src/RESTAPI/RESTAPI_openroaming_gr_acct_handler.cpp src/RESTAPI/RESTAPI_openroaming_gr_acct_handler.h | ||||
|         src/RESTAPI/RESTAPI_openroaming_gr_list_certificates.cpp src/RESTAPI/RESTAPI_openroaming_gr_list_certificates.h | ||||
|         src/RESTAPI/RESTAPI_openroaming_gr_cert_handler.cpp src/RESTAPI/RESTAPI_openroaming_gr_cert_handler.h | ||||
|         src/RESTAPI/RESTAPI_openroaming_orion_list_acct_handler.cpp src/RESTAPI/RESTAPI_openroaming_orion_list_acct_handler.h | ||||
|         src/RESTAPI/RESTAPI_openroaming_orion_acct_handler.cpp src/RESTAPI/RESTAPI_openroaming_orion_acct_handler.h | ||||
|         src/storage/storage_orion_accounts.cpp src/storage/storage_orion_accounts.h | ||||
|         src/storage/storage_radius_endpoints.cpp | ||||
|         src/storage/storage_radius_endpoints.h | ||||
|         src/RESTAPI/RESTAPI_radiusendpoint_list_handler.cpp | ||||
|         src/RESTAPI/RESTAPI_radiusendpoint_list_handler.h | ||||
|         src/RESTAPI/RESTAPI_radius_endpoint_handler.cpp | ||||
|         src/RESTAPI/RESTAPI_radius_endpoint_handler.h | ||||
|         src/RadiusEndpointTypes/GlobalReach.cpp src/RadiusEndpointTypes/GlobalReach.h | ||||
|         src/RadiusEndpointTypes/OrionWifi.h | ||||
|         src/RadiusEndpointUpdater.cpp | ||||
|         src/RadiusEndpointUpdater.h | ||||
|         src/RadiusEndpointTypes/Radsec.cpp | ||||
|         src/RadiusEndpointTypes/Radsec.h | ||||
|         src/RadiusEndpointTypes/GenericRadius.cpp | ||||
|         src/RadiusEndpointTypes/GenericRadius.h | ||||
| ) | ||||
|  | ||||
| target_link_libraries(owprov PUBLIC | ||||
|         ${Poco_LIBRARIES} | ||||
|         ${MySQL_LIBRARIES} | ||||
|         ${ZLIB_LIBRARIES} | ||||
|         CppKafka::cppkafka | ||||
|         fmt::fmt | ||||
|         nlohmann_json_schema_validator) | ||||
|         resolv | ||||
|         fmt::fmt) | ||||
|  | ||||
|   | ||||
							
								
								
									
										243
									
								
								CONFIGURATION.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,243 @@ | ||||
| # OWPROV Configuration | ||||
| Here is the list of parameters you can configure in the `owprov.properties` file. | ||||
|  | ||||
| ## OWPROV Specific Parameters | ||||
| ### Default firmware management rules | ||||
| FMS is already integrated with OpenWifi. In order to allow it to upgrade devices automatically, you should | ||||
| set the following values. | ||||
| ```properties  | ||||
| firmware.updater.upgrade = <true/false> | ||||
| firmware.updater.releaseonly = <true/false> | ||||
| ``` | ||||
| #### firmware.updater.upgrade | ||||
| Should FMS attempt to upgrade devices by default. | ||||
|  | ||||
| #### firmware.updater.releaseonly | ||||
| Should only RC software be used during upgrades. | ||||
|  | ||||
| ### Google Map API Key | ||||
| To support geocoding help, you need to configuration the following in the configuration file. Geocoding is used | ||||
| when creating location and when reporting analytics. | ||||
| ```properties | ||||
| geocodeapi = google | ||||
| google.apikey = ******************************** | ||||
| ``` | ||||
|  | ||||
| ### IP to Country Parameters | ||||
| The controller has the ability to find the location of the IP of each Access Points. This uses an external IP location service. Currently, | ||||
| the controller supports 3 services. Please note that these services will require to obtain an API key or token, and these may cause you to incur | ||||
| additional fees. Here is the list of the services supported: | ||||
| - ip2location: ip2location.com | ||||
| - ipdata: ipdata.co | ||||
| - ipinfo: ipinfo.io | ||||
|  | ||||
| ```properties | ||||
| iptocountry.default = US | ||||
| iptocountry.provider = ipinfo | ||||
| #iptocountry.provider = ipdata | ||||
| #iptocountry.provider = ip2location | ||||
| iptocountry.ipinfo.token = | ||||
| iptocountry.ipdata.apikey = | ||||
| iptocountry.ip2location.apikey = | ||||
| ``` | ||||
|  | ||||
| #### iptocountry.default | ||||
| This is the country code to be used if no information can be found at one of the providers or you have not configured any of the providers. | ||||
|  | ||||
| #### iptocountry.provider | ||||
| You must select onf of the possible services and the fill the appropriate token or api key parameter. | ||||
|  | ||||
| ## Generic OpenWiFi SDK parameters | ||||
| ### REST API External parameters | ||||
| These are the parameters required for the configuration of the external facing REST API server | ||||
| ```properties | ||||
| openwifi.restapi.host.0.backlog = 100 | ||||
| openwifi.restapi.host.0.security = relaxed | ||||
| openwifi.restapi.host.0.rootca = $OWPROV_ROOT/certs/restapi-ca.pem | ||||
| openwifi.restapi.host.0.address = * | ||||
| openwifi.restapi.host.0.port = 16004 | ||||
| openwifi.restapi.host.0.cert = $OWPROV_ROOT/certs/restapi-cert.pem | ||||
| openwifi.restapi.host.0.key = $OWPROV_ROOT/certs/restapi-key.pem | ||||
| openwifi.restapi.host.0.key.password = mypassword | ||||
| ``` | ||||
|  | ||||
| #### openwifi.restapi.host.0.backlog | ||||
| This is the number of concurrent REST API calls that maybe be kept in the backlog for processing. That's a good rule of thumb. Never go above 500. | ||||
| #### openwifi.restapi.host.0.rootca | ||||
| This is the root file of your own certificate CA in `pem` format. | ||||
| #### openwifi.restapi.host.0.cert | ||||
| This is your own server certificate in `pem` format.. | ||||
| #### openwifi.restapi.host.0.key | ||||
| This is the private key associated with your own certificate in `pem` format. | ||||
| #### openwifi.restapi.host.0.address | ||||
| Leve this a `*` in the case you want to bind to all interfaces on your gateway host or select the address of a single interface. | ||||
| #### openwifi.restapi.host.0.port | ||||
| The port on which the REST API server is listening. By default, this is 16002. | ||||
| #### openwifi.restapi.host.0.security | ||||
| Leave this as `relaxed` for now for devices. | ||||
| #### openwifi.restapi.host.0.key.password | ||||
| If you key file uses a password, please enter it here. | ||||
|  | ||||
| ### REST API Intra microservice parameters | ||||
| The following parameters describe the configuration for the inter-microservice HTTP server. You may use the same certificate/key | ||||
| you are using for your extenral server or another certificate. | ||||
| ```properties | ||||
| openwifi.internal.restapi.host.0.backlog = 100 | ||||
| openwifi.internal.restapi.host.0.security = relaxed | ||||
| openwifi.internal.restapi.host.0.rootca = $OWPROV_ROOT/certs/restapi-ca.pem | ||||
| openwifi.internal.restapi.host.0.address = * | ||||
| openwifi.internal.restapi.host.0.port = 17004 | ||||
| openwifi.internal.restapi.host.0.cert = $OWPROV_ROOT/certs/restapi-cert.pem | ||||
| openwifi.internal.restapi.host.0.key = $OWPROV_ROOT/certs/restapi-key.pem | ||||
| openwifi.internal.restapi.host.0.key.password = mypassword | ||||
| ``` | ||||
|  | ||||
| #### openwifi.internal.host.0.backlog | ||||
| This is the number of concurrent REST API calls that maybe be kept in the backlog for processing. That's a good rule of thumb. Never go above 500. | ||||
| #### openwifi.internal.host.0.rootca | ||||
| This is the root file of your own certificate CA in `pem` format. | ||||
| #### openwifi.internal.host.0.cert | ||||
| This is your own server certificate in `pem` format.. | ||||
| #### openwifi.internal.host.0.key | ||||
| This is the private key associated with your own certificate in `pem` format. | ||||
| #### openwifi.internal.host.0.address | ||||
| Leve this a `*` in the case you want to bind to all interfaces on your gateway host or select the address of a single interface. | ||||
| #### openwifi.internal.host.0.port | ||||
| The port on which the REST API server is listening. By default, this is 17002. | ||||
| #### openwifi.internal.host.0.security | ||||
| Leave this as `relaxed` for now for devices. | ||||
| #### openwifi.internal.host.0.key.password | ||||
| If you key file uses a password, please enter it here. | ||||
|  | ||||
| ### Microservice information | ||||
| These are different Microservie parameters. Following is a brief explanation. | ||||
| ```properties | ||||
| openwifi.service.key = $OWPROV_ROOT/certs/restapi-key.pem | ||||
| openwifi.service.key.password = mypassword | ||||
| openwifi.system.data = $OWPROV_ROOT/data | ||||
| openwifi.system.uri.private = https://localhost:17004 | ||||
| openwifi.system.uri.public = https://ucentral.example.com:16004 | ||||
| openwifi.system.uri.ui = https://provisionins-ui.example.com | ||||
| openwifi.security.restapi.disable = false | ||||
| openwifi.system.commandchannel = /tmp/app.ucentralprov | ||||
| openwifi.autoprovisioning = true | ||||
| ``` | ||||
| #### openwifi.service.key | ||||
| From time to time, the microservice must encrypt information. This is the key it should use. You may use the | ||||
| same keey as you RESTAPI or your server. | ||||
| #### openwifi.service.key.password | ||||
| The password for the `openwifi.service.key` | ||||
| #### openwifi.system.data | ||||
| The location of system data. This path must exist. | ||||
| #### openwifi.system.uri.private | ||||
| The URI to reach the controller on the internal port. | ||||
| #### openwifi.system.uri.public | ||||
| The URI to reach the controller from the outside world. | ||||
| #### openwifi.system.uri.ui | ||||
| The URI of the UI to manage this service | ||||
| #### openwifi.security.restapi.disable | ||||
| This allows to disable security for internal and external API calls. This should only be used if the controller | ||||
| sits behind an application load balancer that will actually do TLS. Setting this to `true` disables security. | ||||
| #### openwifi.system.commandchannel | ||||
| The UNIX socket command channel used by this service. | ||||
| #### openwifi.autoprovisioning | ||||
| Allow unknown devices to be provisioned by the system. | ||||
|  | ||||
| ### ALB Support | ||||
| In order to support an application load balancer health check verification, your need to provide the following parameters. | ||||
| ```properties | ||||
| alb.enable = true | ||||
| alb.port = 16104 | ||||
| ``` | ||||
|  | ||||
| ### Kafka | ||||
| The controller use Kafka, like all the other microservices. You must configure the kafka section in order for the | ||||
| system to work. | ||||
| ```properties | ||||
| openwifi.kafka.group.id = provisioning | ||||
| openwifi.kafka.client.id = provisioning1 | ||||
| openwifi.kafka.enable = true | ||||
| openwifi.kafka.brokerlist = my_Kafka.example.com:9092 | ||||
| openwifi.kafka.auto.commit = false | ||||
| openwifi.kafka.queue.buffering.max.ms = 50 | ||||
| ``` | ||||
|  | ||||
| ### openwifi.kafka.group.id | ||||
| The group ID is a single word that should identify the type of service tuning. In the case `provisioning` | ||||
| ### openwifi.kafka.client.id | ||||
| The client ID is a single service within that group ID. Each participant must have a unique client ID. | ||||
| ### openwifi.kafka.enable | ||||
| Kafka should always be enabled. | ||||
| ### openwifi.kafka.brokerlist | ||||
| The list of servers where your Kafka server is running. Comma separated. | ||||
| ### openwifi.kafka.auto.commit | ||||
| Auto commit flag in Kafka. Leave as `false`. | ||||
| ### openwifi.kafka.queue.buffering.max.ms | ||||
| Kafka buffering. Leave as `50`. | ||||
| ### Kafka security | ||||
| If you intend to use SSL, you should look into Kafka Connect and specify the certificates below. | ||||
| ```properties | ||||
| penwifi.kafka.ssl.ca.location = | ||||
| openwifi.kafka.ssl.certificate.location = | ||||
| openwifi.kafka.ssl.key.location = | ||||
| openwifi.kafka.ssl.key.password = | ||||
| ``` | ||||
|  | ||||
| ### DB Type | ||||
| The controller supports 3 types of Database. SQLite should only be used for sites with less than 100 APs or for testing in the lab. | ||||
| In order to select which database to use, you must set the `storage.type` value to sqlite, postgresql, or mysql. | ||||
|  | ||||
| ```properties | ||||
| storage.type = sqlite | ||||
| #storage.type = postgresql | ||||
| #storage.type = mysql | ||||
| ``` | ||||
|  | ||||
| ### Storage SQLite parameters | ||||
| Additional parameters to set for SQLite. The only important one is `storage.type.sqlite.db` which is the database name on disk. | ||||
| ```properties | ||||
| storage.type.sqlite.db = provisioning.db | ||||
| storage.type.sqlite.idletime = 120 | ||||
| storage.type.sqlite.maxsessions = 128 | ||||
| ``` | ||||
|  | ||||
| ### Storage Postgres | ||||
| Additional parameters to set if you select Postgres for your database. You must specify `host`, `username`, `password`, | ||||
| `database`, and `port`. | ||||
| ```properties | ||||
| storage.type.postgresql.maxsessions = 64 | ||||
| storage.type.postgresql.idletime = 60 | ||||
| storage.type.postgresql.host = localhost | ||||
| storage.type.postgresql.username = provisioning | ||||
| storage.type.postgresql.password = provisioning | ||||
| storage.type.postgresql.database = provisioning | ||||
| storage.type.postgresql.port = 5432 | ||||
| storage.type.postgresql.connectiontimeout = 60 | ||||
| ``` | ||||
|  | ||||
| ### Storage MySQL/MariaDB | ||||
| Additional parameters to set if you select mysql for your database. You must specify `host`, `username`, `password`, | ||||
| `database`, and `port`. | ||||
| ```properties | ||||
| storage.type.mysql.maxsessions = 64 | ||||
| storage.type.mysql.idletime = 60 | ||||
| storage.type.mysql.host = localhost | ||||
| storage.type.postgresql.username = provisioning | ||||
| storage.type.postgresql.password = provisioning | ||||
| storage.type.postgresql.database = provisioning | ||||
| storage.type.mysql.port = 3306 | ||||
| storage.type.mysql.connectiontimeout = 60 | ||||
| ``` | ||||
|  | ||||
| ### Logging Parameters | ||||
| The microservice provides extensive logging. If you would like to keep logging on disk, set the `logging.type = file`. If you only want | ||||
| console logging, `set logging.type = console`. When selecting file, `logging.path` must exist. `logging.level` sets the | ||||
| basic logging level for the entire controller. `logging.websocket` disables WebSocket logging. | ||||
|  | ||||
| ```properties | ||||
| logging.type = file | ||||
| logging.path = $OWPROV_ROOT/logs | ||||
| logging.level = information | ||||
| logging.asynch = true | ||||
| logging.websocket = false | ||||
| ``` | ||||
							
								
								
									
										38
									
								
								CONTRIBUTING.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,38 @@ | ||||
| # How to Contribute | ||||
|  | ||||
| We'd love to accept your patches and contributions to this project. There are | ||||
| just a few small guidelines you need to follow. | ||||
|  | ||||
| ## Version of C++ | ||||
| This project is based on the C++17 standard and compiles as-is on most platforms  | ||||
| using either clang or g++. Do not use C++21 or C++23 features for now. Some core  | ||||
| libraries used in this project do not support C++21 or C++23 yet. | ||||
|  | ||||
| ## Variable Naming | ||||
| Naming of pretty much anything uses Pascal naming. Longer explicit names using casing.  | ||||
| Member variable naming adds a `_` at the end of the vars. Try to | ||||
| keep this standard going. Sometimes you must override a base class function and then of course | ||||
| you need to follow the base class. | ||||
|  | ||||
| ## This is a cmake project | ||||
| This is a cmake project, and you need to adhere to the cmake rules. If you need | ||||
| to add a package to the CMakeList, you need to ensure that the package is available | ||||
| on all required platforms and compiles. Remember that this project runs on Linux, OS X,  | ||||
| and the Raspberry PI. | ||||
|  | ||||
| ## Licensed packages | ||||
| When adding a package, you must also state the licensing for the package. MIT, BSD, Apache licenses | ||||
| are acceptable. No commercial licenses are allowed.  | ||||
|  | ||||
| ## clang formatting | ||||
| Please format your code using the included `.clang-format` file included in the project. | ||||
|  | ||||
| ```bash | ||||
| clang-format -i --style=<project root>/.clang-format myfile.cpp | ||||
| ``` | ||||
|  | ||||
| ## Pull Requests | ||||
| All submissions, including submissions by project members, require review. We | ||||
| accept GitHub pull requests. Please create a branch with the Jira name for addressing the issue you are fixing or the  | ||||
| feature you are implementing. | ||||
| Create a pull-request from the branch into master.  | ||||
							
								
								
									
										57
									
								
								Dockerfile
									
									
									
									
									
								
							
							
						
						| @@ -1,8 +1,7 @@ | ||||
| ARG DEBIAN_VERSION=11.4-slim | ||||
| ARG POCO_VERSION=poco-tip-v1 | ||||
| ARG FMTLIB_VERSION=9.0.0 | ||||
| ARG DEBIAN_VERSION=11.5-slim | ||||
| ARG POCO_VERSION=poco-tip-v2 | ||||
| ARG CPPKAFKA_VERSION=tip-v1 | ||||
| ARG JSON_VALIDATOR_VERSION=2.1.0 | ||||
| ARG VALIJASON_VERSION=tip-v1 | ||||
|  | ||||
| FROM debian:$DEBIAN_VERSION AS build-base | ||||
|  | ||||
| @@ -10,14 +9,15 @@ RUN apt-get update && apt-get install --no-install-recommends -y \ | ||||
|     make cmake g++ git \ | ||||
|     libpq-dev libmariadb-dev libmariadbclient-dev-compat \ | ||||
|     librdkafka-dev libboost-all-dev libssl-dev \ | ||||
|     zlib1g-dev nlohmann-json3-dev ca-certificates libcurl4-openssl-dev | ||||
|     zlib1g-dev nlohmann-json3-dev ca-certificates libcurl4-openssl-dev libfmt-dev | ||||
|  | ||||
| FROM build-base AS poco-build | ||||
|  | ||||
| ARG POCO_VERSION | ||||
|  | ||||
| ADD https://api.github.com/repos/AriliaWireless/poco/git/refs/tags/${POCO_VERSION} version.json | ||||
| RUN git clone https://github.com/AriliaWireless/poco --branch ${POCO_VERSION} /poco | ||||
| ADD https://api.github.com/repos/Telecominfraproject/wlan-cloud-lib-poco/git/refs/tags/${POCO_VERSION} version.json | ||||
| RUN git clone https://github.com/Telecominfraproject/wlan-cloud-lib-poco --branch ${POCO_VERSION} /poco | ||||
|  | ||||
|  | ||||
| WORKDIR /poco | ||||
| RUN mkdir cmake-build | ||||
| @@ -26,26 +26,12 @@ RUN cmake .. | ||||
| RUN cmake --build . --config Release -j8 | ||||
| RUN cmake --build . --target install | ||||
|  | ||||
| FROM build-base AS fmtlib-build | ||||
|  | ||||
| ARG FMTLIB_VERSION | ||||
|  | ||||
| ADD https://api.github.com/repos/fmtlib/fmt/git/refs/tags/${FMTLIB_VERSION} version.json | ||||
| RUN git clone https://github.com/fmtlib/fmt --branch ${FMTLIB_VERSION} /fmtlib | ||||
|  | ||||
| WORKDIR /fmtlib | ||||
| RUN mkdir cmake-build | ||||
| WORKDIR cmake-build | ||||
| RUN cmake .. | ||||
| RUN make | ||||
| RUN make install | ||||
|  | ||||
| FROM build-base AS cppkafka-build | ||||
|  | ||||
| ARG CPPKAFKA_VERSION | ||||
|  | ||||
| ADD https://api.github.com/repos/AriliaWireless/cppkafka/git/refs/tags/${CPPKAFKA_VERSION} version.json | ||||
| RUN git clone https://github.com/AriliaWireless/cppkafka --branch ${CPPKAFKA_VERSION} /cppkafka | ||||
| ADD https://api.github.com/repos/Telecominfraproject/wlan-cloud-lib-cppkafka/git/refs/tags/${CPPKAFKA_VERSION} version.json | ||||
| RUN git clone https://github.com/Telecominfraproject/wlan-cloud-lib-cppkafka --branch ${CPPKAFKA_VERSION} /cppkafka | ||||
|  | ||||
| WORKDIR /cppkafka | ||||
| RUN mkdir cmake-build | ||||
| @@ -54,19 +40,19 @@ RUN cmake .. | ||||
| RUN cmake --build . --config Release -j8 | ||||
| RUN cmake --build . --target install | ||||
|  | ||||
| FROM build-base AS json-schema-validator-build | ||||
| FROM build-base AS valijson-build | ||||
|  | ||||
| ARG JSON_VALIDATOR_VERSION | ||||
| ARG VALIJASON_VERSION | ||||
|  | ||||
| ADD https://api.github.com/repos/pboettch/json-schema-validator/git/refs/tags/${JSON_VALIDATOR_VERSION} version.json | ||||
| RUN git clone https://github.com/pboettch/json-schema-validator --branch ${JSON_VALIDATOR_VERSION} /json-schema-validator | ||||
| ADD https://api.github.com/repos/Telecominfraproject/wlan-cloud-lib-valijson/git/refs/tags/${VALIJASON_VERSION} version.json | ||||
| RUN git clone https://github.com/Telecominfraproject/wlan-cloud-lib-valijson --branch ${VALIJASON_VERSION} /valijson | ||||
|  | ||||
| WORKDIR /json-schema-validator | ||||
| WORKDIR /valijson | ||||
| RUN mkdir cmake-build | ||||
| WORKDIR cmake-build | ||||
| RUN cmake .. | ||||
| RUN make | ||||
| RUN make install | ||||
| RUN cmake --build . --config Release -j8 | ||||
| RUN cmake --build . --target install | ||||
|  | ||||
| FROM build-base AS owprov-build | ||||
|  | ||||
| @@ -79,10 +65,7 @@ COPY --from=poco-build /usr/local/include /usr/local/include | ||||
| COPY --from=poco-build /usr/local/lib /usr/local/lib | ||||
| COPY --from=cppkafka-build /usr/local/include /usr/local/include | ||||
| COPY --from=cppkafka-build /usr/local/lib /usr/local/lib | ||||
| COPY --from=json-schema-validator-build /usr/local/include /usr/local/include | ||||
| COPY --from=json-schema-validator-build /usr/local/lib /usr/local/lib | ||||
| COPY --from=fmtlib-build /usr/local/include /usr/local/include | ||||
| COPY --from=fmtlib-build /usr/local/lib /usr/local/lib | ||||
| COPY --from=valijson-build /usr/local/include /usr/local/include | ||||
|  | ||||
| WORKDIR /owprov | ||||
| RUN mkdir cmake-build | ||||
| @@ -104,7 +87,7 @@ RUN mkdir -p "$OWPROV_ROOT" "$OWPROV_CONFIG" && \ | ||||
|  | ||||
| RUN apt-get update && apt-get install --no-install-recommends -y \ | ||||
|     librdkafka++1 gosu gettext ca-certificates bash jq curl wget \ | ||||
|     libmariadb-dev-compat libpq5 unixodbc postgresql-client | ||||
|     libmariadb-dev-compat libpq5 postgresql-client libfmt7 | ||||
|  | ||||
| COPY readiness_check /readiness_check | ||||
| COPY test_scripts/curl/cli /cli | ||||
| @@ -116,8 +99,8 @@ RUN wget https://raw.githubusercontent.com/Telecominfraproject/wlan-cloud-ucentr | ||||
|     -O /usr/local/share/ca-certificates/restapi-ca-selfsigned.crt | ||||
|  | ||||
| COPY --from=owprov-build /owprov/cmake-build/owprov /openwifi/owprov | ||||
| COPY --from=cppkafka-build /cppkafka/cmake-build/src/lib/* /usr/local/lib | ||||
| COPY --from=poco-build /poco/cmake-build/lib/* /usr/local/lib | ||||
| COPY --from=cppkafka-build /cppkafka/cmake-build/src/lib/* /usr/local/lib/ | ||||
| COPY --from=poco-build /poco/cmake-build/lib/* /usr/local/lib/ | ||||
|  | ||||
| RUN ldconfig | ||||
|  | ||||
|   | ||||
							
								
								
									
										113
									
								
								README.md
									
									
									
									
									
								
							
							
						
						| @@ -1,11 +1,23 @@ | ||||
| # OpenWiFi Provisioning | ||||
| <p align="center"> | ||||
|     <img src="images/project/logo.svg" width="200"/> | ||||
| </p> | ||||
|  | ||||
| ## Build from source. | ||||
| You need: | ||||
| - https://github.com/pboettch/json-schema-validator.git | ||||
| - https://github.com/nlohmann/json.git | ||||
| # OpenWiFi Provisioning Service (OWPROV) | ||||
| ## What is it? | ||||
| The OWPROV is a service for the TIP OpenWiFi CloudSDK (OWSDK). | ||||
| OWPROV manages groups of access points through the use of entities and vanues. OWPROV, like all other OWSDK microservices, is | ||||
| defined using an OpenAPI definition and uses the ucentral communication protocol to interact with Access Points. To use | ||||
| the OWPROV, you either need to [build it](#building) or use the [Docker version](#docker). | ||||
|  | ||||
| build and install them. | ||||
| ## OpenAPI | ||||
| You may get static page with OpenAPI docs generated from the definition on [GitHub Page](https://telecominfraproject.github.io/wlan-cloud-owprov/). | ||||
| Also, you may use [Swagger UI](https://petstore.swagger.io/#/) with OpenAPI definition file raw link (i.e. [latest version file](https://raw.githubusercontent.com/Telecominfraproject/wlan-cloud-owprov/main/openapi/owprov.yaml)) to get interactive docs page. | ||||
|  | ||||
| ## Building | ||||
| To build the microservice from source, please follow the instructions in [here](./BUILDING.md) | ||||
|  | ||||
| ## Docker | ||||
| To use the CLoudSDK deployment please follow [here](https://github.com/Telecominfraproject/wlan-cloud-ucentral-deploy) | ||||
|  | ||||
| ## Root entity | ||||
| It's UUID value is 0000-0000-0000. Its parent entity must be empty. | ||||
| @@ -46,24 +58,77 @@ You may modify the following fields in the POST | ||||
| - You may include an array of devices UUIDs | ||||
| - Topology and design cannot be set | ||||
|  | ||||
| ## Geocoding | ||||
| To support geocoding help, you need to configuration the following in the configuration file. Geocoding is used | ||||
| when creating location and when reporting analytics. | ||||
| ```  | ||||
| geocodeapi = google | ||||
| google.apikey = ********************************** | ||||
| #### Expected directory layout | ||||
| From the directory where your cloned source is, you will need to create the `certs`, `logs`, and `uploads` directories. | ||||
| ```bash | ||||
| mkdir certs | ||||
| mkdir certs/cas | ||||
| mkdir logs | ||||
| mkdir uploads | ||||
| ``` | ||||
| Currently, only google Geocoding is supported. Additional methods may be added in the future. | ||||
|  | ||||
| ## Default firmware management rules | ||||
| FMS is already integrated with OpenWifi. In order to allow it to upgrade devices automatically, you should  | ||||
| set the following values. | ||||
| ```  | ||||
| firmware.updater.upgrade = <true/false> | ||||
| firmware.updater.releaseonly = <true/false> | ||||
| You should now have the following: | ||||
| ```text | ||||
| --+-- certs | ||||
|   |   +--- cas | ||||
|   +-- cmake | ||||
|   +-- cmake-build | ||||
|   +-- logs | ||||
|   +-- src | ||||
|   +-- test_scripts | ||||
|   +-- openapi | ||||
|   +-- uploads | ||||
|   +-- owsec.properties | ||||
| ``` | ||||
| ### firmware.updater.upgrade | ||||
| Should FMS attempt to upgrade devices by default. | ||||
|  | ||||
| ### firmware.updater.releaseonly | ||||
| Should only RC software be used during upgrades. | ||||
| ### Certificate | ||||
| The OWFMS uses a certificate to provide security for the REST API Certificate to secure the Northbound API. | ||||
|  | ||||
| #### The `certs` directory | ||||
| For all deployments, you will need the following `certs` directory, populated with the proper files. | ||||
|  | ||||
| ```text | ||||
| certs ---+--- restapi-ca.pem | ||||
|          +--- restapi-cert.pem | ||||
|          +--- restapi-key.pem | ||||
| ``` | ||||
|  | ||||
| ## Firewall Considerations | ||||
| | Port  | Description                                    | Configurable | | ||||
| |:------|:-----------------------------------------------|:------------:| | ||||
| | 16004 | Default port for REST API Access to the OWPROV |     yes      | | ||||
|  | ||||
| ### Environment variables | ||||
| The following environment variables should be set from the root directory of the service. They tell the OWGW process where to find | ||||
| the configuration and the root directory. | ||||
| ```bash | ||||
| export OWGW_ROOT=`pwd` | ||||
| export OWGW_CONFIG=`pwd` | ||||
| ``` | ||||
| You can run the shell script `set_env.sh` from the microservice root. | ||||
|  | ||||
| ### OWPROV Service Configuration | ||||
| The configuration is kept in a file called `owprov.properties`. To understand the content of this file, | ||||
| please look [here](https://github.com/Telecominfraproject/wlan-cloud-owprov/blob/main/CONFIGURATION.md) | ||||
|  | ||||
| ## Kafka topics | ||||
| Toe read more about Kafka, follow the [document](https://github.com/Telecominfraproject/wlan-cloud-ucentralgw/blob/main/KAFKA.md) | ||||
|  | ||||
| ## Contributions | ||||
| We need more contributors. Should you wish to contribute, | ||||
| please follow the [contributions](https://github.com/Telecominfraproject/wlan-cloud-ucentralgw/blob/master/CONTRIBUTING.md) document. | ||||
|  | ||||
| ## Pull Requests | ||||
| Please create a branch with the Jira addressing the issue you are fixing or the feature you are implementing. | ||||
| Create a pull-request from the branch into master. | ||||
|  | ||||
| ## Additional OWSDK Microservices | ||||
| Here is a list of additional OWSDK microservices | ||||
| | Name | Description | Link | OpenAPI | | ||||
| | :--- | :--- | :---: | :---: | | ||||
| | OWSEC | Security Service | [here](https://github.com/Telecominfraproject/wlan-cloud-ucentralsec) | [here](https://github.com/Telecominfraproject/wlan-cloud-ucentralsec/blob/main/openpapi/owsec.yaml) | | ||||
| | OWGW | Controller Service | [here](https://github.com/Telecominfraproject/wlan-cloud-ucentralgw) | [here](https://github.com/Telecominfraproject/wlan-cloud-ucentralgw/blob/master/openapi/owgw.yaml) | | ||||
| | OWFMS | Firmware Management Service | [here](https://github.com/Telecominfraproject/wlan-cloud-ucentralfms) | [here](https://github.com/Telecominfraproject/wlan-cloud-ucentralfms/blob/main/openapi/owfms.yaml) | | ||||
| | OWPROV | Provisioning Service | [here](https://github.com/Telecominfraproject/wlan-cloud-owprov) | [here](https://github.com/Telecominfraproject/wlan-cloud-owprov/blob/main/openapi/owprov.yaml) | | ||||
| | OWANALYTICS | Analytics Service | [here](https://github.com/Telecominfraproject/wlan-cloud-analytics) | [here](https://github.com/Telecominfraproject/wlan-cloud-analytics/blob/main/openapi/owanalytics.yaml) | | ||||
| | OWSUB | Subscriber Service | [here](https://github.com/Telecominfraproject/wlan-cloud-userportal) | [here](https://github.com/Telecominfraproject/wlan-cloud-userportal/blob/main/openapi/userportal.yaml) | | ||||
|  | ||||
|   | ||||
							
								
								
									
										84
									
								
								config-samples/OpenRo.am Test.mobileconfig
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,84 @@ | ||||
| <?xml version="1.0" encoding="UTF-8"?> | ||||
| <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> | ||||
| <plist version="1.0"> | ||||
| <dict> | ||||
| 	<key>PayloadContent</key> | ||||
| 	<array> | ||||
| 		<dict> | ||||
| 			<key>AutoJoin</key> | ||||
| 			<true/> | ||||
| 			<key>CaptiveBypass</key> | ||||
| 			<false/> | ||||
| 			<key>DisableAssociationMACRandomization</key> | ||||
| 			<false/> | ||||
| 			<key>DisplayedOperatorName</key> | ||||
| 			<string>OpenRo.am</string> | ||||
| 			<key>DomainName</key> | ||||
| 			<string>openro.am</string> | ||||
| 			<key>EAPClientConfiguration</key> | ||||
| 			<dict> | ||||
| 				<key>AcceptEAPTypes</key> | ||||
| 				<array> | ||||
| 					<integer>21</integer> | ||||
| 				</array> | ||||
| 				<key>OuterIdentity</key> | ||||
| 				<string>anonymous@openro.am</string> | ||||
| 				<key>TLSMaximumVersion</key> | ||||
| 				<string>1.2</string> | ||||
| 				<key>TLSMinimumVersion</key> | ||||
| 				<string>1.2</string> | ||||
| 				<key>TTLSInnerAuthentication</key> | ||||
| 				<string>MSCHAPv2</string> | ||||
| 				<key>UserName</key> | ||||
| 				<string>420a5371-47d4-4d1d-b234-d17be4e54bb3@openro.am</string> | ||||
| 				<key>UserPassword</key> | ||||
| 				<string>XaHBCFhgGxi-mCK9XXdQ8</string> | ||||
| 			</dict> | ||||
| 			<key>EncryptionType</key> | ||||
| 			<string>WPA2</string> | ||||
| 			<key>HIDDEN_NETWORK</key> | ||||
| 			<false/> | ||||
| 			<key>IsHotspot</key> | ||||
| 			<true/> | ||||
| 			<key>NAIRealmNames</key> | ||||
| 			<array> | ||||
| 				<string>openro.am</string> | ||||
| 			</array> | ||||
| 			<key>PayloadDescription</key> | ||||
| 			<string>Configures Wi-Fi settings</string> | ||||
| 			<key>PayloadDisplayName</key> | ||||
| 			<string>Wi-Fi</string> | ||||
| 			<key>PayloadIdentifier</key> | ||||
| 			<string>com.apple.wifi.managed.12788EED-2E0C-4370-9411-4EEFC8D9ABB0</string> | ||||
| 			<key>PayloadType</key> | ||||
| 			<string>com.apple.wifi.managed</string> | ||||
| 			<key>PayloadUUID</key> | ||||
| 			<string>12788EED-2E0C-4370-9411-4EEFC8D9ABB0</string> | ||||
| 			<key>PayloadVersion</key> | ||||
| 			<integer>1</integer> | ||||
| 			<key>ProxyType</key> | ||||
| 			<string>None</string> | ||||
| 			<key>RoamingConsortiumOIs</key> | ||||
| 			<array> | ||||
| 				<string>5A03BA0000</string> | ||||
| 			</array> | ||||
| 			<key>ServiceProviderRoamingEnabled</key> | ||||
| 			<true/> | ||||
| 		</dict> | ||||
| 	</array> | ||||
| 	<key>PayloadDisplayName</key> | ||||
| 	<string>OpenRo.am Test</string> | ||||
| 	<key>PayloadIdentifier</key> | ||||
| 	<string>openroam.44A21054-2F3F-437F-822A-C2F6766A2A23</string> | ||||
| 	<key>PayloadOrganization</key> | ||||
| 	<string>OpenRo.am</string> | ||||
| 	<key>PayloadRemovalDisallowed</key> | ||||
| 	<false/> | ||||
| 	<key>PayloadType</key> | ||||
| 	<string>Configuration</string> | ||||
| 	<key>PayloadUUID</key> | ||||
| 	<string>1D460B0F-9311-4FD2-A75D-BADA866BC31C</string> | ||||
| 	<key>PayloadVersion</key> | ||||
| 	<integer>1</integer> | ||||
| </dict> | ||||
| </plist> | ||||
| @@ -42,6 +42,7 @@ if [[ "$TEMPLATE_CONFIG" = 'true' ]]; then | ||||
|   STORAGE_TYPE_MYSQL_PASSWORD=${STORAGE_TYPE_MYSQL_PASSWORD:-"owprov"} \ | ||||
|   STORAGE_TYPE_MYSQL_DATABASE=${STORAGE_TYPE_MYSQL_DATABASE:-"owprov"} \ | ||||
|   STORAGE_TYPE_MYSQL_PORT=${STORAGE_TYPE_MYSQL_PORT:-"3306"} \ | ||||
|   RRM_PROVIDERS=${RRM_PROVIDERS:-"owrrm"} \ | ||||
|   envsubst < /owprov.properties.tmpl > $OWPROV_CONFIG/owprov.properties | ||||
| fi | ||||
|  | ||||
|   | ||||
| @@ -9,7 +9,7 @@ fullnameOverride: "" | ||||
| images: | ||||
|   owprov: | ||||
|     repository: tip-tip-wlan-cloud-ucentral.jfrog.io/owprov | ||||
|     tag: main | ||||
|     tag: v3.2.1 | ||||
|     pullPolicy: Always | ||||
| #    regcred: | ||||
| #      registry: tip-tip-wlan-cloud-ucentral.jfrog.io | ||||
|   | ||||
							
								
								
									
										
											BIN
										
									
								
								images/device_types/cig_wf160d.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 104 KiB | 
							
								
								
									
										
											BIN
										
									
								
								images/device_types/cig_wf188.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 80 KiB | 
							
								
								
									
										
											BIN
										
									
								
								images/device_types/cig_wf188n.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 80 KiB | 
							
								
								
									
										
											BIN
										
									
								
								images/device_types/cig_wf194c.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 75 KiB | 
							
								
								
									
										
											BIN
										
									
								
								images/device_types/cig_wf194c4.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 75 KiB | 
							
								
								
									
										
											BIN
										
									
								
								images/device_types/cig_wf808.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 218 KiB | 
							
								
								
									
										
											BIN
										
									
								
								images/device_types/cig_wf809.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 158 KiB | 
							
								
								
									
										
											BIN
										
									
								
								images/device_types/edgecore_eap101.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 140 KiB | 
							
								
								
									
										
											BIN
										
									
								
								images/device_types/edgecore_eap102.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 121 KiB | 
							
								
								
									
										
											BIN
										
									
								
								images/device_types/edgecore_ecs4100-12ph.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 44 KiB | 
							
								
								
									
										
											BIN
										
									
								
								images/device_types/edgecore_ecw5211.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 192 KiB | 
							
								
								
									
										
											BIN
										
									
								
								images/device_types/edgecore_ecw5410.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 197 KiB | 
							
								
								
									
										
											BIN
										
									
								
								images/device_types/edgecore_oap100.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 50 KiB | 
							
								
								
									
										
											BIN
										
									
								
								images/device_types/edgecore_spw2ac1200-lan-poe.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 59 KiB | 
							
								
								
									
										
											BIN
										
									
								
								images/device_types/edgecore_spw2ac1200.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 59 KiB | 
							
								
								
									
										
											BIN
										
									
								
								images/device_types/edgecore_ssw2ac2600.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 51 KiB | 
							
								
								
									
										
											BIN
										
									
								
								images/device_types/hfcl_ion4.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 72 KiB | 
							
								
								
									
										
											BIN
										
									
								
								images/device_types/hfcl_ion4.yml.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 72 KiB | 
							
								
								
									
										
											BIN
										
									
								
								images/device_types/indio_um-305ac.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 34 KiB | 
							
								
								
									
										
											BIN
										
									
								
								images/device_types/linksys_e8450-ubi.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 98 KiB | 
							
								
								
									
										
											BIN
										
									
								
								images/device_types/linksys_ea6350-v4.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 89 KiB | 
							
								
								
									
										
											BIN
										
									
								
								images/device_types/linksys_ea6350.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 89 KiB | 
							
								
								
									
										
											BIN
										
									
								
								images/device_types/linksys_ea8300.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 204 KiB | 
							
								
								
									
										
											BIN
										
									
								
								images/device_types/tp-link_ec420-g1.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 159 KiB | 
							
								
								
									
										
											BIN
										
									
								
								images/device_types/tplink_ec420.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 159 KiB | 
							
								
								
									
										
											BIN
										
									
								
								images/device_types/tplink_ex227.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 103 KiB | 
							
								
								
									
										
											BIN
										
									
								
								images/device_types/tplink_ex228.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 103 KiB | 
							
								
								
									
										
											BIN
										
									
								
								images/device_types/tplink_ex447.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 103 KiB | 
							
								
								
									
										
											BIN
										
									
								
								images/device_types/wallys_dr40x9.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 59 KiB | 
							
								
								
									
										
											BIN
										
									
								
								images/device_types/wallys_dr6018.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 80 KiB | 
							
								
								
									
										
											BIN
										
									
								
								images/device_types/wallys_dr6018_v4.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 80 KiB | 
							
								
								
									
										
											BIN
										
									
								
								images/project/logo.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 4.8 KiB | 
							
								
								
									
										165
									
								
								images/project/logo.svg
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,165 @@ | ||||
| <?xml version="1.0" encoding="utf-8"?> | ||||
| <!-- Generator: Adobe Illustrator 24.2.3, SVG Export Plug-In . SVG Version: 6.00 Build 0)  --> | ||||
| <svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" | ||||
| 	 viewBox="0 0 141.5 185.6" style="enable-background:new 0 0 141.5 185.6;" xml:space="preserve"> | ||||
| <style type="text/css"> | ||||
| 	.st0{fill:#414141;} | ||||
| 	.st1{fill:#FFFFFF;} | ||||
| 	.st2{fill:#FED206;} | ||||
| 	.st3{fill:#EB6F53;} | ||||
| 	.st4{fill:#3BA9B6;} | ||||
| </style> | ||||
| <g> | ||||
| 	<g> | ||||
| 		<path class="st0" d="M120.7,183.9H21.5c-10.8,0-19.5-8.7-19.5-19.5V20.5c0-10.8,8.7-19.5,19.5-19.5h99.2 | ||||
| 			c10.8,0,19.5,8.7,19.5,19.5v143.9C140.2,175.2,131.5,183.9,120.7,183.9z"/> | ||||
| 		<g> | ||||
| 			<g> | ||||
| 				<g> | ||||
| 					<path class="st1" d="M46.3,166.2v-3.4h-1.2v-0.6h3.1v0.6H47v3.4H46.3z"/> | ||||
| 				</g> | ||||
| 				<g> | ||||
| 					<path class="st1" d="M49,166.2v-4h2.7v0.6h-2v1h2v0.6h-2v1.1h2v0.6H49z"/> | ||||
| 				</g> | ||||
| 				<g> | ||||
| 					<path class="st1" d="M52.6,166.2v-4h0.7v3.4h1.8v0.6H52.6z"/> | ||||
| 				</g> | ||||
| 				<g> | ||||
| 					<path class="st1" d="M55.7,166.2v-4h2.7v0.6h-2v1h2v0.6h-2v1.1h2v0.6H55.7z"/> | ||||
| 				</g> | ||||
| 				<g> | ||||
| 					<path class="st1" d="M59.1,164.2c0-1.2,0.9-2.1,2.1-2.1c0.8,0,1.3,0.4,1.6,0.9l-0.6,0.3c-0.2-0.3-0.6-0.6-1-0.6 | ||||
| 						c-0.8,0-1.4,0.6-1.4,1.4c0,0.8,0.6,1.4,1.4,1.4c0.4,0,0.8-0.3,1-0.6l0.6,0.3c-0.3,0.5-0.8,0.9-1.6,0.9 | ||||
| 						C60,166.3,59.1,165.5,59.1,164.2z"/> | ||||
| 				</g> | ||||
| 				<g> | ||||
| 					<path class="st1" d="M63.2,164.2c0-1.2,0.8-2.1,2-2.1c1.2,0,2,0.9,2,2.1c0,1.2-0.8,2.1-2,2.1C64,166.3,63.2,165.4,63.2,164.2z | ||||
| 						 M66.5,164.2c0-0.8-0.5-1.4-1.3-1.4c-0.8,0-1.3,0.6-1.3,1.4c0,0.8,0.5,1.4,1.3,1.4C66,165.7,66.5,165,66.5,164.2z"/> | ||||
| 				</g> | ||||
| 				<g> | ||||
| 					<path class="st1" d="M71.3,166.2v-3.1l-1.2,3.1h-0.3l-1.2-3.1v3.1h-0.7v-4h1l1.1,2.7l1.1-2.7h1v4H71.3z"/> | ||||
| 				</g> | ||||
| 				<g> | ||||
| 					<path class="st1" d="M75.7,166.2v-4h0.7v4H75.7z"/> | ||||
| 				</g> | ||||
| 				<g> | ||||
| 					<path class="st1" d="M80.4,166.2l-2.1-2.8v2.8h-0.7v-4h0.7l2,2.8v-2.8h0.7v4H80.4z"/> | ||||
| 				</g> | ||||
| 				<g> | ||||
| 					<path class="st1" d="M82.3,166.2v-4H85v0.6h-2v1h2v0.6h-2v1.7H82.3z"/> | ||||
| 				</g> | ||||
| 				<g> | ||||
| 					<path class="st1" d="M87.9,166.2l-0.9-1.5h-0.7v1.5h-0.7v-4h1.7c0.8,0,1.3,0.5,1.3,1.2c0,0.7-0.5,1.1-0.9,1.2l1,1.6H87.9z | ||||
| 						 M88,163.5c0-0.4-0.3-0.6-0.7-0.6h-1v1.3h1C87.7,164.1,88,163.9,88,163.5z"/> | ||||
| 				</g> | ||||
| 				<g> | ||||
| 					<path class="st1" d="M92.4,166.2l-0.3-0.8h-1.8l-0.3,0.8h-0.8l1.6-4h0.9l1.6,4H92.4z M91.2,162.9l-0.7,1.9h1.4L91.2,162.9z"/> | ||||
| 				</g> | ||||
| 				<g> | ||||
| 					<path class="st1" d="M95.8,166.2v-4h1.5c0.8,0,1.2,0.5,1.2,1.2c0,0.6-0.4,1.2-1.2,1.2h-1.2v1.7H95.8z M98.2,163.4 | ||||
| 						c0-0.5-0.3-0.9-0.9-0.9h-1.1v1.7h1.1C97.8,164.3,98.2,163.9,98.2,163.4z"/> | ||||
| 				</g> | ||||
| 				<g> | ||||
| 					<path class="st1" d="M101.5,166.2l-1.1-1.6h-0.9v1.6h-0.3v-4h1.5c0.7,0,1.2,0.4,1.2,1.2c0,0.7-0.5,1.1-1.1,1.1l1.2,1.7H101.5z | ||||
| 						 M101.6,163.4c0-0.5-0.4-0.9-0.9-0.9h-1.1v1.7h1.1C101.2,164.3,101.6,163.9,101.6,163.4z"/> | ||||
| 				</g> | ||||
| 				<g> | ||||
| 					<path class="st1" d="M102.8,164.2c0-1.2,0.8-2.1,1.9-2.1c1.2,0,1.9,0.9,1.9,2.1c0,1.2-0.8,2.1-1.9,2.1 | ||||
| 						C103.6,166.3,102.8,165.4,102.8,164.2z M106.3,164.2c0-1-0.6-1.7-1.6-1.7c-1,0-1.6,0.7-1.6,1.7c0,1,0.6,1.7,1.6,1.7 | ||||
| 						C105.7,166,106.3,165.2,106.3,164.2z"/> | ||||
| 				</g> | ||||
| 				<g> | ||||
| 					<path class="st1" d="M106.9,165.8l0.2-0.3c0.2,0.2,0.4,0.4,0.8,0.4c0.5,0,0.9-0.4,0.9-0.9v-2.8h0.3v2.8c0,0.8-0.5,1.2-1.2,1.2 | ||||
| 						C107.5,166.3,107.2,166.1,106.9,165.8z"/> | ||||
| 				</g> | ||||
| 				<g> | ||||
| 					<path class="st1" d="M110.4,166.2v-4h2.5v0.3h-2.2v1.5h2.1v0.3h-2.1v1.6h2.2v0.3H110.4z"/> | ||||
| 				</g> | ||||
| 				<g> | ||||
| 					<path class="st1" d="M113.5,164.2c0-1.2,0.9-2.1,2-2.1c0.6,0,1.1,0.3,1.5,0.7l-0.3,0.2c-0.3-0.3-0.7-0.6-1.2-0.6 | ||||
| 						c-0.9,0-1.7,0.7-1.7,1.7c0,1,0.7,1.7,1.7,1.7c0.5,0,0.9-0.2,1.2-0.6l0.3,0.2c-0.4,0.4-0.8,0.7-1.5,0.7 | ||||
| 						C114.4,166.3,113.5,165.5,113.5,164.2z"/> | ||||
| 				</g> | ||||
| 				<g> | ||||
| 					<path class="st1" d="M118.7,166.2v-3.7h-1.3v-0.3h2.9v0.3H119v3.7H118.7z"/> | ||||
| 				</g> | ||||
| 			</g> | ||||
| 			<g> | ||||
| 				<polygon class="st1" points="26.3,163.8 31.6,158.5 36.9,163.8 37.7,163.8 31.6,157.6 25.5,163.8 				"/> | ||||
| 				<polygon class="st1" points="36.9,164.7 31.6,170 26.3,164.7 25.5,164.7 31.6,170.8 37.7,164.7 				"/> | ||||
| 				<polygon class="st1" points="31,163.8 36.3,158.5 41.6,163.8 42.5,163.8 36.3,157.6 30.2,163.8 				"/> | ||||
| 				<polygon class="st1" points="41.6,164.7 36.3,170 31,164.7 30.2,164.7 36.3,170.8 42.5,164.7 				"/> | ||||
| 			</g> | ||||
| 		</g> | ||||
| 		<g> | ||||
| 			<path class="st1" d="M33.2,100.7c-4.6,0-8.3,3.7-8.3,8.3s3.7,8.3,8.3,8.3s8.3-3.7,8.3-8.3S37.8,100.7,33.2,100.7z"/> | ||||
| 		</g> | ||||
| 		<g> | ||||
| 			<g> | ||||
| 				<g> | ||||
| 					<path class="st2" d="M33.2,35.2c40.7,0,73.8,33.1,73.8,73.8c0,0.7,0,1.4,0,2.1c0,1.7,0.6,3.3,1.7,4.6c1.2,1.2,2.8,1.9,4.5,2 | ||||
| 						l0.2,0c3.5,0,6.3-2.7,6.4-6.2c0-0.8,0-1.7,0-2.5c0-47.7-38.8-86.6-86.6-86.6c-0.8,0-1.7,0-2.5,0c-1.7,0-3.3,0.8-4.5,2 | ||||
| 						c-1.2,1.2-1.8,2.9-1.7,4.6c0.1,3.5,3,6.3,6.6,6.2C31.8,35.2,32.5,35.2,33.2,35.2z"/> | ||||
| 				</g> | ||||
| 			</g> | ||||
| 		</g> | ||||
| 		<g> | ||||
| 			<g> | ||||
| 				<g> | ||||
| 					<path class="st3" d="M33.2,60.5c26.7,0,48.5,21.7,48.5,48.5c0,0.6,0,1.3,0,2c-0.1,1.7,0.5,3.3,1.7,4.6c1.2,1.3,2.7,2,4.4,2.1 | ||||
| 						c1.7,0.1,3.3-0.5,4.6-1.7c1.2-1.2,2-2.7,2-4.4c0-0.9,0.1-1.8,0.1-2.6c0-33.8-27.5-61.2-61.2-61.2c-0.8,0-1.6,0-2.6,0.1 | ||||
| 						c-1.7,0.1-3.3,0.8-4.4,2.1c-1.2,1.3-1.8,2.9-1.7,4.6s0.8,3.3,2.1,4.4c1.3,1.2,2.9,1.8,4.6,1.7C31.9,60.5,32.6,60.5,33.2,60.5z" | ||||
| 						/> | ||||
| 				</g> | ||||
| 			</g> | ||||
| 		</g> | ||||
| 		<g> | ||||
| 			<g> | ||||
| 				<g> | ||||
| 					<path class="st4" d="M33.2,86.7c12.3,0,22.3,10,22.3,22.3c0,0.5,0,1.1-0.1,1.8c-0.3,3.5,2.3,6.6,5.8,6.9 | ||||
| 						c3.5,0.3,6.6-2.3,6.9-5.8c0.1-1,0.1-1.9,0.1-2.8c0-19.3-15.7-35.1-35.1-35.1c-0.9,0-1.8,0-2.8,0.1c-1.7,0.1-3.2,0.9-4.3,2.2 | ||||
| 						c-1.1,1.3-1.6,2.9-1.5,4.6c0.1,1.7,0.9,3.2,2.2,4.3c1.3,1.1,2.9,1.6,4.6,1.5C32.1,86.7,32.7,86.7,33.2,86.7z"/> | ||||
| 				</g> | ||||
| 			</g> | ||||
| 		</g> | ||||
| 	</g> | ||||
| 	<g> | ||||
| 		<path class="st1" d="M35.8,130.4c1.1,0.6,2.1,1.5,2.7,2.6c0.7,1.1,1,2.3,1,3.7s-0.3,2.6-1,3.7c-0.7,1.1-1.6,2-2.7,2.6 | ||||
| 			c-1.1,0.6-2.4,1-3.8,1s-2.7-0.3-3.8-1c-1.1-0.6-2.1-1.5-2.7-2.6c-0.7-1.1-1-2.3-1-3.7c0-1.3,0.3-2.6,1-3.7c0.7-1.1,1.6-2,2.7-2.6 | ||||
| 			c1.1-0.6,2.4-0.9,3.8-0.9C33.4,129.5,34.7,129.8,35.8,130.4z M29.9,132.9c-0.7,0.4-1.2,0.9-1.6,1.6s-0.6,1.4-0.6,2.2 | ||||
| 			c0,0.8,0.2,1.6,0.6,2.3c0.4,0.7,0.9,1.2,1.6,1.6c0.7,0.4,1.4,0.6,2.1,0.6c0.8,0,1.5-0.2,2.1-0.6c0.6-0.4,1.2-0.9,1.5-1.6 | ||||
| 			c0.4-0.7,0.6-1.4,0.6-2.3c0-0.8-0.2-1.6-0.6-2.2s-0.9-1.2-1.5-1.6c-0.6-0.4-1.4-0.6-2.1-0.6C31.3,132.3,30.6,132.5,29.9,132.9z"/> | ||||
| 		<path class="st1" d="M50.6,133.6c0.8,0.5,1.4,1.1,1.8,2c0.4,0.8,0.6,1.8,0.6,2.9c0,1.1-0.2,2-0.6,2.8c-0.4,0.8-1,1.5-1.8,1.9 | ||||
| 			c-0.8,0.5-1.6,0.7-2.6,0.7c-0.7,0-1.4-0.1-2-0.4s-1.1-0.7-1.5-1.2v5.4h-3.1V133h3.1v1.6c0.4-0.5,0.9-1,1.4-1.2s1.2-0.4,2-0.4 | ||||
| 			C48.9,132.9,49.8,133.1,50.6,133.6z M49.1,140.5c0.5-0.6,0.7-1.3,0.7-2.2c0-0.9-0.2-1.6-0.7-2.1c-0.5-0.6-1.1-0.8-1.9-0.8 | ||||
| 			s-1.4,0.3-1.9,0.8c-0.5,0.6-0.8,1.3-0.8,2.1c0,0.9,0.2,1.6,0.8,2.2s1.1,0.8,1.9,0.8S48.6,141,49.1,140.5z"/> | ||||
| 		<path class="st1" d="M63.4,134.4c0.9,1,1.4,2.4,1.4,4.2c0,0.3,0,0.6,0,0.7H57c0.2,0.7,0.5,1.2,1,1.6c0.5,0.4,1.1,0.6,1.8,0.6 | ||||
| 			c0.5,0,1-0.1,1.5-0.3s0.9-0.5,1.3-0.9l1.6,1.6c-0.5,0.6-1.2,1.1-2,1.4c-0.8,0.3-1.6,0.5-2.6,0.5c-1.1,0-2.1-0.2-3-0.7 | ||||
| 			s-1.5-1.1-2-1.9c-0.5-0.8-0.7-1.8-0.7-2.9c0-1.1,0.2-2.1,0.7-2.9s1.1-1.5,2-1.9c0.8-0.5,1.8-0.7,2.9-0.7 | ||||
| 			C61.2,132.9,62.5,133.4,63.4,134.4z M61.8,137.5c0-0.7-0.3-1.3-0.7-1.7s-1-0.6-1.7-0.6c-0.7,0-1.2,0.2-1.7,0.6 | ||||
| 			c-0.4,0.4-0.7,1-0.9,1.7H61.8z"/> | ||||
| 		<path class="st1" d="M76.2,134c0.7,0.7,1.1,1.7,1.1,3v6.8h-3.1v-5.9c0-0.7-0.2-1.2-0.6-1.6s-0.9-0.6-1.5-0.6 | ||||
| 			c-0.8,0-1.4,0.3-1.8,0.8c-0.4,0.5-0.7,1.2-0.7,2v5.3h-3.1V133h3.1v1.9c0.7-1.3,2-2,3.7-2C74.6,132.8,75.5,133.2,76.2,134z"/> | ||||
| 		<path class="st1" d="M96,129.7h3.3l-4.7,14h-3.3l-2.9-10.1l-3,10.1h-3.2l-4.7-14h3.4l3,10.7l3-10.7H90l3.1,10.7L96,129.7z"/> | ||||
| 		<path class="st1" d="M103.3,128.7c0.3,0.3,0.5,0.7,0.5,1.2s-0.2,0.9-0.5,1.2c-0.3,0.3-0.7,0.5-1.2,0.5c-0.5,0-0.9-0.2-1.2-0.5 | ||||
| 			c-0.3-0.3-0.5-0.7-0.5-1.2c0-0.5,0.2-0.9,0.5-1.2c0.3-0.3,0.7-0.5,1.2-0.5C102.6,128.2,103,128.3,103.3,128.7z M100.6,133h3.1 | ||||
| 			v10.8h-3.1V133z"/> | ||||
| 		<path class="st1" d="M106.5,129.7h10.1l0,2.6h-6.9v3.4h6.3v2.6h-6.3v5.3h-3.2V129.7z"/> | ||||
| 		<path class="st1" d="M120.9,128.7c0.3,0.3,0.5,0.7,0.5,1.2s-0.2,0.9-0.5,1.2c-0.3,0.3-0.7,0.5-1.2,0.5c-0.5,0-0.9-0.2-1.2-0.5 | ||||
| 			c-0.3-0.3-0.5-0.7-0.5-1.2c0-0.5,0.2-0.9,0.5-1.2c0.3-0.3,0.7-0.5,1.2-0.5C120.1,128.2,120.5,128.3,120.9,128.7z M118.1,133h3.1 | ||||
| 			v10.8h-3.1V133z"/> | ||||
| 	</g> | ||||
| </g> | ||||
| <g> | ||||
| </g> | ||||
| <g> | ||||
| </g> | ||||
| <g> | ||||
| </g> | ||||
| <g> | ||||
| </g> | ||||
| <g> | ||||
| </g> | ||||
| <g> | ||||
| </g> | ||||
| </svg> | ||||
| After Width: | Height: | Size: 8.0 KiB | 
							
								
								
									
										407
									
								
								openapi/openroaming_globalreach.yaml
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,407 @@ | ||||
| openapi: 3.0.1 | ||||
| info: | ||||
|   title: OpenWiFi RadiusEndpointTypes Provisioning Model for Global Reach | ||||
|   description: Definitions and APIs to Open Roaming WiFi. | ||||
|   version: 2.5.0 | ||||
|   license: | ||||
|     name: BSD3 | ||||
|     url: https://github.com/Telecominfraproject/wlan-cloud-ucentralgw/blob/master/LICENSE | ||||
|  | ||||
| servers: | ||||
|   - url: 'https://localhost:16005/api/v1' | ||||
|  | ||||
| security: | ||||
|   - bearerAuth: [] | ||||
|   - ApiKeyAuth: [] | ||||
|  | ||||
| components: | ||||
|   securitySchemes: | ||||
|     ApiKeyAuth: | ||||
|       type: apiKey | ||||
|       in: header | ||||
|       name: X-API-KEY | ||||
|     bearerAuth: | ||||
|       type: http | ||||
|       scheme: bearer | ||||
|       bearerFormat: JWT | ||||
|  | ||||
|   responses: | ||||
|     NotFound: | ||||
|       $ref: 'https://github.com/Telecominfraproject/wlan-cloud-ucentralsec/blob/main/openpapi/owsec.yaml#/components/responses/NotFound' | ||||
|     Unauthorized: | ||||
|       $ref: 'https://github.com/Telecominfraproject/wlan-cloud-ucentralsec/blob/main/openpapi/owsec.yaml#/components/responses/Unauthorized' | ||||
|     Success: | ||||
|       $ref: 'https://github.com/Telecominfraproject/wlan-cloud-ucentralsec/blob/main/openpapi/owsec.yaml#/components/responses/Success' | ||||
|     BadRequest: | ||||
|       $ref: 'https://github.com/Telecominfraproject/wlan-cloud-ucentralsec/blob/main/openpapi/owsec.yaml#/components/responses/BadRequest' | ||||
|  | ||||
|   schemas: | ||||
|     GLBLRAccountInfo: | ||||
|       type: object | ||||
|       properties: | ||||
|         allOf: | ||||
|           $ref: 'https://github.com/Telecominfraproject/wlan-cloud-owprov/blob/main/openpapi/owprov.yaml#/components/schemas/ObjectInfo' | ||||
|         privateKey: | ||||
|           type: string | ||||
|         country: | ||||
|           type: string | ||||
|         province: | ||||
|           type: string | ||||
|         city: | ||||
|           type: string | ||||
|         organization: | ||||
|           type: string | ||||
|         commonName: | ||||
|           type: string | ||||
|         CSR: | ||||
|           type: string | ||||
|         CSRPrivateKey: | ||||
|           type: string | ||||
|         CSRPublicKey: | ||||
|           type: string | ||||
|         GlobalReachAcctId: | ||||
|           type: string | ||||
|  | ||||
|     GLBLRCertificateInfo: | ||||
|       type: object | ||||
|       properties: | ||||
|         id: | ||||
|           type: string | ||||
|           format: uuid | ||||
|         name: | ||||
|           type: string | ||||
|         accountId: | ||||
|           type: string | ||||
|           format: uuid | ||||
|         csr: | ||||
|           type: string | ||||
|         certificate: | ||||
|           type: string | ||||
|         certificateChain: | ||||
|           type: string | ||||
|         certificateId: | ||||
|           type: string | ||||
|         expiresAt: | ||||
|           type: integer | ||||
|           format: int64 | ||||
|         created: | ||||
|           type: integer | ||||
|           format: int64 | ||||
|  | ||||
| paths: | ||||
|   /openroaming/globalreach/accounts: | ||||
|     get: | ||||
|       tags: | ||||
|         - RadiusEndpointTypes-Global Reach | ||||
|       operationId: getOpenRoamingGlobalReachAccountList | ||||
|       summary: Retrieve account list. | ||||
|       parameters: | ||||
|         - in: query | ||||
|           description: Pagination start (starts at 1. If not specified, 1 is assumed) | ||||
|           name: offset | ||||
|           schema: | ||||
|             type: integer | ||||
|           required: false | ||||
|         - in: query | ||||
|           description: Maximum number of entries to return (if absent, no limit is assumed) | ||||
|           name: limit | ||||
|           schema: | ||||
|             type: integer | ||||
|           required: false | ||||
|         - in: query | ||||
|           description: return the number of accounts | ||||
|           name: countOnly | ||||
|           schema: | ||||
|             type: boolean | ||||
|           required: false | ||||
|  | ||||
|       responses: | ||||
|         200: | ||||
|           description: The list of accounts | ||||
|           content: | ||||
|             application/json: | ||||
|               schema: | ||||
|                 type: array | ||||
|                 items: | ||||
|                   $ref: '#/components/schemas/GLBLRAccountInfo' | ||||
|           $ref: '#/components/responses/Success' | ||||
|         400: | ||||
|           $ref: '#/components/responses/BadRequest' | ||||
|         403: | ||||
|           $ref: '#/components/responses/Unauthorized' | ||||
|         404: | ||||
|           $ref: '#/components/responses/NotFound' | ||||
|  | ||||
|   /openroaming/globalreach/account/{name}: | ||||
|     get: | ||||
|       tags: | ||||
|         - RadiusEndpointTypes-Global Reach | ||||
|       operationId: getOpenRoamingGlobalReachAccount | ||||
|       summary: Retrieve account information. | ||||
|       parameters: | ||||
|         - in: path | ||||
|           description: The account name | ||||
|           name: name | ||||
|           schema: | ||||
|             type: string | ||||
|           required: true | ||||
|       responses: | ||||
|         200: | ||||
|           $ref: '#/components/schemas/GLBLRAccountInfo' | ||||
|         400: | ||||
|           $ref: '#/components/responses/BadRequest' | ||||
|         403: | ||||
|           $ref: '#/components/responses/Unauthorized' | ||||
|         404: | ||||
|           $ref: '#/components/responses/NotFound' | ||||
|  | ||||
|     delete: | ||||
|       tags: | ||||
|         - RadiusEndpointTypes-Global Reach | ||||
|       operationId: deleteOpenRoamingGlobalReachAccount | ||||
|       summary: Delete account information. | ||||
|       parameters: | ||||
|         - in: path | ||||
|           description: The account name | ||||
|           name: name | ||||
|           schema: | ||||
|             type: string | ||||
|           required: true | ||||
|       responses: | ||||
|         200: | ||||
|           $ref: '#/components/responses/Success' | ||||
|         400: | ||||
|           $ref: '#/components/responses/BadRequest' | ||||
|         403: | ||||
|           $ref: '#/components/responses/Unauthorized' | ||||
|         404: | ||||
|           $ref: '#/components/responses/NotFound' | ||||
|  | ||||
|     post: | ||||
|       tags: | ||||
|         - RadiusEndpointTypes-Global Reach | ||||
|       operationId: createOpenRoamingGlobalReachAccount | ||||
|       summary: Create account information. | ||||
|       parameters: | ||||
|         - in: path | ||||
|           description: The account name | ||||
|           name: name | ||||
|           schema: | ||||
|             type: string | ||||
|           required: true | ||||
|       requestBody: | ||||
|         content: | ||||
|           application/json: | ||||
|             schema: | ||||
|               $ref: '#/components/schemas/GLBLRAccountInfo' | ||||
|       responses: | ||||
|         200: | ||||
|           $ref: '#/components/schemas/GLBLRAccountInfo' | ||||
|         400: | ||||
|           $ref: '#/components/responses/BadRequest' | ||||
|         403: | ||||
|           $ref: '#/components/responses/Unauthorized' | ||||
|         404: | ||||
|           $ref: '#/components/responses/NotFound' | ||||
|  | ||||
|     put: | ||||
|       tags: | ||||
|         - RadiusEndpointTypes-Global Reach | ||||
|       operationId: modifyOpenRoamingGlobalReachAccount | ||||
|       summary: Modify account information. | ||||
|       parameters: | ||||
|         - in: path | ||||
|           description: The account name | ||||
|           name: name | ||||
|           schema: | ||||
|             type: string | ||||
|           required: true | ||||
|       requestBody: | ||||
|         content: | ||||
|           application/json: | ||||
|             schema: | ||||
|               $ref: '#/components/schemas/GLBLRAccountInfo' | ||||
|       responses: | ||||
|         200: | ||||
|           $ref: '#/components/schemas/GLBLRAccountInfo' | ||||
|         400: | ||||
|           $ref: '#/components/responses/BadRequest' | ||||
|         403: | ||||
|           $ref: '#/components/responses/Unauthorized' | ||||
|         404: | ||||
|           $ref: '#/components/responses/NotFound' | ||||
|  | ||||
|   /openroaming/globalreach/certificates/{account}: | ||||
|     get: | ||||
|       tags: | ||||
|         - RadiusEndpointTypes-Global Reach Certificate | ||||
|       operationId: getOpenRoamingGlobalReachCertificateList | ||||
|       summary: Retrieve certificate list. | ||||
|       parameters: | ||||
|         - in: path | ||||
|           description: The account name | ||||
|           name: account | ||||
|           schema: | ||||
|             type: string | ||||
|           required: true | ||||
|         - in: query | ||||
|           description: Pagination start (starts at 1. If not specified, 1 is assumed) | ||||
|           name: offset | ||||
|           schema: | ||||
|             type: integer | ||||
|           required: false | ||||
|         - in: query | ||||
|           description: Maximum number of entries to return (if absent, no limit is assumed) | ||||
|           name: limit | ||||
|           schema: | ||||
|             type: integer | ||||
|           required: false | ||||
|         - in: query | ||||
|           description: return the number of certificates | ||||
|           name: countOnly | ||||
|           schema: | ||||
|             type: boolean | ||||
|           required: false | ||||
|  | ||||
|       responses: | ||||
|         200: | ||||
|           description: The list of certificates | ||||
|           content: | ||||
|             application/json: | ||||
|               schema: | ||||
|                 type: array | ||||
|                 items: | ||||
|                   $ref: '#/components/schemas/GLBLRCertificateInfo' | ||||
|           $ref: '#/components/responses/Success' | ||||
|         400: | ||||
|           $ref: '#/components/responses/BadRequest' | ||||
|         403: | ||||
|           $ref: '#/components/responses/Unauthorized' | ||||
|         404: | ||||
|           $ref: '#/components/responses/NotFound' | ||||
|  | ||||
|   /openroaming/globalreach/certificate/{account}/{id}: | ||||
|     get: | ||||
|       tags: | ||||
|         - RadiusEndpointTypes-Global Reach Certificate | ||||
|       operationId: getOpenRoamingGlobalReachCertificate | ||||
|       summary: Retrieve certificate information. | ||||
|       parameters: | ||||
|         - in: path | ||||
|           description: The account name - this is the provisioning ID for the account. Not the GlobalReach ID. | ||||
|           name: account | ||||
|           schema: | ||||
|             type: string | ||||
|           required: true | ||||
|         - in: path | ||||
|           description: The certificate id in provisioning - not the certificate_id from GlobalReach | ||||
|           name: id | ||||
|           schema: | ||||
|             type: string | ||||
|           required: true | ||||
|       responses: | ||||
|         200: | ||||
|           $ref: '#/components/schemas/GLBLRCertificateInfo' | ||||
|         400: | ||||
|           $ref: '#/components/responses/BadRequest' | ||||
|         403: | ||||
|           $ref: '#/components/responses/Unauthorized' | ||||
|         404: | ||||
|           $ref: '#/components/responses/NotFound' | ||||
|  | ||||
|     delete: | ||||
|       tags: | ||||
|         - RadiusEndpointTypes-Global Reach Certificate | ||||
|       operationId: deleteOpenRoamingGlobalReachCertificate | ||||
|       summary: Delete certificate information. | ||||
|       parameters: | ||||
|         - in: path | ||||
|           description: The account name - this is the provisioning ID for the account. Not the GlobalReach ID. | ||||
|           name: account | ||||
|           schema: | ||||
|             type: string | ||||
|           required: true | ||||
|         - in: path | ||||
|           description: The certificate id in provisioning - not the certificate_id from GlobalReach | ||||
|           name: id | ||||
|           schema: | ||||
|             type: string | ||||
|           required: true | ||||
|       responses: | ||||
|         200: | ||||
|           $ref: '#/components/responses/Success' | ||||
|         400: | ||||
|           $ref: '#/components/responses/BadRequest' | ||||
|         403: | ||||
|           $ref: '#/components/responses/Unauthorized' | ||||
|         404: | ||||
|           $ref: '#/components/responses/NotFound' | ||||
|  | ||||
|     post: | ||||
|       tags: | ||||
|         - RadiusEndpointTypes-Global Reach Certificate | ||||
|       operationId: createOpenRoamingGlobalReachCertificate | ||||
|       summary: Create certificate information. | ||||
|       parameters: | ||||
|         - in: path | ||||
|           description: The account name - this is the provisioning ID for the account. Not the GlobalReach ID. | ||||
|           name: account | ||||
|           schema: | ||||
|             type: string | ||||
|           required: true | ||||
|         - in: path | ||||
|           description: Must be set to "0" | ||||
|           name: id | ||||
|           schema: | ||||
|             type: string | ||||
|           required: true | ||||
|       requestBody: | ||||
|         content: | ||||
|           application/json: | ||||
|             schema: | ||||
|               $ref: '#/components/schemas/GLBLRCertificateInfo' | ||||
|       responses: | ||||
|         200: | ||||
|           $ref: '#/components/schemas/GLBLRCertificateInfo' | ||||
|         400: | ||||
|           $ref: '#/components/responses/BadRequest' | ||||
|         403: | ||||
|           $ref: '#/components/responses/Unauthorized' | ||||
|         404: | ||||
|           $ref: '#/components/responses/NotFound' | ||||
|  | ||||
|     put: | ||||
|       tags: | ||||
|         - RadiusEndpointTypes-Global Reach Certificate | ||||
|       operationId: updateOpenRoamingGlobalReachCertificate | ||||
|       summary: Update certificate information. | ||||
|       parameters: | ||||
|         - in: path | ||||
|           description: The account name - this is the provisioning ID for the account. Not the GlobalReach ID. | ||||
|           name: account | ||||
|           schema: | ||||
|             type: string | ||||
|           required: true | ||||
|         - in: path | ||||
|           description: the UUID of the certificate | ||||
|           name: id | ||||
|           schema: | ||||
|             type: string | ||||
|           required: true | ||||
|         - in: query | ||||
|           description: Update an existing certificate | ||||
|           name: updateCertificate | ||||
|           schema: | ||||
|             type: boolean | ||||
|             default: false | ||||
|           required: false | ||||
|       responses: | ||||
|         200: | ||||
|           $ref: '#/components/schemas/GLBLRCertificateInfo' | ||||
|         400: | ||||
|           $ref: '#/components/responses/BadRequest' | ||||
|         403: | ||||
|           $ref: '#/components/responses/Unauthorized' | ||||
|         404: | ||||
|           $ref: '#/components/responses/NotFound' | ||||
|  | ||||
							
								
								
									
										199
									
								
								openapi/openroaming_orion.yaml
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,199 @@ | ||||
| openapi: 3.0.1 | ||||
| info: | ||||
|   title: OpenWiFi RadiusEndpointTypes Provisioning Model for Google Orion | ||||
|   description: Definitions and APIs to Open Roaming WiFi. | ||||
|   version: 2.5.0 | ||||
|   license: | ||||
|     name: BSD3 | ||||
|     url: https://github.com/Telecominfraproject/wlan-cloud-ucentralgw/blob/master/LICENSE | ||||
|  | ||||
| servers: | ||||
|   - url: 'https://localhost:16005/api/v1' | ||||
|  | ||||
| security: | ||||
|   - bearerAuth: [] | ||||
|   - ApiKeyAuth: [] | ||||
|  | ||||
| components: | ||||
|   securitySchemes: | ||||
|     ApiKeyAuth: | ||||
|       type: apiKey | ||||
|       in: header | ||||
|       name: X-API-KEY | ||||
|     bearerAuth: | ||||
|       type: http | ||||
|       scheme: bearer | ||||
|       bearerFormat: JWT | ||||
|  | ||||
|   responses: | ||||
|     NotFound: | ||||
|       $ref: 'https://github.com/Telecominfraproject/wlan-cloud-ucentralsec/blob/main/openpapi/owsec.yaml#/components/responses/NotFound' | ||||
|     Unauthorized: | ||||
|       $ref: 'https://github.com/Telecominfraproject/wlan-cloud-ucentralsec/blob/main/openpapi/owsec.yaml#/components/responses/Unauthorized' | ||||
|     Success: | ||||
|       $ref: 'https://github.com/Telecominfraproject/wlan-cloud-ucentralsec/blob/main/openpapi/owsec.yaml#/components/responses/Success' | ||||
|     BadRequest: | ||||
|       $ref: 'https://github.com/Telecominfraproject/wlan-cloud-ucentralsec/blob/main/openpapi/owsec.yaml#/components/responses/BadRequest' | ||||
|  | ||||
|   schemas: | ||||
|     GooglOrionAccountInfo: | ||||
|       type: object | ||||
|       properties: | ||||
|         allOf: | ||||
|           $ref: 'https://github.com/Telecominfraproject/wlan-cloud-owprov/blob/main/openpapi/owprov.yaml#/components/schemas/ObjectInfo' | ||||
|         privateKey: | ||||
|           type: string | ||||
|         certificate: | ||||
|           type: string | ||||
|         cacerts: | ||||
|           type: array | ||||
|           items: | ||||
|             type: string | ||||
|  | ||||
| paths: | ||||
|   /openroaming/orion/accounts: | ||||
|     get: | ||||
|       tags: | ||||
|         - RadiusEndpointTypes-Google Orion | ||||
|       operationId: getOpenRoamingGlobalReachAccountList | ||||
|       summary: Retrieve account list. | ||||
|       parameters: | ||||
|         - in: query | ||||
|           description: Pagination start (starts at 1. If not specified, 1 is assumed) | ||||
|           name: offset | ||||
|           schema: | ||||
|             type: integer | ||||
|           required: false | ||||
|         - in: query | ||||
|           description: Maximum number of entries to return (if absent, no limit is assumed) | ||||
|           name: limit | ||||
|           schema: | ||||
|             type: integer | ||||
|           required: false | ||||
|         - in: query | ||||
|           description: return the number of accounts | ||||
|           name: countOnly | ||||
|           schema: | ||||
|             type: boolean | ||||
|           required: false | ||||
|  | ||||
|       responses: | ||||
|         200: | ||||
|           description: The list of accounts | ||||
|           content: | ||||
|             application/json: | ||||
|               schema: | ||||
|                 type: array | ||||
|                 items: | ||||
|                   $ref: '#/components/schemas/GooglOrionAccountInfo' | ||||
|           $ref: '#/components/responses/Success' | ||||
|         400: | ||||
|           $ref: '#/components/responses/BadRequest' | ||||
|         403: | ||||
|           $ref: '#/components/responses/Unauthorized' | ||||
|         404: | ||||
|           $ref: '#/components/responses/NotFound' | ||||
|  | ||||
|   /openroaming/orion/account/{id}: | ||||
|     get: | ||||
|       tags: | ||||
|         - RadiusEndpointTypes-Google Orion | ||||
|       operationId: getOpenRoamingGlobalReachAccount | ||||
|       summary: Retrieve account information. | ||||
|       parameters: | ||||
|         - in: path | ||||
|           description: The account ID | ||||
|           name: id | ||||
|           schema: | ||||
|             type: string | ||||
|             format: uuid | ||||
|           required: true | ||||
|       responses: | ||||
|         200: | ||||
|           $ref: '#/components/schemas/GooglOrionAccountInfo' | ||||
|         400: | ||||
|           $ref: '#/components/responses/BadRequest' | ||||
|         403: | ||||
|           $ref: '#/components/responses/Unauthorized' | ||||
|         404: | ||||
|           $ref: '#/components/responses/NotFound' | ||||
|  | ||||
|     delete: | ||||
|       tags: | ||||
|         - RadiusEndpointTypes-Google Orion | ||||
|       operationId: deleteOpenRoamingGlobalReachAccount | ||||
|       summary: Delete account information. | ||||
|       parameters: | ||||
|         - in: path | ||||
|           description: The account ID | ||||
|           name: id | ||||
|           schema: | ||||
|             type: string | ||||
|             format: uuid | ||||
|           required: true | ||||
|       responses: | ||||
|         200: | ||||
|           $ref: '#/components/responses/Success' | ||||
|         400: | ||||
|           $ref: '#/components/responses/BadRequest' | ||||
|         403: | ||||
|           $ref: '#/components/responses/Unauthorized' | ||||
|         404: | ||||
|           $ref: '#/components/responses/NotFound' | ||||
|  | ||||
|     post: | ||||
|       tags: | ||||
|         - RadiusEndpointTypes-Google Orion | ||||
|       operationId: createOpenRoamingGlobalReachAccount | ||||
|       summary: Create account information. | ||||
|       parameters: | ||||
|         - in: path | ||||
|           description: The account ID | ||||
|           name: id | ||||
|           schema: | ||||
|             type: string | ||||
|             format: uuid | ||||
|           required: true | ||||
|       requestBody: | ||||
|         content: | ||||
|           application/json: | ||||
|             schema: | ||||
|               $ref: '#/components/schemas/GooglOrionAccountInfo' | ||||
|       responses: | ||||
|         200: | ||||
|           $ref: '#/components/schemas/GooglOrionAccountInfo' | ||||
|         400: | ||||
|           $ref: '#/components/responses/BadRequest' | ||||
|         403: | ||||
|           $ref: '#/components/responses/Unauthorized' | ||||
|         404: | ||||
|           $ref: '#/components/responses/NotFound' | ||||
|  | ||||
|     put: | ||||
|       tags: | ||||
|         - RadiusEndpointTypes-Google Orion | ||||
|       operationId: modifyOpenRoamingGlobalReachAccount | ||||
|       summary: Modify account information. | ||||
|       parameters: | ||||
|         - in: path | ||||
|           description: The account ID | ||||
|           name: id | ||||
|           schema: | ||||
|             type: string | ||||
|             format: uuid | ||||
|           required: true | ||||
|       requestBody: | ||||
|         content: | ||||
|           application/json: | ||||
|             schema: | ||||
|               $ref: '#/components/schemas/GooglOrionAccountInfo' | ||||
|       responses: | ||||
|         200: | ||||
|           $ref: '#/components/schemas/GooglOrionAccountInfo' | ||||
|         400: | ||||
|           $ref: '#/components/responses/BadRequest' | ||||
|         403: | ||||
|           $ref: '#/components/responses/Unauthorized' | ||||
|         404: | ||||
|           $ref: '#/components/responses/NotFound' | ||||
|  | ||||
| @@ -1,268 +0,0 @@ | ||||
| openapi: 3.0.1 | ||||
| info: | ||||
|   title: OpenWiFi Open roaming Ameriband Provisioning Model | ||||
|   description: Registration of an OpenRoaming profile with Ameriband for TIP OpenWifi. | ||||
|   version: 1.0.0 | ||||
|   license: | ||||
|     name: BSD3 | ||||
|     url: https://github.com/Telecominfraproject/wlan-cloud-ucentralgw/blob/master/LICENSE | ||||
|  | ||||
| servers: | ||||
|   - url: 'https://tip.regiatration.ameriband.com:8001/api/v1' | ||||
|  | ||||
| security: | ||||
|   - bearerAuth: [] | ||||
|  | ||||
| components: | ||||
|   securitySchemes: | ||||
|     bearerAuth: | ||||
|       type: http | ||||
|       scheme: bearer | ||||
|  | ||||
|   responses: | ||||
|     NotFound: | ||||
|       description: The specified resource was not found. | ||||
|       content: | ||||
|         application/json: | ||||
|           schema: | ||||
|             properties: | ||||
|               ErrorCode: | ||||
|                 type: integer | ||||
|               ErrorDetails: | ||||
|                 type: string | ||||
|               ErrorDescription: | ||||
|                 type: string | ||||
|  | ||||
|     Unauthorized: | ||||
|       description: The requested does not have sufficient rights to perform the operation. | ||||
|       content: | ||||
|         application/json: | ||||
|           schema: | ||||
|             properties: | ||||
|               ErrorCode: | ||||
|                 type: integer | ||||
|                 enum: | ||||
|                   - 0     # Success | ||||
|                   - 8     # INVALID_TOKEN | ||||
|                   - 9     # EXPIRED_TOKEN | ||||
|               ErrorDetails: | ||||
|                 type: string | ||||
|               ErrorDescription: | ||||
|                 type: string | ||||
|  | ||||
|     Success: | ||||
|       description: The requested operation was performed. | ||||
|       content: | ||||
|         application/json: | ||||
|           schema: | ||||
|             properties: | ||||
|               Operation: | ||||
|                 type: string | ||||
|               Details: | ||||
|                 type: string | ||||
|               Code: | ||||
|                 type: integer | ||||
|  | ||||
|     BadRequest: | ||||
|       description: The requested operation failed. | ||||
|       content: | ||||
|         application/json: | ||||
|           schema: | ||||
|             properties: | ||||
|               ErrorCode: | ||||
|                 type: integer | ||||
|               ErrorDetails: | ||||
|                 type: string | ||||
|               ErrorDescription: | ||||
|                 type: integer | ||||
|  | ||||
|   schemas: | ||||
|     RegistrationRequest: | ||||
|       type: object | ||||
|       properties: | ||||
|         orgRequestId: | ||||
|           type: string | ||||
|           format: uuid | ||||
|           minLength: 36 | ||||
|           maxLength: 36 | ||||
|           example: | ||||
|             Client will generate a UUID that must be returned in the response. | ||||
|         orgAcceptedTermsAndConditions: | ||||
|           type: boolean | ||||
|           default: false | ||||
|         orgLegalName: | ||||
|           type: string | ||||
|           minLength: 1 | ||||
|         orgWebSite: | ||||
|           type: string | ||||
|           format: url | ||||
|           minLength: 1 | ||||
|         orgContact: | ||||
|           type: string | ||||
|           minLength: 1 | ||||
|           example: | ||||
|             John Smith | ||||
|         orgEmail: | ||||
|           type: string | ||||
|           format: email | ||||
|           minLength: 1 | ||||
|         orgPhone: | ||||
|           type: string | ||||
|           example: | ||||
|             (607)555-1234 or +1(223)555-1222 | ||||
|         orgLocation: | ||||
|           type: string | ||||
|           example: | ||||
|             Boston, NH - LA, CA | ||||
|         orgCertificate: | ||||
|           type: string | ||||
|           minLength: 1 | ||||
|           example: | ||||
|             This must be the entire PEM file content of the certificate, encoded using base64 | ||||
|  | ||||
|     RegistrationResponse: | ||||
|       type: object | ||||
|       properties: | ||||
|         orgRequestId: | ||||
|           type: string | ||||
|           format: uuid | ||||
|           minLength: 36 | ||||
|           maxLength: 36 | ||||
|           example: | ||||
|             This should be the same orgRequestId passed during registration. | ||||
|         orgNASID: | ||||
|           type: string | ||||
|           minLength: 10 | ||||
|           description: | ||||
|             This is the NASID generated by Ameriband. It will be used by the operator as NASID when contacting Ameriband. | ||||
|         ameribandCertificate: | ||||
|           type: string | ||||
|           minLength: 1 | ||||
|           example: | ||||
|             This must be the entire PEM file content of the certificate, encoded using base64 | ||||
|  | ||||
|     RegistrationInformationRequest: | ||||
|       type: object | ||||
|       properties: | ||||
|         link: | ||||
|           description: This should be the link where a potential registrant can read the terms and conditions of registering with Ameriband. | ||||
|           type: string | ||||
|           format: url | ||||
|           minLength: 1 | ||||
|           example: | ||||
|             https://ameriband.com/romain-registration.html | ||||
|  | ||||
| paths: | ||||
|   /termsAndConditions: | ||||
|     get: | ||||
|       summary: The registrant must be given a chance to view the terms and conditions of the relationship they are entering into | ||||
|       operationId: getTermsAndConditions | ||||
|       responses: | ||||
|         200: | ||||
|           description: Sucessfully retrieved Terms and Conditions | ||||
|           content: | ||||
|             application/json: | ||||
|               schema: | ||||
|                 $ref: '#/components/schemas/RegistrationInformationRequest' | ||||
|         404: | ||||
|           $ref: '#/components/responses/Unauthorized' | ||||
|  | ||||
|   /registration: | ||||
|     get: | ||||
|       tags: | ||||
|         - Registration | ||||
|       operationId: getRegistrationInformation | ||||
|       summary: This should return the information from a registration based on the NASID | ||||
|       parameters: | ||||
|         - in: query | ||||
|           name: orgNASID | ||||
|           schema: | ||||
|             type: string | ||||
|           required: true | ||||
|           example: | ||||
|             This is the orgNASID returned during registration. | ||||
|       responses: | ||||
|         200: | ||||
|           $ref: '#/components/schemas/RegistrationResponse' | ||||
|         403: | ||||
|           $ref: '#/components/responses/Unauthorized' | ||||
|         404: | ||||
|           $ref: '#/components/responses/NotFound' | ||||
|  | ||||
|     post: | ||||
|       summary: Called when the registrant ahs read the T&Cs and iw willing to submit their information to enter in a partnership | ||||
|       tags: | ||||
|         - Registration | ||||
|       operationId: createRegistration | ||||
|       requestBody: | ||||
|         required: true | ||||
|         content: | ||||
|           application/json: | ||||
|             schema: | ||||
|               $ref: '#/components/schemas/RegistrationRequest' | ||||
|       responses: | ||||
|         200: | ||||
|           description: Succesfully registered | ||||
|           content: | ||||
|             application/json: | ||||
|               schema: | ||||
|                 $ref: '#/components/schemas/RegistrationResponse' | ||||
|         400: | ||||
|           description: Registration failed due to  missing or incomplete information | ||||
|           $ref: '#/components/responses/BadRequest' | ||||
|         403: | ||||
|           $ref: '#/components/responses/Unauthorized' | ||||
|  | ||||
|     put: | ||||
|       summary: Called when the registrant needs to update its information with Ameriband. The does not generate a new NASID. | ||||
|       tags: | ||||
|         - Registration | ||||
|       operationId: updateRegistration | ||||
|       parameters: | ||||
|         - in: query | ||||
|           name: orgNASID | ||||
|           schema: | ||||
|             type: string | ||||
|           required: true | ||||
|           example: | ||||
|             This is the orgNASID returned during registration. | ||||
|       requestBody: | ||||
|         required: true | ||||
|         content: | ||||
|           application/json: | ||||
|             schema: | ||||
|               $ref: '#/components/schemas/RegistrationRequest' | ||||
|       responses: | ||||
|         200: | ||||
|           description: Succesfully found the information based on the orgNASID | ||||
|           content: | ||||
|             application/json: | ||||
|               schema: | ||||
|                 $ref: '#/components/schemas/RegistrationResponse' | ||||
|         400: | ||||
|           $ref: '#/components/responses/BadRequest' | ||||
|         403: | ||||
|           $ref: '#/components/responses/Unauthorized' | ||||
|         404: | ||||
|           $ref: '#/components/responses/NotFound' | ||||
|  | ||||
|     delete: | ||||
|       tags: | ||||
|         - Registration | ||||
|       summary: When a registrant wants to terminate a relationship with Ameriband. Ameriband should also delete all information from the registrant | ||||
|       operationId: deleteRegistration | ||||
|       parameters: | ||||
|         - in: query | ||||
|           name: orgNASID | ||||
|           schema: | ||||
|             type: string | ||||
|           required: true | ||||
|           example: | ||||
|             This is the orgNASID returned during registration. | ||||
|       responses: | ||||
|         204: | ||||
|           $ref: '#/components/responses/Success' | ||||
|         403: | ||||
|           $ref: '#/components/responses/Unauthorized' | ||||
|         404: | ||||
|           $ref: '#/components/responses/NotFound' | ||||
| @@ -815,6 +815,17 @@ components: | ||||
|           type: string | ||||
|           minLength: 2 | ||||
|           maxLength: 2 | ||||
|         imported: | ||||
|           type: integer | ||||
|           format: int64 | ||||
|         connected: | ||||
|           type: integer | ||||
|           format: int64 | ||||
|         platform: | ||||
|           type: string | ||||
|           enum: | ||||
|             - AP | ||||
|             - SWITCH | ||||
|  | ||||
|     VenueDeviceList: | ||||
|       type: object | ||||
| @@ -1220,11 +1231,54 @@ components: | ||||
|           items: | ||||
|             $ref: '#/components/schemas/SubscriberDevice' | ||||
|  | ||||
|     ConfigurationOverride: | ||||
|       type: object | ||||
|       properties: | ||||
|         source: | ||||
|           type: string | ||||
|         reason: | ||||
|           type: string | ||||
|         parameterName: | ||||
|           type: string | ||||
|         parameterType: | ||||
|           enum: | ||||
|             - string | ||||
|             - integer | ||||
|             - boolean | ||||
|         parameterValue: | ||||
|           type: string | ||||
|         modified: | ||||
|           type: integer | ||||
|           format: int64 | ||||
|  | ||||
|     ConfigurationOverrideList: | ||||
|       type: object | ||||
|       properties: | ||||
|         serialNumber: | ||||
|           type: string | ||||
|         managementPolicy: | ||||
|           type: string | ||||
|           format: uuid | ||||
|         overrides: | ||||
|           type: array | ||||
|           items: | ||||
|             $ref: '#/components/schemas/ConfigurationOverride' | ||||
|  | ||||
|     ######################################################################################### | ||||
|     ## | ||||
|     ## These are endpoints that all services in the OPenWiFI stack must provide | ||||
|     ## | ||||
|     ######################################################################################### | ||||
|     ExtraSystemConfiguration: | ||||
|       type: array | ||||
|       items: | ||||
|         type: object | ||||
|         properties: | ||||
|           parameterName: | ||||
|             type: string | ||||
|           parameterValue: | ||||
|             type: string | ||||
|  | ||||
|     AnyPayload: | ||||
|       type: object | ||||
|       properties: | ||||
| @@ -1288,12 +1342,6 @@ components: | ||||
|             - $ref: '#/components/schemas/StringList' | ||||
|             - $ref: '#/components/schemas/TagValuePairList' | ||||
|  | ||||
|     SystemCommandResults: | ||||
|       type: object | ||||
|       oneOf: | ||||
|         - $ref: '#/components/schemas/StringList' | ||||
|         - $ref: '#/components/schemas/TagValuePairList' | ||||
|  | ||||
|     NoteInfo: | ||||
|       type: object | ||||
|       properties: | ||||
| @@ -1333,6 +1381,33 @@ components: | ||||
|                 type: integer | ||||
|                 format: int64 | ||||
|  | ||||
|     SystemResources: | ||||
|       type: object | ||||
|       properties: | ||||
|         numberOfFileDescriptors: | ||||
|           type: integer | ||||
|           format: int64 | ||||
|         currRealMem: | ||||
|           type: integer | ||||
|           format: int64 | ||||
|         peakRealMem: | ||||
|           type: integer | ||||
|           format: int64 | ||||
|         currVirtMem: | ||||
|           type: integer | ||||
|           format: int64 | ||||
|         peakVirtMem: | ||||
|           type: integer | ||||
|           format: int64 | ||||
|  | ||||
|     SystemCommandResults: | ||||
|       type: object | ||||
|       oneOf: | ||||
|         - $ref: '#/components/schemas/SystemResources' | ||||
|         - $ref: '#/components/schemas/SystemInfoResults' | ||||
|         - $ref: '#/components/schemas/StringList' | ||||
|         - $ref: '#/components/schemas/TagValuePairList' | ||||
|  | ||||
|     Dashboard: | ||||
|       type: object | ||||
|       properties: | ||||
| @@ -2023,19 +2098,12 @@ paths: | ||||
|             default: false | ||||
|           required: false | ||||
|         - in: query | ||||
|           description: return the list of devices under RRM | ||||
|           description: return the list of devices for a subscriber | ||||
|           name: subscriber | ||||
|           schema: | ||||
|             type: string | ||||
|             format: uuid | ||||
|           required: false | ||||
|         - in: query | ||||
|           description: return RRM settings for a specific device | ||||
|           name: rrmSettings | ||||
|           schema: | ||||
|             type: boolean | ||||
|             default: false | ||||
|           required: false | ||||
|         - in: query | ||||
|           description: return the resolved configuration for a specific device | ||||
|           name:   resolveConfig | ||||
| @@ -2101,6 +2169,13 @@ paths: | ||||
|             type: string | ||||
|             format: uuid | ||||
|           required: false | ||||
|         - in: query | ||||
|           description: return RRM settings for a specific device | ||||
|           name: rrmSettings | ||||
|           schema: | ||||
|             type: boolean | ||||
|             default: false | ||||
|           required: false | ||||
|       responses: | ||||
|         200: | ||||
|           description: Succesful retrieve configuratiopn or part of the configuration | ||||
| @@ -2211,6 +2286,94 @@ paths: | ||||
|         404: | ||||
|           $ref: '#/components/responses/NotFound' | ||||
|  | ||||
|   /configurationOverrides/{serialNumber}: | ||||
|     get: | ||||
|       tags: | ||||
|         - Configuration Overrides | ||||
|       operationId: getConfigurationOverrides | ||||
|       summary: retrieve a list of configuration overrides for a given device | ||||
|       parameters: | ||||
|         - in: path | ||||
|           name: serialNumber | ||||
|           schema: | ||||
|             type: string | ||||
|           required: true | ||||
|       responses: | ||||
|         200: | ||||
|           description: Return a list of configuration overrides. | ||||
|           content: | ||||
|             application/json: | ||||
|               schema: | ||||
|                 $ref: '#/components/schemas/ConfigurationOverrideList' | ||||
|         400: | ||||
|           $ref: '#/components/responses/BadRequest' | ||||
|         403: | ||||
|           $ref: '#/components/responses/Unauthorized' | ||||
|         404: | ||||
|           $ref: '#/components/responses/NotFound' | ||||
|     delete: | ||||
|       tags: | ||||
|         - Configuration Overrides | ||||
|       operationId: deleteConfigurationOverrides | ||||
|       summary: delete all configuration overrides for a given device from a given source | ||||
|       parameters: | ||||
|         - in: path | ||||
|           name: serialNumber | ||||
|           schema: | ||||
|             type: string | ||||
|           required: true | ||||
|         - in: query | ||||
|           name: source | ||||
|           schema: | ||||
|             type: string | ||||
|           required: true | ||||
|       responses: | ||||
|         200: | ||||
|           $ref: '#/components/responses/Success' | ||||
|         400: | ||||
|           $ref: '#/components/responses/BadRequest' | ||||
|         403: | ||||
|           $ref: '#/components/responses/Unauthorized' | ||||
|         404: | ||||
|           $ref: '#/components/responses/NotFound' | ||||
|     put: | ||||
|       tags: | ||||
|         - Configuration Overrides | ||||
|       operationId: modifyConfigurationOverrides | ||||
|       summary: modify configuration overrides for a given device for a given source | ||||
|       parameters: | ||||
|         - in: path | ||||
|           name: serialNumber | ||||
|           schema: | ||||
|             type: string | ||||
|           required: true | ||||
|         - in: query | ||||
|           name: source | ||||
|           schema: | ||||
|             type: string | ||||
|           required: true | ||||
|       requestBody: | ||||
|         description: Information used to modify the override list | ||||
|         content: | ||||
|           application/json: | ||||
|             schema: | ||||
|               $ref: '#/components/schemas/ConfigurationOverrideList' | ||||
|       responses: | ||||
|         200: | ||||
|           description: Return the modified configuration overrides. | ||||
|           content: | ||||
|             application/json: | ||||
|               schema: | ||||
|                 $ref: '#/components/schemas/ConfigurationOverrideList' | ||||
|         400: | ||||
|           $ref: '#/components/responses/BadRequest' | ||||
|         403: | ||||
|           $ref: '#/components/responses/Unauthorized' | ||||
|         404: | ||||
|           $ref: '#/components/responses/NotFound' | ||||
|  | ||||
|  | ||||
|  | ||||
|   /venue: | ||||
|     get: | ||||
|       tags: | ||||
| @@ -2285,6 +2448,14 @@ paths: | ||||
|             type: boolean | ||||
|             default: false | ||||
|           required: false | ||||
|         - in: query | ||||
|           description: list venues that use a specific RRM vendor | ||||
|           name: RRMvendor | ||||
|           schema: | ||||
|             type: string | ||||
|             example: | ||||
|               - this is the shortname of the RRM vendor | ||||
|           required: false | ||||
|       responses: | ||||
|         200: | ||||
|           description: Return a list of venues. | ||||
| @@ -2403,6 +2574,17 @@ paths: | ||||
|             type: boolean | ||||
|             default: false | ||||
|           required: false | ||||
|         - in: query | ||||
|           name: revisionsAvailable | ||||
|           schema: | ||||
|             type: boolean | ||||
|             default: false | ||||
|           required: false | ||||
|         - in: query | ||||
|           name: revision | ||||
|           schema: | ||||
|             type: string | ||||
|           required: false | ||||
|       requestBody: | ||||
|         description: Information used to modify the new venue | ||||
|         content: | ||||
| @@ -3069,6 +3251,15 @@ paths: | ||||
|           schema: | ||||
|             type: boolean | ||||
|           required: false | ||||
|         - in: query | ||||
|           name: deviceType | ||||
|           schema: | ||||
|             type: string | ||||
|             enum: | ||||
|               - AP | ||||
|               - SWITCH | ||||
|           required: false | ||||
|           default: AP | ||||
|       requestBody: | ||||
|         description: Information used to create the new entity | ||||
|         content: | ||||
| @@ -3097,6 +3288,15 @@ paths: | ||||
|             format: uuid | ||||
|             example: When modifying the root entity, the uuid 0000-0000-0000 must be entered. | ||||
|           required: true | ||||
|         - in: query | ||||
|           name: deviceType | ||||
|           schema: | ||||
|             type: string | ||||
|             enum: | ||||
|               - AP | ||||
|               - SWITCH | ||||
|           required: false | ||||
|           default: AP | ||||
|       requestBody: | ||||
|         description: Information used to modify the new entity | ||||
|         content: | ||||
| @@ -4273,15 +4473,75 @@ paths: | ||||
|             type: string | ||||
|             enum: | ||||
|               - info | ||||
|               - extraConfiguration | ||||
|               - resources | ||||
|           required: true | ||||
|       responses: | ||||
|         200: | ||||
|           description: Successful command execution | ||||
|           content: | ||||
|             application/json: | ||||
|               schema: | ||||
|                 oneOf: | ||||
|                   - $ref: '#/components/schemas/SystemInfoResults' | ||||
|           $ref: '#/components/schemas/SystemCommandResults' | ||||
|         403: | ||||
|           $ref: '#/components/responses/Unauthorized' | ||||
|         404: | ||||
|           $ref: '#/components/responses/NotFound' | ||||
|  | ||||
|   /systemConfiguration: | ||||
|     get: | ||||
|       tags: | ||||
|         - SystemConfiguration | ||||
|       summary: Retrieve system configuration items | ||||
|       operationId: getSystemConfiguration | ||||
|       parameters: | ||||
|         - in: query | ||||
|           description: Which parameters you want to retrieve | ||||
|           name: entries | ||||
|           schema: | ||||
|             type: string | ||||
|             example: | ||||
|               - element1 | ||||
|               - element1,element2,element3 | ||||
|           required: false | ||||
|       responses: | ||||
|         200: | ||||
|           description: List of configuration elements | ||||
|           content: | ||||
|             application/json: | ||||
|               schema: | ||||
|                 type: array | ||||
|                 items: | ||||
|                   $ref: '#/components/schemas/ExtraSystemConfiguration' | ||||
|         403: | ||||
|           $ref: '#/components/responses/Unauthorized' | ||||
|         404: | ||||
|           $ref: '#/components/responses/NotFound' | ||||
|  | ||||
|     put: | ||||
|       tags: | ||||
|         - SystemConfiguration | ||||
|       summary: Set some or all system configuration | ||||
|       operationId: setSystemConfiguration | ||||
|       requestBody: | ||||
|         content: | ||||
|           application/json: | ||||
|             schema: | ||||
|               $ref: '#/components/schemas/ExtraSystemConfiguration' | ||||
|  | ||||
|       responses: | ||||
|         200: | ||||
|           $ref: '#/components/schemas/ExtraSystemConfiguration' | ||||
|         403: | ||||
|           $ref: '#/components/responses/Unauthorized' | ||||
|         404: | ||||
|           $ref: '#/components/responses/NotFound' | ||||
|  | ||||
|     delete: | ||||
|       tags: | ||||
|         - SystemConfiguration | ||||
|       summary: Delete all additional system configuration | ||||
|       operationId: deleteSystemConfiguration | ||||
|  | ||||
|       responses: | ||||
|         200: | ||||
|           $ref: '#/components/responses/Success' | ||||
|         403: | ||||
|           $ref: '#/components/responses/Unauthorized' | ||||
|         404: | ||||
|   | ||||
							
								
								
									
										342
									
								
								openapi/radius_endpoints.yaml
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,342 @@ | ||||
| openapi: 3.0.1 | ||||
| info: | ||||
|   title: OpenWiFi RADIUS Resource Model | ||||
|   description: Definitions and APIs to manage RADIUS Resources. | ||||
|   version: 1.0.0 | ||||
|   license: | ||||
|     name: BSD3 | ||||
|     url: https://github.com/Telecominfraproject/wlan-cloud-ucentralgw/blob/master/LICENSE | ||||
|  | ||||
| servers: | ||||
|   - url: 'https://localhost:16005/api/v1' | ||||
|  | ||||
| security: | ||||
|   - bearerAuth: [] | ||||
|   - ApiKeyAuth: [] | ||||
|  | ||||
| components: | ||||
|   securitySchemes: | ||||
|     ApiKeyAuth: | ||||
|       type: apiKey | ||||
|       in: header | ||||
|       name: X-API-KEY | ||||
|     bearerAuth: | ||||
|       type: http | ||||
|       scheme: bearer | ||||
|       bearerFormat: JWT | ||||
|  | ||||
|   responses: | ||||
|     NotFound: | ||||
|       $ref: 'https://github.com/Telecominfraproject/wlan-cloud-ucentralsec/blob/main/openpapi/owsec.yaml#/components/responses/NotFound' | ||||
|     Unauthorized: | ||||
|       $ref: 'https://github.com/Telecominfraproject/wlan-cloud-ucentralsec/blob/main/openpapi/owsec.yaml#/components/responses/Unauthorized' | ||||
|     Success: | ||||
|       $ref: 'https://github.com/Telecominfraproject/wlan-cloud-ucentralsec/blob/main/openpapi/owsec.yaml#/components/responses/Success' | ||||
|     BadRequest: | ||||
|       $ref: 'https://github.com/Telecominfraproject/wlan-cloud-ucentralsec/blob/main/openpapi/owsec.yaml#/components/responses/BadRequest' | ||||
|  | ||||
|   schemas: | ||||
|  | ||||
|     RADIUSServer: | ||||
|       type: object | ||||
|       properties: | ||||
|         Hostname: | ||||
|           type: string | ||||
|         IP: | ||||
|           type: string | ||||
|         Port: | ||||
|           type: integer | ||||
|           format: int32 | ||||
|         Secret: | ||||
|           type: string | ||||
|  | ||||
|     RADIUSEndPointRadiusType: | ||||
|       type: object | ||||
|       properties: | ||||
|         Authentication: | ||||
|           type: array | ||||
|           items: | ||||
|             $ref: '#/components/schemas/RADIUSServer' | ||||
|         Accounting: | ||||
|           type: array | ||||
|           items: | ||||
|             $ref: '#/components/schemas/RADIUSServer' | ||||
|         CoA: | ||||
|           type: array | ||||
|           items: | ||||
|             $ref: '#/components/schemas/RADIUSServer' | ||||
|         AccountingInterval: | ||||
|           type: integer | ||||
|           format: int32 | ||||
|  | ||||
|     RADIUSEndPointRadsecType: | ||||
|       type: object | ||||
|       properties: | ||||
|         Hostname: | ||||
|           type: string | ||||
|         IP: | ||||
|           type: string | ||||
|         Port: | ||||
|           type: integer | ||||
|         Secret: | ||||
|           type: string | ||||
|           default: radsec | ||||
|         UseOpenRoamingAccount: | ||||
|           type: string | ||||
|           format: uuid | ||||
|         Weight: | ||||
|           type: integer | ||||
|           format: int32 | ||||
|         Certificate: | ||||
|           type: string | ||||
|         PrivateKey: | ||||
|           type: string | ||||
|         CaCerts: | ||||
|           type: array | ||||
|           items: | ||||
|             type: string | ||||
|         AllowSelfSigned: | ||||
|           type: boolean | ||||
|           default: false | ||||
|  | ||||
|     RADIUSEndPoint: | ||||
|       type: object | ||||
|       properties: | ||||
|         allOf: | ||||
|           $ref: 'https://github.com/Telecominfraproject/wlan-cloud-owprov/blob/main/openpapi/owprov.yaml#/components/schemas/ObjectInfo' | ||||
|         Type: | ||||
|           type: string | ||||
|           enum: | ||||
|             - generic | ||||
|             - radsec | ||||
|             - globalreach | ||||
|             - orion | ||||
|           default: radius | ||||
|         RadsecServers: | ||||
|           type: array | ||||
|           items: | ||||
|             $ref: '#/components/schemas/RADIUSEndPointRadsecType' | ||||
|         RadiusServers: | ||||
|           type: array | ||||
|           items: | ||||
|             $ref: '#/components/schemas/RADIUSEndPointRadiusType' | ||||
|         PoolStrategy: | ||||
|           type: string | ||||
|           enum: | ||||
|             - round_robin | ||||
|             - weighted | ||||
|             - random | ||||
|           default: random | ||||
|         UseGWProxy: | ||||
|           type: boolean | ||||
|           default: true | ||||
|         Index: | ||||
|           type: string | ||||
|           example: | ||||
|             - 0.0.1.1: a ficticious IP address that should be between 0.0.1.1 and 0.0.2.254 | ||||
|         UsedBy: | ||||
|           type: array | ||||
|           description: list of configuration using this endpoint | ||||
|           items: | ||||
|             type: string | ||||
|             format: uuid | ||||
|         NasIdentifier: | ||||
|           type: string | ||||
|         AccountingInterval: | ||||
|           type: integer | ||||
|           format: int64 | ||||
|  | ||||
|     RADIUSEndpointUpdateStatus: | ||||
|       type: object | ||||
|       properties: | ||||
|         lastUpdate: | ||||
|           type: integer | ||||
|           format: int64 | ||||
|         lastConfigurationChange: | ||||
|           type: integer | ||||
|           format: int64 | ||||
|  | ||||
|  | ||||
|  | ||||
| paths: | ||||
|   /RADIUSEndPoints: | ||||
|     get: | ||||
|       tags: | ||||
|         - RADIUS Endpoints | ||||
|       operationId: getRADIUSEndPoints | ||||
|       summary: Retrieve the lists of RADIUSendPoints | ||||
|       parameters: | ||||
|         - in: query | ||||
|           description: Pagination start (starts at 1. If not specified, 1 is assumed) | ||||
|           name: offset | ||||
|           schema: | ||||
|             type: integer | ||||
|           required: false | ||||
|         - in: query | ||||
|           description: Maximum number of entries to return (if absent, no limit is assumed) | ||||
|           name: limit | ||||
|           schema: | ||||
|             type: integer | ||||
|           required: false | ||||
|         - in: query | ||||
|           description: return the number of certificates | ||||
|           name: countOnly | ||||
|           schema: | ||||
|             type: boolean | ||||
|           required: false | ||||
|         - in: query | ||||
|           description: return the last update time | ||||
|           name: currentStatus | ||||
|           schema: | ||||
|             type: boolean | ||||
|           required: false | ||||
|       responses: | ||||
|         200: | ||||
|           description: The list of endpoints | ||||
|           content: | ||||
|             application/json: | ||||
|               schema: | ||||
|                 oneOf: | ||||
|                   - type: array | ||||
|                     items: | ||||
|                       $ref: '#/components/schemas/RADIUSEndPoint' | ||||
|                   - $ref: '#/components/schemas/RADIUSEndpointUpdateStatus' | ||||
|         400: | ||||
|           $ref: '#/components/responses/BadRequest' | ||||
|         403: | ||||
|           $ref: '#/components/responses/Unauthorized' | ||||
|         404: | ||||
|           $ref: '#/components/responses/NotFound' | ||||
|  | ||||
|     put: | ||||
|       tags: | ||||
|         - RADIUS Endpoints | ||||
|       operationId: updateRADIUSEndpoints | ||||
|       summary: Force an Update to teh RADIUSendPoints in the controller | ||||
|       parameters: | ||||
|         - in: query | ||||
|           name: updateEndpoints | ||||
|           schema: | ||||
|             type: boolean | ||||
|           required: false | ||||
|       responses: | ||||
|         200: | ||||
|           description: The list of endpoints | ||||
|           content: | ||||
|             application/json: | ||||
|               schema: | ||||
|                 type: object | ||||
|                 properties: | ||||
|                   Error: | ||||
|                     type: string | ||||
|                   ErrorNum: | ||||
|                     type: integer | ||||
|         400: | ||||
|           $ref: '#/components/responses/BadRequest' | ||||
|         403: | ||||
|           $ref: '#/components/responses/Unauthorized' | ||||
|         404: | ||||
|           $ref: '#/components/responses/NotFound' | ||||
|  | ||||
|   /RADIUSEndPoint/{id}: | ||||
|     get: | ||||
|       tags: | ||||
|         - RADIUS Endpoints | ||||
|       operationId: getRADIUSEndPoint | ||||
|       summary: Retrieve a RADIUSendPoint | ||||
|       parameters: | ||||
|         - in: path | ||||
|           name: id | ||||
|           schema: | ||||
|             type: string | ||||
|             format: uuid | ||||
|           required: true | ||||
|       responses: | ||||
|         200: | ||||
|           description: The endpoint | ||||
|           content: | ||||
|             application/json: | ||||
|               schema: | ||||
|                 $ref: '#/components/schemas/RADIUSEndPoint' | ||||
|         400: | ||||
|           $ref: '#/components/responses/BadRequest' | ||||
|         403: | ||||
|           $ref: '#/components/responses/Unauthorized' | ||||
|         404: | ||||
|           $ref: '#/components/responses/NotFound' | ||||
|  | ||||
|     delete: | ||||
|       tags: | ||||
|         - RADIUS Endpoints | ||||
|       operationId: deleteRADIUSEndPoint | ||||
|       summary: Delete a RADIUSendPoint | ||||
|       parameters: | ||||
|         - in: path | ||||
|           name: id | ||||
|           schema: | ||||
|             type: string | ||||
|             format: uuid | ||||
|           required: true | ||||
|       responses: | ||||
|         200: | ||||
|           $ref: '#/components/responses/Success' | ||||
|         400: | ||||
|           $ref: '#/components/responses/BadRequest' | ||||
|         403: | ||||
|           $ref: '#/components/responses/Unauthorized' | ||||
|         404: | ||||
|           $ref: '#/components/responses/NotFound' | ||||
|  | ||||
|     post: | ||||
|       tags: | ||||
|         - RADIUS Endpoints | ||||
|       operationId: createRADIUSEndPoint | ||||
|       summary: Create a RADIUSendPoint | ||||
|       parameters: | ||||
|         - in: path | ||||
|           name: id | ||||
|           schema: | ||||
|             type: string | ||||
|             format: uuid | ||||
|           required: true | ||||
|       requestBody: | ||||
|         content: | ||||
|           application/json: | ||||
|             schema: | ||||
|               $ref: '#/components/schemas/RADIUSEndPoint' | ||||
|       responses: | ||||
|         200: | ||||
|           $ref: '#/components/schemas/RADIUSEndPoint' | ||||
|         400: | ||||
|           $ref: '#/components/responses/BadRequest' | ||||
|         403: | ||||
|           $ref: '#/components/responses/Unauthorized' | ||||
|         404: | ||||
|           $ref: '#/components/responses/NotFound' | ||||
|  | ||||
|     put: | ||||
|       tags: | ||||
|         - RADIUS Endpoints | ||||
|       operationId: modifyRADIUSEndPoint | ||||
|       summary: Modify a RADIUSendPoint | ||||
|       parameters: | ||||
|         - in: path | ||||
|           name: id | ||||
|           schema: | ||||
|             type: string | ||||
|             format: uuid | ||||
|           required: true | ||||
|       requestBody: | ||||
|         content: | ||||
|           application/json: | ||||
|             schema: | ||||
|               $ref: '#/components/schemas/RADIUSEndPoint' | ||||
|       responses: | ||||
|         200: | ||||
|           $ref: '#/components/schemas/RADIUSEndPoint' | ||||
|         400: | ||||
|           $ref: '#/components/responses/BadRequest' | ||||
|         403: | ||||
|           $ref: '#/components/responses/Unauthorized' | ||||
|         404: | ||||
|           $ref: '#/components/responses/NotFound' | ||||
| @@ -133,29 +133,32 @@ paths: | ||||
|       summary: Run a specific or default RRM algorithm. The UI user or CLI user will have the ability to run an algorithm on demand. | ||||
|       parameters: | ||||
|         - in: query | ||||
|           description: | ||||
|           description: The venue this algorithm should be run on. | ||||
|           name: venue | ||||
|           schema: | ||||
|             type: string | ||||
|             format: uuid | ||||
|           required: true | ||||
|         - in: query | ||||
|           description: Perform RRM without updating anything. This may be used by an admin to see what RRM would do. | ||||
|           name: mock | ||||
|           description: Perform RRM asynchronously, synchronously or in mockRun mode (without updating anything, this may be used by an admin to see what RRM would do). | ||||
|           name: mode | ||||
|           schema: | ||||
|             type: boolean | ||||
|             default: false | ||||
|             type: string | ||||
|             enum: [ async, sync, mockRun ] | ||||
|           required: false | ||||
|         - in: query | ||||
|           description: Specify the RRM algorithm to use. If omitted, select the default algorithm. | ||||
|           name: algorithm | ||||
|           schema: | ||||
|             type: string | ||||
|           required: false | ||||
|         - in: query | ||||
|           description: Specify the parameters to use with the RRM algorithm to use. If omitted, select the default parameters. | ||||
|           description: Specify the comma separated name=value parameters to use with the RRM algorithm to use. If omitted, select the default parameters. | ||||
|           name: parameters | ||||
|           schema: | ||||
|             type: string | ||||
|           required: false | ||||
|  | ||||
|       responses: | ||||
|         200: | ||||
|           description: Return the list of actions that were or would be performed. | ||||
|   | ||||
| @@ -37,10 +37,12 @@ openwifi.system.data = ${SYSTEM_DATA} | ||||
| openwifi.system.debug = false | ||||
| openwifi.system.uri.private = ${SYSTEM_URI_PRIVATE} | ||||
| openwifi.system.uri.public = ${SYSTEM_URI_PUBLIC} | ||||
| openwifi.system.commandchannel = /tmp/app.ucentralfms | ||||
| openwifi.system.commandchannel = /tmp/app.owprov | ||||
| openwifi.system.uri.ui = ${SYSTEM_URI_UI} | ||||
| openwifi.security.restapi.disable = ${SECURITY_RESTAPI_DISABLE} | ||||
|  | ||||
| rrm.providers = ${RRM_PROVIDERS} | ||||
|  | ||||
| ############################# | ||||
| # Generic information for all micro services | ||||
| ############################# | ||||
|   | ||||
							
								
								
									
										730
									
								
								src/APConfig.cpp
									
									
									
									
									
								
							
							
						
						| @@ -5,295 +5,459 @@ | ||||
| #include "APConfig.h" | ||||
| #include "StorageService.h" | ||||
|  | ||||
| #include "Poco/JSON/Parser.h" | ||||
| #include "Poco/StringTokenizer.h" | ||||
| #include "fmt/format.h" | ||||
|  | ||||
| #include <RadiusEndpointTypes/OrionWifi.h> | ||||
| #include <RadiusEndpointTypes/GlobalReach.h> | ||||
| #include <RadiusEndpointTypes/Radsec.h> | ||||
| #include <RadiusEndpointTypes/GenericRadius.h> | ||||
|  | ||||
| namespace OpenWifi { | ||||
|  | ||||
|     APConfig::APConfig(const std::string &SerialNumber, const std::string &DeviceType, Poco::Logger &L, bool Explain) | ||||
|         :   SerialNumber_(SerialNumber), | ||||
|             DeviceType_(DeviceType), | ||||
|             Logger_(L), | ||||
|             Explain_(Explain) | ||||
|     { | ||||
|     } | ||||
| 	APConfig::APConfig(const std::string &SerialNumber, const std::string &DeviceType, | ||||
| 					   Poco::Logger &L, bool Explain) | ||||
| 		: SerialNumber_(SerialNumber), DeviceType_(DeviceType), Logger_(L), Explain_(Explain) {} | ||||
|  | ||||
|     APConfig::APConfig(const std::string & SerialNumber, Poco::Logger & L) | ||||
|         :   SerialNumber_(SerialNumber), | ||||
|             Logger_(L) | ||||
|     { | ||||
|         Explain_ = false; | ||||
|         Sub_ = true; | ||||
|     } | ||||
| 	APConfig::APConfig(const std::string &SerialNumber, Poco::Logger &L) | ||||
| 		: SerialNumber_(SerialNumber), Logger_(L) { | ||||
| 		Explain_ = false; | ||||
| 		Sub_ = true; | ||||
| 	} | ||||
|  | ||||
|     bool APConfig::FindRadio(const std::string &Band, const Poco::JSON::Array::Ptr &Arr, Poco::JSON::Object::Ptr & Radio) { | ||||
|         for(const auto &i:*Arr) { | ||||
|             auto R = i.extract<Poco::JSON::Object::Ptr>(); | ||||
|             if(R->has("band") && R->get("band").toString()==Band) { | ||||
|                 Radio = R; | ||||
|                 return true; | ||||
|             } | ||||
|         } | ||||
|         return false; | ||||
|     } | ||||
|  | ||||
|     bool APConfig::RemoveBand(const std::string &Band, const Poco::JSON::Array::Ptr &A_in,Poco::JSON::Array::Ptr &A_Out) { | ||||
|         for(const auto &i:*A_in) { | ||||
|             auto R = i.extract<Poco::JSON::Object::Ptr>(); | ||||
|             if(R->has("band") && R->get("band").toString()==Band) { | ||||
|             } else { | ||||
|                 A_Out->add(i); | ||||
|             } | ||||
|         } | ||||
|         return false; | ||||
|     } | ||||
|  | ||||
|  | ||||
|     [[maybe_unused ]] static void ShowJSON([[maybe_unused]] const char *S, [[maybe_unused]] const Poco::JSON::Object::Ptr &Obj) { | ||||
|         /* | ||||
|         std::stringstream O; | ||||
|         Poco::JSON::Stringifier::stringify(Obj,O); | ||||
|         std::cout << S << ":" << std::endl; | ||||
|         std::cout << ">>>" << std::endl << O.str() << std::endl << "<<<" << std::endl; | ||||
|          */ | ||||
|     } | ||||
|  | ||||
|     bool APConfig::ReplaceVariablesInObject( const Poco::JSON::Object::Ptr & Original, Poco::JSON::Object::Ptr & Result) { | ||||
|         // get all the names and expand | ||||
|         auto Names = Original->getNames(); | ||||
|         for(const auto &i:Names) { | ||||
|             if(i=="__variableBlock") { | ||||
|                 if(Original->isArray(i)) { | ||||
|                     auto UUIDs = Original->getArray(i); | ||||
|                     for(const auto &uuid:*UUIDs) { | ||||
|                         ProvObjects::VariableBlock  VB; | ||||
|                         if(StorageService()->VariablesDB().GetRecord("id", uuid, VB)) { | ||||
|                             for(const auto &var:VB.variables) { | ||||
|                                 Poco::JSON::Parser P; | ||||
|                                 auto VariableBlockInfo = P.parse(var.value).extract<Poco::JSON::Object::Ptr>(); | ||||
|                                 auto VarNames = VariableBlockInfo->getNames(); | ||||
|                                 for(const auto &j:VarNames) { | ||||
|                                     Result->set(j,VariableBlockInfo->get(j)); | ||||
|                                 } | ||||
|                             } | ||||
|                         } | ||||
|                     } | ||||
|                 } | ||||
|             } else if(Original->isArray(i)) { | ||||
|                 auto Arr = Poco::makeShared<Poco::JSON::Array>(); | ||||
|                 auto Obj = Original->getArray(i); | ||||
|                 ReplaceVariablesInArray(Obj,Arr); | ||||
|                 Result->set(i,Arr); | ||||
|             } else if (Original->isObject(i)) { | ||||
|                 auto Expanded = Poco::makeShared<Poco::JSON::Object>(); | ||||
|                 auto Obj = Original->getObject(i); | ||||
|                 ReplaceVariablesInObject(Obj,Expanded); | ||||
|                 Result->set(i,Expanded); | ||||
|             } else { | ||||
|                 Result->set(i,Original->get(i)); | ||||
|             } | ||||
|         } | ||||
|         return true; | ||||
|     } | ||||
|  | ||||
|     bool APConfig::ReplaceVariablesInArray( const Poco::JSON::Array::Ptr & Original, Poco::JSON::Array::Ptr & ResultArray) { | ||||
|  | ||||
|         for(const auto &element:*Original) { | ||||
|  | ||||
|             if(element.isArray()) { | ||||
|                 auto Expanded = Poco::makeShared<Poco::JSON::Array>(); | ||||
|                 const auto & Object = element.extract<Poco::JSON::Array::Ptr>(); | ||||
|                 ReplaceVariablesInArray(Object,Expanded); | ||||
|                 ResultArray->add(Expanded); | ||||
|             } else if(element.isStruct()) { | ||||
|                 auto Expanded = Poco::makeShared<Poco::JSON::Object>(); | ||||
|                 const auto & Object = element.extract<Poco::JSON::Object::Ptr>(); | ||||
|                 ReplaceVariablesInObject(Object,Expanded); | ||||
|                 ResultArray->add(Expanded); | ||||
|             } else if(  element.isString() || | ||||
|                         element.isNumeric() || | ||||
|                         element.isBoolean() || | ||||
|                         element.isInteger() || | ||||
|                         element.isSigned() ) { | ||||
|                 ResultArray->add(element); | ||||
|             } else { | ||||
|                 auto Expanded = Poco::makeShared<Poco::JSON::Object>(); | ||||
|                 const auto & Object = element.extract<Poco::JSON::Object::Ptr>(); | ||||
|                 ReplaceVariablesInObject(Object,Expanded); | ||||
|                 ResultArray->add(Expanded); | ||||
|             } | ||||
|         } | ||||
|         return true; | ||||
|     } | ||||
|  | ||||
|     bool APConfig::Get(Poco::JSON::Object::Ptr & Configuration) { | ||||
|         if(Config_.empty()) { | ||||
|             Explanation_.clear(); | ||||
|             try { | ||||
|                 if(!Sub_) { | ||||
|                     ProvObjects::InventoryTag D; | ||||
|                     if (StorageService()->InventoryDB().GetRecord("serialNumber", SerialNumber_, D)) { | ||||
|                         if (!D.deviceConfiguration.empty()) { | ||||
|                             AddConfiguration(D.deviceConfiguration); | ||||
|                         } | ||||
|                         if (!D.entity.empty()) { | ||||
|                             AddEntityConfig(D.entity); | ||||
|                         } else if (!D.venue.empty()) { | ||||
|                             AddVenueConfig(D.venue); | ||||
|                         } | ||||
|                     } | ||||
|                 } else { | ||||
|                     ProvObjects::SubscriberDevice D; | ||||
|                     if (StorageService()->SubscriberDeviceDB().GetRecord("serialNumber", SerialNumber_, D)) { | ||||
|                         if (!D.configuration.empty()) { | ||||
|                             AddConfiguration(D.configuration); | ||||
|                         } | ||||
|                     } | ||||
|                 } | ||||
|                 //  Now we have all the config we need. | ||||
|             } catch (const Poco::Exception &E ) { | ||||
|                 Logger_.log(E); | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         try { | ||||
|             std::set<std::string> Sections; | ||||
|             for (const auto &i: Config_) { | ||||
|                 Poco::JSON::Parser P; | ||||
|                 auto O = P.parse(i.element.configuration).extract<Poco::JSON::Object::Ptr>(); | ||||
|                 auto Names = O->getNames(); | ||||
|                 for (const auto &SectionName: Names) { | ||||
|                     auto InsertInfo = Sections.insert(SectionName); | ||||
|                     if (InsertInfo.second) { | ||||
|                         if (O->isArray(SectionName)) { | ||||
|                             auto OriginalArray = O->getArray(SectionName); | ||||
|                             if (Explain_) { | ||||
|                                 Poco::JSON::Object ExObj; | ||||
|                                 ExObj.set("from-uuid", i.info.id); | ||||
|                                 ExObj.set("from-name", i.info.name); | ||||
|                                 ExObj.set("action", "added"); | ||||
|                                 ExObj.set("element", OriginalArray); | ||||
|                                 Explanation_.add(ExObj); | ||||
|                             } | ||||
|                             auto ExpandedArray = Poco::makeShared<Poco::JSON::Array>(); | ||||
|                             ReplaceVariablesInArray(OriginalArray, ExpandedArray); | ||||
|                             Configuration->set(SectionName, ExpandedArray); | ||||
|                         } else if (O->isObject(SectionName)) { | ||||
|                             auto OriginalSection = O->get(SectionName).extract<Poco::JSON::Object::Ptr>(); | ||||
|                             if (Explain_) { | ||||
|                                 Poco::JSON::Object ExObj; | ||||
|                                 ExObj.set("from-uuid", i.info.id); | ||||
|                                 ExObj.set("from-name", i.info.name); | ||||
|                                 ExObj.set("action", "added"); | ||||
|                                 ExObj.set("element", OriginalSection); | ||||
|                                 Explanation_.add(ExObj); | ||||
|                             } | ||||
|                             auto ExpandedSection = Poco::makeShared<Poco::JSON::Object>(); | ||||
|                             ReplaceVariablesInObject(OriginalSection, ExpandedSection); | ||||
|                             Configuration->set(SectionName, ExpandedSection); | ||||
|                         } else { | ||||
|                             std::cout << " --- unknown element type --- " << O->get(SectionName).toString() | ||||
|                                       << std::endl; | ||||
|                         } | ||||
|                     } else { | ||||
|                         if (Explain_) { | ||||
|                             Poco::JSON::Object ExObj; | ||||
|                             ExObj.set("from-uuid", i.info.id); | ||||
|                             ExObj.set("from-name", i.info.name); | ||||
|                             ExObj.set("action", "ignored"); | ||||
|                             ExObj.set("reason", "weight insufficient"); | ||||
|                             ExObj.set("element", O->get(SectionName)); | ||||
|                             Explanation_.add(ExObj); | ||||
|                         } | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
|         } catch (...) { | ||||
|  | ||||
|         } | ||||
|         return !Config_.empty(); | ||||
|     } | ||||
|  | ||||
|     static bool DeviceTypeMatch(const std::string &DeviceType, const Types::StringVec & Types) { | ||||
|         for(const auto &i:Types) { | ||||
|             if(i=="*" || Poco::icompare(DeviceType,i)==0) | ||||
|                 return true; | ||||
|         } | ||||
|         return false; | ||||
|     } | ||||
|  | ||||
|     void APConfig::AddConfiguration(const ProvObjects::DeviceConfigurationElementVec &Elements) { | ||||
|         for(const auto &i:Elements) { | ||||
|             if(i.weight==0) { | ||||
|                 VerboseElement  VE{ .element = i, .info = ProvObjects::ObjectInfo{} }; | ||||
|                 Config_.push_back(VE); | ||||
|             } else { | ||||
|                 // we need to insert after everything bigger or equal | ||||
|                 auto Hint = std::lower_bound(Config_.cbegin(),Config_.cend(),i.weight, | ||||
|                                              [](const VerboseElement &Elem, uint64_t Value) { | ||||
|                                                  return Elem.element.weight>=Value; }); | ||||
|                 VerboseElement  VE{ .element = i, .info = ProvObjects::ObjectInfo{}}; | ||||
|                 Config_.insert(Hint,VE); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     void APConfig::AddConfiguration(const Types::UUIDvec_t &UUIDs) { | ||||
|         for(const auto &i:UUIDs) | ||||
|             AddConfiguration(i); | ||||
|     } | ||||
|  | ||||
|     void APConfig::AddConfiguration(const std::string &UUID) { | ||||
|         if(UUID.empty()) | ||||
|             return; | ||||
|  | ||||
|         ProvObjects::DeviceConfiguration    Config; | ||||
|         if(StorageService()->ConfigurationDB().GetRecord("id", UUID, Config)) { | ||||
|             if(!Config.configuration.empty()) { | ||||
|                 if(DeviceTypeMatch(DeviceType_,Config.deviceTypes)) { | ||||
|                     for(const auto &i:Config.configuration) { | ||||
|                         if(i.weight==0) { | ||||
|                             VerboseElement  VE{ .element = i, .info = Config.info}; | ||||
|                             Config_.push_back(VE); | ||||
|                         } else { | ||||
|                             // we need to insert after everything bigger or equal | ||||
|                             auto Hint = std::lower_bound(Config_.cbegin(),Config_.cend(),i.weight, | ||||
|                                                          [](const VerboseElement &Elem, uint64_t Value) { | ||||
|                                 return Elem.element.weight>=Value; }); | ||||
|                             VerboseElement  VE{ .element = i, .info = Config.info}; | ||||
|                             Config_.insert(Hint,VE); | ||||
|                         } | ||||
|                     } | ||||
|                 } else { | ||||
|                     Poco::JSON::Object  ExObj; | ||||
|                     ExObj.set("from-uuid", Config.info.id); | ||||
|                     ExObj.set("from-name",Config.info.name ); | ||||
|                     ExObj.set("action", "ignored"); | ||||
|                     ExObj.set("reason", "deviceType mismatch"); | ||||
|                     Explanation_.add(ExObj); | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     void APConfig::AddEntityConfig(const std::string &UUID) { | ||||
|         ProvObjects::Entity E; | ||||
|         if(StorageService()->EntityDB().GetRecord("id",UUID,E)) { | ||||
|             AddConfiguration(E.configurations); | ||||
|             if(!E.parent.empty()) { | ||||
|                 AddEntityConfig(E.parent); | ||||
| 	bool APConfig::FindRadio(const std::string &Band, const Poco::JSON::Array::Ptr &Arr, | ||||
| 							 Poco::JSON::Object::Ptr &Radio) { | ||||
| 		for (const auto &i : *Arr) { | ||||
| 			auto R = i.extract<Poco::JSON::Object::Ptr>(); | ||||
| 			if (R->has("band") && R->get("band").toString() == Band) { | ||||
| 				Radio = R; | ||||
| 				return true; | ||||
| 			} | ||||
| 		} | ||||
| 		return false; | ||||
| 	} | ||||
|  | ||||
| 	bool APConfig::RemoveBand(const std::string &Band, const Poco::JSON::Array::Ptr &A_in, | ||||
| 							  Poco::JSON::Array::Ptr &A_Out) { | ||||
| 		for (const auto &i : *A_in) { | ||||
| 			auto R = i.extract<Poco::JSON::Object::Ptr>(); | ||||
| 			if (R->has("band") && R->get("band").toString() == Band) { | ||||
| 			} else { | ||||
| 				A_Out->add(i); | ||||
| 			} | ||||
| 		} | ||||
| 		return false; | ||||
| 	} | ||||
|  | ||||
| 	[[maybe_unused]] static void ShowJSON([[maybe_unused]] const char *S, | ||||
| 										  [[maybe_unused]] const Poco::JSON::Object::Ptr &Obj) { | ||||
| 		/* | ||||
| 		std::stringstream O; | ||||
| 		Poco::JSON::Stringifier::stringify(Obj,O); | ||||
| 		std::cout << S << ":" << std::endl; | ||||
| 		std::cout << ">>>" << std::endl << O.str() << std::endl << "<<<" << std::endl; | ||||
| 		 */ | ||||
| 	} | ||||
|  | ||||
|     bool APConfig::InsertRadiusEndPoint(const ProvObjects::RADIUSEndPoint &RE, Poco::JSON::Object &Result) { | ||||
|         if(RE.UseGWProxy) { | ||||
|             Poco::JSON::Object  ServerSettings; | ||||
|             if (RE.Type == "orion") { | ||||
|                 return OpenRoaming_Orion()->Render(RE, SerialNumber_, Result); | ||||
|             } else if (RE.Type == "globalreach") { | ||||
|                 return OpenRoaming_GlobalReach()->Render(RE, SerialNumber_, Result); | ||||
|             } else if (RE.Type == "radsec") { | ||||
|                 return OpenRoaming_Radsec()->Render(RE, SerialNumber_, Result); | ||||
|             } else if (RE.Type == "generic") { | ||||
|                 return OpenRoaming_GenericRadius()->Render(RE, SerialNumber_, Result); | ||||
|             } | ||||
|             Result.set( "radius" , ServerSettings); | ||||
|         } else { | ||||
|             std::cout << "Radius proxy off" << RE.info.name << std::endl; | ||||
|         } | ||||
|         return false; | ||||
|     } | ||||
|  | ||||
|     void APConfig::AddVenueConfig(const std::string &UUID) { | ||||
|         ProvObjects::Venue V; | ||||
|         if(StorageService()->VenueDB().GetRecord("id",UUID,V)) { | ||||
|             AddConfiguration(V.configurations); | ||||
|             if(!V.entity.empty()) { | ||||
|                 AddEntityConfig(V.entity); | ||||
|             } else if(!V.parent.empty()) { | ||||
|                 AddVenueConfig(V.parent); | ||||
|             } | ||||
|         } else { | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 	void APConfig::ReplaceNestedVariables(const std::string uuid, Poco::JSON::Object &Result) { | ||||
| 		/* | ||||
| 		Helper method contains code previously in ReplaceVariablesinObject. | ||||
| 		Once the top-level variable is resolved, this will be called to resolve any | ||||
| 		variables nested within the top-level variable. | ||||
| 		*/ | ||||
| 		ProvObjects::VariableBlock VB; | ||||
| 		if (StorageService()->VariablesDB().GetRecord("id", uuid, VB)) { | ||||
| 			for (const auto &var: VB.variables) { | ||||
| 				Poco::JSON::Parser P; | ||||
| 				auto VariableBlockInfo = | ||||
| 					P.parse(var.value).extract<Poco::JSON::Object::Ptr>(); | ||||
| 				auto VarNames = VariableBlockInfo->getNames(); | ||||
| 				for (const auto &j: VarNames) { | ||||
| 					if(VariableBlockInfo->isArray(j)) { | ||||
| 						auto Elements = VariableBlockInfo->getArray(j); | ||||
| 						if(Elements->size()>0) { | ||||
| 							Poco::JSON::Array InnerArray; | ||||
| 							ReplaceVariablesInArray(*Elements, InnerArray); | ||||
| 							Result.set(j, InnerArray); | ||||
| 						} else { | ||||
| //                      	std::cout << "Empty Array!!!" << std::endl; | ||||
| 						} | ||||
| 					} else if(VariableBlockInfo->isObject(j)) { | ||||
| 						Poco::JSON::Object  InnerEval; | ||||
| 						auto O = VariableBlockInfo->getObject(j); | ||||
| 						ReplaceVariablesInObject(*O,InnerEval); | ||||
| 						Result.set(j, InnerEval); | ||||
| 					} else { | ||||
| 						Result.set(j, VariableBlockInfo->get(j)); | ||||
| 					} | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
|     bool APConfig::ReplaceVariablesInObject(const Poco::JSON::Object &Original, | ||||
| 											Poco::JSON::Object &Result) { | ||||
| 		// get all the names and expand | ||||
| 		auto Names = Original.getNames(); | ||||
| 		for (const auto &i : Names) { | ||||
|             if (i == "__variableBlock") { | ||||
|                 if (Original.isArray(i)) { | ||||
| 					/* | ||||
| 					E.g. of what the variable block would look like in an array: | ||||
| 					"ssids": [ | ||||
| 						{ | ||||
| 							"__variableBlock": [ | ||||
| 								"79c083d2-d496-4de0-8600-76a63556851b" | ||||
| 							] | ||||
| 						} | ||||
| 					] | ||||
| 					*/ | ||||
|                     auto UUIDs = Original.getArray(i); | ||||
|                     for (const std::string &uuid: *UUIDs) { | ||||
|                         ReplaceNestedVariables(uuid, Result); | ||||
| 					} | ||||
|                 } | ||||
| 				else { | ||||
| 					/* | ||||
| 					E.g. of what the variable block would look like replacing an entire json blob: | ||||
| 					"services" : { | ||||
| 						"__variableBlock": "ef8db4c0-f0ef-40d2-b676-c9c02ef39430" | ||||
| 					} | ||||
| 					*/ | ||||
| 					const std::string uuid = Original.get(i); | ||||
| 					ReplaceNestedVariables(uuid, Result); | ||||
| 				} | ||||
|             } else if (i == "__radiusEndpoint") { | ||||
|                 auto EndPointId = Original.get(i).toString(); | ||||
|                 ProvObjects::RADIUSEndPoint RE; | ||||
| //                std::cout << "ID->" << EndPointId << std::endl; | ||||
|                 if(StorageService()->RadiusEndpointDB().GetRecord("id",EndPointId,RE)) { | ||||
|                     InsertRadiusEndPoint(RE, Result); | ||||
|                 } else { | ||||
|                     poco_error(Logger_, fmt::format("RADIUS Endpoint {} could not be found. Please delete this configuration and recreate it.")); | ||||
|                     return false; | ||||
|                 } | ||||
| 			} else if (Original.isArray(i)) { | ||||
|                 Poco::JSON::Array Arr; | ||||
| 				auto Obj = Original.getArray(i); | ||||
|                 if(Obj->size()>0) { | ||||
|                     ReplaceVariablesInArray(*Obj, Arr); | ||||
|                     Result.set(i, Arr); | ||||
|                 } | ||||
| 			} else if (Original.isObject(i)) { | ||||
|                 Poco::JSON::Object Expanded; | ||||
| 				auto Obj = Original.getObject(i); | ||||
| 				ReplaceVariablesInObject(*Obj, Expanded); | ||||
| 				Result.set(i, Expanded); | ||||
| 			} else { | ||||
| 				Result.set(i, Original.get(i)); | ||||
| 			} | ||||
| 		} | ||||
| 		return true; | ||||
| 	} | ||||
|  | ||||
| 	bool APConfig::ReplaceVariablesInArray(const Poco::JSON::Array &Original, | ||||
| 										   Poco::JSON::Array &ResultArray) { | ||||
|  | ||||
| 		for (const auto &element : Original) { | ||||
| //            std::cout << element.toString() << std::endl; | ||||
| 			if (element.isArray()) { | ||||
|                 Poco::JSON::Array  Expanded; | ||||
| 				const auto Object = element.extract<Poco::JSON::Array::Ptr>(); | ||||
|                 if(Object->size()>0) { | ||||
|                     ReplaceVariablesInArray(*Object, Expanded); | ||||
|                     ResultArray.add(Expanded); | ||||
|                 } | ||||
| 			} else if (element.isStruct()) { | ||||
|                 Poco::JSON::Object  Expanded; | ||||
| 				const auto &Object = element.extract<Poco::JSON::Object::Ptr>(); | ||||
| 				ReplaceVariablesInObject(*Object, Expanded); | ||||
| 				ResultArray.add(Expanded); | ||||
| 			} else if (element.isString() || element.isNumeric() || element.isBoolean() || | ||||
| 					   element.isInteger() || element.isSigned()) { | ||||
| 				ResultArray.add(element); | ||||
| 			} else { | ||||
|                 Poco::JSON::Object  Expanded; | ||||
| 				const auto &Object = element.extract<Poco::JSON::Object::Ptr>(); | ||||
| 				ReplaceVariablesInObject(*Object, Expanded); | ||||
| 				ResultArray.add(Expanded); | ||||
| 			} | ||||
| 		} | ||||
| 		return true; | ||||
| 	} | ||||
|  | ||||
| 	bool APConfig::Get(Poco::JSON::Object::Ptr &Configuration) { | ||||
|  | ||||
| 		if (Config_.empty()) { | ||||
| 			Explanation_.clear(); | ||||
| 			try { | ||||
| 				if (!Sub_) { | ||||
| 					ProvObjects::InventoryTag D; | ||||
| 					if (StorageService()->InventoryDB().GetRecord("serialNumber", SerialNumber_, | ||||
| 																  D)) { | ||||
| 						if (!D.deviceConfiguration.empty()) { | ||||
| 							// std::cout << "Adding device specific configuration: " << D.deviceConfiguration.size() << std::endl; | ||||
| 							AddConfiguration(D.deviceConfiguration); | ||||
| 						} else { | ||||
| 							// std::cout << "No device specific configuration." << std::endl; | ||||
| 						} | ||||
| 						if (!D.entity.empty()) { | ||||
| 							AddEntityConfig(D.entity); | ||||
| 						} else if (!D.venue.empty()) { | ||||
| 							AddVenueConfig(D.venue); | ||||
| 						} | ||||
| 					} | ||||
| 				} else { | ||||
| 					ProvObjects::SubscriberDevice D; | ||||
| 					if (StorageService()->SubscriberDeviceDB().GetRecord("serialNumber", | ||||
| 																		 SerialNumber_, D)) { | ||||
| 						if (!D.configuration.empty()) { | ||||
| 							AddConfiguration(D.configuration); | ||||
| 						} | ||||
| 					} | ||||
| 				} | ||||
| 				//  Now we have all the config we need. | ||||
| 			} catch (const Poco::Exception &E) { | ||||
| 				Logger_.log(E); | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		try { | ||||
| 			std::set<std::string> Sections; | ||||
| 			for (const auto &i : Config_) { | ||||
| 				Poco::JSON::Parser P; | ||||
| 				auto O = P.parse(i.element.configuration).extract<Poco::JSON::Object::Ptr>(); | ||||
| 				auto Names = O->getNames(); | ||||
| 				for (const auto &SectionName : Names) { | ||||
| 					auto InsertInfo = Sections.insert(SectionName); | ||||
| 					if (InsertInfo.second) { | ||||
| 						if (O->isArray(SectionName)) { | ||||
| 							auto OriginalArray = O->getArray(SectionName); | ||||
| 							if (Explain_) { | ||||
| 								Poco::JSON::Object ExObj; | ||||
| 								ExObj.set("from-uuid", i.info.id); | ||||
| 								ExObj.set("from-name", i.info.name); | ||||
| 								ExObj.set("action", "added"); | ||||
| 								ExObj.set("element", OriginalArray); | ||||
| 								Explanation_.add(ExObj); | ||||
| 							} | ||||
|                             Poco::JSON::Array ExpandedArray; | ||||
| 							ReplaceVariablesInArray(*OriginalArray, ExpandedArray); | ||||
| 							Configuration->set(SectionName, ExpandedArray); | ||||
| 						} else if (O->isObject(SectionName)) { | ||||
| 							auto OriginalSection = | ||||
| 								O->get(SectionName).extract<Poco::JSON::Object::Ptr>(); | ||||
| 							if (Explain_) { | ||||
| 								Poco::JSON::Object ExObj; | ||||
| 								ExObj.set("from-uuid", i.info.id); | ||||
| 								ExObj.set("from-name", i.info.name); | ||||
| 								ExObj.set("action", "added"); | ||||
| 								ExObj.set("element", OriginalSection); | ||||
| 								Explanation_.add(ExObj); | ||||
| 							} | ||||
|                             Poco::JSON::Object ExpandedSection; | ||||
| 							ReplaceVariablesInObject(*OriginalSection, ExpandedSection); | ||||
| 							Configuration->set(SectionName, ExpandedSection); | ||||
| 						} else { | ||||
|                             poco_warning(Logger(), fmt::format("Unknown config element type: {}",O->get(SectionName).toString())); | ||||
| 						} | ||||
| 					} else { | ||||
| 						if (Explain_) { | ||||
| 							Poco::JSON::Object ExObj; | ||||
| 							ExObj.set("from-uuid", i.info.id); | ||||
| 							ExObj.set("from-name", i.info.name); | ||||
| 							ExObj.set("action", "ignored"); | ||||
| 							ExObj.set("reason", "weight insufficient"); | ||||
| 							ExObj.set("element", O->get(SectionName)); | ||||
| 							Explanation_.add(ExObj); | ||||
| 						} | ||||
| 					} | ||||
| 				} | ||||
| 			} | ||||
|  | ||||
| 			//  Apply overrides... | ||||
| 			ProvObjects::ConfigurationOverrideList COL; | ||||
| 			if (StorageService()->OverridesDB().GetRecord("serialNumber", SerialNumber_, COL)) { | ||||
| 				for (const auto &col : COL.overrides) { | ||||
| 					const auto Tokens = Poco::StringTokenizer(col.parameterName, "."); | ||||
| 					if (Tokens[0] == "radios" && Tokens.count() == 3) { | ||||
| 						std::uint64_t RadioIndex = std::strtoull(Tokens[1].c_str(), nullptr, 10); | ||||
| 						if (RadioIndex < MaximumPossibleRadios) { | ||||
| 							auto RadioArray = Configuration->getArray("radios"); | ||||
| 							if (RadioIndex < RadioArray->size()) { | ||||
| 								auto IndexedRadio = | ||||
| 									RadioArray->get(RadioIndex).extract<Poco::JSON::Object::Ptr>(); | ||||
| 								if (Tokens[2] == "tx-power") { | ||||
| 									IndexedRadio->set( | ||||
| 										"tx-power", | ||||
| 										std::strtoull(col.parameterValue.c_str(), nullptr, 10)); | ||||
| 									if (Explain_) { | ||||
| 										Poco::JSON::Object ExObj; | ||||
| 										ExObj.set("from-name", "overrides"); | ||||
| 										ExObj.set("override", col.parameterName); | ||||
| 										ExObj.set("source", col.source); | ||||
| 										ExObj.set("reason", col.reason); | ||||
| 										ExObj.set("value", col.parameterValue); | ||||
| 										Explanation_.add(ExObj); | ||||
| 									} | ||||
| 									RadioArray->set(RadioIndex, IndexedRadio); | ||||
| 									Configuration->set("radios", RadioArray); | ||||
| 								} else if (Tokens[2] == "channel") { | ||||
| 									if (col.parameterValue == "auto") { | ||||
| 										IndexedRadio->set("channel", "auto"); | ||||
| 									} else { | ||||
| 										IndexedRadio->set( | ||||
| 											"channel", | ||||
| 											std::strtoull(col.parameterValue.c_str(), nullptr, 10)); | ||||
| 									} | ||||
| 									// std::cout << "Setting channel in radio " << RadioIndex << std::endl; | ||||
| 									if (Explain_) { | ||||
| 										Poco::JSON::Object ExObj; | ||||
| 										ExObj.set("from-name", "overrides"); | ||||
| 										ExObj.set("override", col.parameterName); | ||||
| 										ExObj.set("source", col.source); | ||||
| 										ExObj.set("reason", col.reason); | ||||
| 										ExObj.set("value", col.parameterValue); | ||||
| 										Explanation_.add(ExObj); | ||||
| 									} | ||||
| 									RadioArray->set(RadioIndex, IndexedRadio); | ||||
| 									Configuration->set("radios", RadioArray); | ||||
| 								} else { | ||||
| 									poco_error( | ||||
| 										Logger(), | ||||
| 										fmt::format("{}: Unsupported override variable name {}", | ||||
| 													col.parameterName)); | ||||
| 								} | ||||
| 							} | ||||
| 						} else { | ||||
| 							poco_error(Logger(), fmt::format("{}: radio index out of range in {}", | ||||
| 															 col.parameterName)); | ||||
| 						} | ||||
| 					} else { | ||||
| 						poco_error(Logger(), | ||||
| 								   fmt::format("{}: Unsupported override variable name {}", | ||||
| 											   col.parameterName)); | ||||
| 					} | ||||
| 				} | ||||
| 			} | ||||
| 		} catch (...) { | ||||
| 		} | ||||
| 		return !Config_.empty(); | ||||
| 	} | ||||
|  | ||||
| 	static bool DeviceTypeMatch(const std::string &DeviceType, const Types::StringVec &Types) { | ||||
| 		for (const auto &i : Types) { | ||||
| 			if (i == "*" || Poco::icompare(DeviceType, i) == 0) | ||||
| 				return true; | ||||
| 		} | ||||
| 		return false; | ||||
| 	} | ||||
|  | ||||
| 	void APConfig::AddConfiguration(const ProvObjects::DeviceConfigurationElementVec &Elements) { | ||||
| 		for (const auto &i : Elements) { | ||||
| 			if (i.weight == 0) { | ||||
| 				VerboseElement VE{.element = i, .info = ProvObjects::ObjectInfo{}}; | ||||
| 				Config_.push_back(VE); | ||||
| 			} else { | ||||
| 				// we need to insert after everything bigger or equal | ||||
| 				auto Hint = std::lower_bound(Config_.cbegin(), Config_.cend(), i.weight, | ||||
| 											 [](const VerboseElement &Elem, uint64_t Value) { | ||||
| 												 return Elem.element.weight >= Value; | ||||
| 											 }); | ||||
| 				VerboseElement VE{.element = i, .info = ProvObjects::ObjectInfo{}}; | ||||
| 				Config_.insert(Hint, VE); | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	void APConfig::AddConfiguration(const Types::UUIDvec_t &UUIDs) { | ||||
| 		for (const auto &i : UUIDs) | ||||
| 			AddConfiguration(i); | ||||
| 	} | ||||
|  | ||||
| 	void APConfig::AddConfiguration(const std::string &UUID) { | ||||
| 		if (UUID.empty()) | ||||
| 			return; | ||||
|  | ||||
| 		ProvObjects::DeviceConfiguration Config; | ||||
| 		if (StorageService()->ConfigurationDB().GetRecord("id", UUID, Config)) { | ||||
| //            std::cout << Config.info.name << ":" << Config.configuration.size() << std::endl; | ||||
| 			if (!Config.configuration.empty()) { | ||||
| 				if (DeviceTypeMatch(DeviceType_, Config.deviceTypes)) { | ||||
| 					for (const auto &i : Config.configuration) { | ||||
| 						if (i.weight == 0) { | ||||
| 							VerboseElement VE{.element = i, .info = Config.info}; | ||||
| 							Config_.push_back(VE); | ||||
| 						} else { | ||||
| 							// we need to insert after everything bigger or equal | ||||
| 							auto Hint = | ||||
| 								std::lower_bound(Config_.cbegin(), Config_.cend(), i.weight, | ||||
| 												 [](const VerboseElement &Elem, uint64_t Value) { | ||||
| 													 return Elem.element.weight >= Value; | ||||
| 												 }); | ||||
| 							VerboseElement VE{.element = i, .info = Config.info}; | ||||
| 							Config_.insert(Hint, VE); | ||||
| 						} | ||||
| 					} | ||||
| 				} else { | ||||
| 					Poco::JSON::Object ExObj; | ||||
| 					ExObj.set("from-uuid", Config.info.id); | ||||
| 					ExObj.set("from-name", Config.info.name); | ||||
| 					ExObj.set("action", "ignored"); | ||||
| 					ExObj.set("reason", "deviceType mismatch"); | ||||
| 					Explanation_.add(ExObj); | ||||
| 				} | ||||
| 			} else { | ||||
| 				poco_error(Logger(), | ||||
| 						   fmt::format("Device configuration for {} is empty.", SerialNumber_)); | ||||
| 			} | ||||
| 		} else { | ||||
| 			poco_error(Logger(), | ||||
| 					   fmt::format("Invalid device configuration UUID for {}.", SerialNumber_)); | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	void APConfig::AddEntityConfig(const std::string &UUID) { | ||||
| 		ProvObjects::Entity E; | ||||
| 		if (StorageService()->EntityDB().GetRecord("id", UUID, E)) { | ||||
| 			AddConfiguration(E.configurations); | ||||
| 			if (!E.parent.empty()) { | ||||
| 				AddEntityConfig(E.parent); | ||||
| 			} | ||||
| 		} else { | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	void APConfig::AddVenueConfig(const std::string &UUID) { | ||||
| 		ProvObjects::Venue V; | ||||
| 		if (StorageService()->VenueDB().GetRecord("id", UUID, V)) { | ||||
| 			AddConfiguration(V.configurations); | ||||
| 			if (!V.entity.empty()) { | ||||
| 				AddEntityConfig(V.entity); | ||||
| 			} else if (!V.parent.empty()) { | ||||
| 				AddVenueConfig(V.parent); | ||||
| 			} | ||||
| 		} else { | ||||
| 		} | ||||
| 	} | ||||
| } // namespace OpenWifi | ||||
|   | ||||
| @@ -4,50 +4,61 @@ | ||||
|  | ||||
| #pragma once | ||||
|  | ||||
| #include <string> | ||||
| #include "Poco/Logger.h" | ||||
| #include "RESTObjects//RESTAPI_ProvObjects.h" | ||||
| #include <string> | ||||
|  | ||||
| namespace OpenWifi { | ||||
|  | ||||
|     struct VerboseElement { | ||||
|         ProvObjects::DeviceConfigurationElement     element; | ||||
|         ProvObjects::ObjectInfo                     info; | ||||
|     }; | ||||
|     typedef std::vector<VerboseElement> ConfigVec; | ||||
| 	constexpr std::uint64_t MaximumPossibleRadios = 6; | ||||
|  | ||||
|     class APConfig { | ||||
|         public: | ||||
|             explicit APConfig(const std::string & SerialNumber, const std::string & DeviceType, Poco::Logger & L, bool Explain=false); | ||||
|             explicit APConfig(const std::string & SerialNumber, Poco::Logger & L); | ||||
| 	struct VerboseElement { | ||||
| 		ProvObjects::DeviceConfigurationElement element; | ||||
| 		ProvObjects::ObjectInfo info; | ||||
| 	}; | ||||
| 	typedef std::vector<VerboseElement> ConfigVec; | ||||
|  | ||||
| 	class APConfig { | ||||
| 	  public: | ||||
| 		explicit APConfig(const std::string &SerialNumber, const std::string &DeviceType, | ||||
| 						  Poco::Logger &L, bool Explain = false); | ||||
| 		explicit APConfig(const std::string &SerialNumber, Poco::Logger &L); | ||||
|  | ||||
|             [[nodiscard]] bool Get(Poco::JSON::Object::Ptr &Configuration); | ||||
| 		[[nodiscard]] bool Get(Poco::JSON::Object::Ptr &Configuration); | ||||
|  | ||||
|             void AddConfiguration(const std::string &UUID); | ||||
|             void AddConfiguration(const Types::UUIDvec_t &UUID); | ||||
|             void AddConfiguration(const ProvObjects::DeviceConfigurationElementVec &Elements); | ||||
|             void AddVenueConfig(const std::string &UUID); | ||||
|             void AddEntityConfig(const std::string &UUID); | ||||
|             const Poco::JSON::Array & Explanation() { return Explanation_; }; | ||||
|         private: | ||||
|             std::string                 SerialNumber_; | ||||
|             std::string                 DeviceType_; | ||||
|             Poco::Logger                & Logger_; | ||||
|             std::string                 CompleteConfig_; | ||||
|             ConfigVec                   Config_; | ||||
|             Types::StringPairVec        Errors; | ||||
|             bool                        Explain_=false; | ||||
|             Poco::JSON::Array           Explanation_; | ||||
|             bool                        Sub_=false; | ||||
|             Poco::Logger & Logger()     { return Logger_;} | ||||
| 		void AddConfiguration(const std::string &UUID); | ||||
| 		void AddConfiguration(const Types::UUIDvec_t &UUID); | ||||
| 		void AddConfiguration(const ProvObjects::DeviceConfigurationElementVec &Elements); | ||||
| 		void AddVenueConfig(const std::string &UUID); | ||||
| 		void AddEntityConfig(const std::string &UUID); | ||||
| 		const Poco::JSON::Array &Explanation() { return Explanation_; }; | ||||
|  | ||||
|             bool ReplaceVariablesInArray( const Poco::JSON::Array::Ptr & O, Poco::JSON::Array::Ptr & Result); | ||||
|             bool ReplaceVariablesInObject( const Poco::JSON::Object::Ptr & Original, Poco::JSON::Object::Ptr & Result); | ||||
| 	  private: | ||||
| 		std::string SerialNumber_; | ||||
| 		std::string DeviceType_; | ||||
| 		Poco::Logger &Logger_; | ||||
| 		std::string CompleteConfig_; | ||||
| 		ConfigVec Config_; | ||||
| 		Types::StringPairVec Errors; | ||||
| 		bool Explain_ = false; | ||||
| 		Poco::JSON::Array Explanation_; | ||||
| 		bool Sub_ = false; | ||||
| 		Poco::Logger &Logger() { return Logger_; } | ||||
|  | ||||
|             bool FindRadio(const std::string &Band, const Poco::JSON::Array::Ptr &Arr, Poco::JSON::Object::Ptr & Radio); | ||||
|             bool mergeArray(const std::string &K, const Poco::JSON::Array::Ptr &A , const Poco::JSON::Array::Ptr &B, Poco::JSON::Array &Arr); | ||||
|             bool merge(const Poco::JSON::Object::Ptr & A, const Poco::JSON::Object::Ptr & B, Poco::JSON::Object::Ptr &C); | ||||
|             bool RemoveBand(const std::string &Band, const Poco::JSON::Array::Ptr &A_in,Poco::JSON::Array::Ptr &A_Out); | ||||
|     }; | ||||
| } | ||||
| 		bool ReplaceVariablesInArray(const Poco::JSON::Array &O, | ||||
| 									 Poco::JSON::Array &Result); | ||||
| 		void ReplaceNestedVariables(const std::string uuid, Poco::JSON::Object &Result); | ||||
| 		bool ReplaceVariablesInObject(const Poco::JSON::Object &Original, | ||||
| 									  Poco::JSON::Object &Result); | ||||
|  | ||||
| 		bool FindRadio(const std::string &Band, const Poco::JSON::Array::Ptr &Arr, | ||||
| 					   Poco::JSON::Object::Ptr &Radio); | ||||
| 		bool mergeArray(const std::string &K, const Poco::JSON::Array::Ptr &A, | ||||
| 						const Poco::JSON::Array::Ptr &B, Poco::JSON::Array &Arr); | ||||
| 		bool merge(const Poco::JSON::Object::Ptr &A, const Poco::JSON::Object::Ptr &B, | ||||
| 				   Poco::JSON::Object::Ptr &C); | ||||
| 		bool RemoveBand(const std::string &Band, const Poco::JSON::Array::Ptr &A_in, | ||||
| 						Poco::JSON::Array::Ptr &A_Out); | ||||
|         bool InsertRadiusEndPoint(const ProvObjects::RADIUSEndPoint &EP, Poco::JSON::Object &Result); | ||||
| 	}; | ||||
| } // namespace OpenWifi | ||||
|   | ||||
| @@ -3,77 +3,127 @@ | ||||
| // | ||||
|  | ||||
| #include "AutoDiscovery.h" | ||||
| #include "framework/ow_constants.h" | ||||
| #include "framework/KafkaTopics.h" | ||||
| #include "Poco/JSON/Parser.h" | ||||
| #include "StorageService.h" | ||||
| #include "Tasks/VenueConfigUpdater.h" | ||||
| #include "framework/KafkaManager.h" | ||||
| #include "framework/KafkaTopics.h" | ||||
| #include "framework/ow_constants.h" | ||||
|  | ||||
| namespace OpenWifi { | ||||
|  | ||||
|     int AutoDiscovery::Start() { | ||||
|         Running_ = true; | ||||
|         Types::TopicNotifyFunction F = [this](const std::string &Key, const std::string &Payload) { this->ConnectionReceived(Key,Payload); }; | ||||
|         ConnectionWatcherId_ = KafkaManager()->RegisterTopicWatcher(KafkaTopics::CONNECTION, F); | ||||
|         Worker_.start(*this); | ||||
|         return 0; | ||||
|     }; | ||||
| 	int AutoDiscovery::Start() { | ||||
| 		poco_information(Logger(), "Starting..."); | ||||
| 		Running_ = true; | ||||
| 		Types::TopicNotifyFunction F = [this](const std::string &Key, const std::string &Payload) { | ||||
| 			this->ConnectionReceived(Key, Payload); | ||||
| 		}; | ||||
| 		ConnectionWatcherId_ = KafkaManager()->RegisterTopicWatcher(KafkaTopics::CONNECTION, F); | ||||
| 		Worker_.start(*this); | ||||
| 		return 0; | ||||
| 	}; | ||||
|  | ||||
|     void AutoDiscovery::Stop() { | ||||
|         Running_ = false; | ||||
|         KafkaManager()->UnregisterTopicWatcher(KafkaTopics::CONNECTION, ConnectionWatcherId_); | ||||
|         Queue_.wakeUpAll(); | ||||
|         Worker_.join(); | ||||
|     }; | ||||
| 	void AutoDiscovery::Stop() { | ||||
| 		poco_information(Logger(), "Stopping..."); | ||||
| 		Running_ = false; | ||||
| 		KafkaManager()->UnregisterTopicWatcher(KafkaTopics::CONNECTION, ConnectionWatcherId_); | ||||
| 		Queue_.wakeUpAll(); | ||||
| 		Worker_.join(); | ||||
| 		poco_information(Logger(), "Stopped..."); | ||||
| 	}; | ||||
|  | ||||
|     void AutoDiscovery::run() { | ||||
|         Poco::AutoPtr<Poco::Notification>	Note(Queue_.waitDequeueNotification()); | ||||
|         Utils::SetThreadName("auto-discovery"); | ||||
|         while(Note && Running_) { | ||||
|             auto Msg = dynamic_cast<DiscoveryMessage *>(Note.get()); | ||||
|             if(Msg!= nullptr) { | ||||
|                 try { | ||||
|                     Poco::JSON::Parser Parser; | ||||
|                     auto Object = Parser.parse(Msg->Payload()).extract<Poco::JSON::Object::Ptr>(); | ||||
|  | ||||
|                     if (Object->has(uCentralProtocol::PAYLOAD)) { | ||||
|                         auto PayloadObj = Object->getObject(uCentralProtocol::PAYLOAD); | ||||
|                         std::string ConnectedIP, SerialNumber, DeviceType; | ||||
|                         if (PayloadObj->has(uCentralProtocol::CONNECTIONIP)) | ||||
|                             ConnectedIP = PayloadObj->get(uCentralProtocol::CONNECTIONIP).toString(); | ||||
|                         if (PayloadObj->has(uCentralProtocol::CAPABILITIES)) { | ||||
|                             auto CapObj = PayloadObj->getObject(uCentralProtocol::CAPABILITIES); | ||||
|                             if (CapObj->has(uCentralProtocol::COMPATIBLE)) { | ||||
|                                 DeviceType = CapObj->get(uCentralProtocol::COMPATIBLE).toString(); | ||||
|                                 SerialNumber = PayloadObj->get(uCentralProtocol::SERIAL).toString(); | ||||
|                             } | ||||
|                         } else if (PayloadObj->has(uCentralProtocol::PING)) { | ||||
|                             auto PingMessage = PayloadObj->getObject(uCentralProtocol::PING); | ||||
|                             if (PingMessage->has(uCentralProtocol::FIRMWARE) && | ||||
|                                 PingMessage->has(uCentralProtocol::SERIALNUMBER) && | ||||
|                                 PingMessage->has(uCentralProtocol::COMPATIBLE)) { | ||||
|                                 if (PingMessage->has(uCentralProtocol::CONNECTIONIP)) | ||||
|                                     ConnectedIP = PingMessage->get(uCentralProtocol::CONNECTIONIP).toString(); | ||||
|                                 SerialNumber = PingMessage->get(uCentralProtocol::SERIALNUMBER).toString(); | ||||
|                                 DeviceType = PingMessage->get(uCentralProtocol::COMPATIBLE).toString(); | ||||
|                             } | ||||
|                         } | ||||
|                         std::string Locale; | ||||
|                         if(PayloadObj->has("locale")) | ||||
|                             Locale = PayloadObj->get("locale").toString(); | ||||
|  | ||||
|                         if (!SerialNumber.empty()) { | ||||
|                             StorageService()->InventoryDB().CreateFromConnection(SerialNumber, ConnectedIP, DeviceType, Locale); | ||||
|                         } | ||||
|                     } | ||||
|                 } catch (const Poco::Exception &E) { | ||||
|                     Logger().log(E); | ||||
|                 } catch (...) { | ||||
|  | ||||
|                 } | ||||
|             } else { | ||||
|  | ||||
|             } | ||||
|             Note = Queue_.waitDequeueNotification(); | ||||
|     void AutoDiscovery::ProcessPing(const Poco::JSON::Object::Ptr & P, std::string &FW, std::string &SN, | ||||
|                                     std::string &Compat, std::string &Conn, std::string &locale) { | ||||
|         if (P->has(uCentralProtocol::CONNECTIONIP)) | ||||
|             Conn = P->get(uCentralProtocol::CONNECTIONIP).toString(); | ||||
|         if (P->has(uCentralProtocol::FIRMWARE)) | ||||
|             FW = P->get(uCentralProtocol::FIRMWARE).toString(); | ||||
|         if (P->has(uCentralProtocol::SERIALNUMBER)) | ||||
|             SN = P->get(uCentralProtocol::SERIALNUMBER).toString(); | ||||
|         if (P->has(uCentralProtocol::COMPATIBLE)) | ||||
|             Compat = P->get(uCentralProtocol::COMPATIBLE).toString(); | ||||
|         if (P->has("locale")) { | ||||
|             locale = P->get("locale").toString(); | ||||
|         } | ||||
|     } | ||||
|  | ||||
| } | ||||
|     void AutoDiscovery::ProcessConnect(const Poco::JSON::Object::Ptr &P, std::string &FW, std::string &SN, | ||||
|                                        std::string &Compat, std::string &Conn, std::string &locale) { | ||||
|         if (P->has(uCentralProtocol::CONNECTIONIP)) | ||||
|             Conn = P->get(uCentralProtocol::CONNECTIONIP).toString(); | ||||
|         if (P->has(uCentralProtocol::FIRMWARE)) | ||||
|             FW = P->get(uCentralProtocol::FIRMWARE).toString(); | ||||
|         if (P->has(uCentralProtocol::SERIALNUMBER)) | ||||
|             SN = P->get(uCentralProtocol::SERIALNUMBER).toString(); | ||||
|         else if (P->has(uCentralProtocol::SERIAL)) | ||||
|             SN = P->get(uCentralProtocol::SERIAL).toString(); | ||||
|         if (P->has("locale")) { | ||||
|             locale = P->get("locale").toString(); | ||||
|         } | ||||
|         if(P->has(uCentralProtocol::CAPABILITIES)) { | ||||
|             auto CapObj = P->getObject(uCentralProtocol::CAPABILITIES); | ||||
|             if (CapObj->has(uCentralProtocol::COMPATIBLE)) | ||||
|                 Compat = CapObj->get(uCentralProtocol::COMPATIBLE).toString(); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     void AutoDiscovery::ProcessDisconnect(const Poco::JSON::Object::Ptr &P, [[maybe_unused]] std::string &FW, | ||||
|                                             std::string &SN, | ||||
|                                           [[maybe_unused]] std::string &Compat, | ||||
|                                           [[maybe_unused]] std::string &Conn, | ||||
|                                           [[maybe_unused]] std::string &locale) { | ||||
|         if (P->has(uCentralProtocol::SERIALNUMBER)) | ||||
|             SN = P->get(uCentralProtocol::SERIALNUMBER).toString(); | ||||
|     } | ||||
|  | ||||
|     void AutoDiscovery::run() { | ||||
| 		Poco::AutoPtr<Poco::Notification> Note(Queue_.waitDequeueNotification()); | ||||
| 		Utils::SetThreadName("auto-discovery"); | ||||
| 		while (Note && Running_) { | ||||
| 			auto Msg = dynamic_cast<DiscoveryMessage *>(Note.get()); | ||||
| 			if (Msg != nullptr) { | ||||
| 				try { | ||||
| 					Poco::JSON::Parser Parser; | ||||
| 					auto Object = Parser.parse(Msg->Payload()).extract<Poco::JSON::Object::Ptr>(); | ||||
|                     bool    Connected=true; | ||||
|                     bool isConnection=false; | ||||
|  | ||||
| 					if (Object->has(uCentralProtocol::PAYLOAD)) { | ||||
|                         auto PayloadObj = Object->getObject(uCentralProtocol::PAYLOAD); | ||||
|                         std::string ConnectedIP, SerialNumber, Compatible, Firmware, Locale ; | ||||
|                         if (PayloadObj->has(uCentralProtocol::PING)) { | ||||
|                             auto PingObj = PayloadObj->getObject("ping"); | ||||
|                             ProcessPing(PingObj, Firmware, SerialNumber, Compatible, ConnectedIP, Locale); | ||||
|                         } else if(PayloadObj->has("capabilities")) { | ||||
|                             isConnection=true; | ||||
|                             ProcessConnect(PayloadObj, Firmware, SerialNumber, Compatible, ConnectedIP, Locale); | ||||
|                         } else if(PayloadObj->has("disconnection")) { | ||||
|                             //  we ignore disconnection in provisioning | ||||
|                             Connected=false; | ||||
|                             ProcessConnect(PayloadObj, Firmware, SerialNumber, Compatible, ConnectedIP, Locale); | ||||
|                         } else { | ||||
|                             poco_debug(Logger(),fmt::format("Unknown message on 'connection' topic: {}",Msg->Payload())); | ||||
|                         } | ||||
|  | ||||
|                         if (!SerialNumber.empty() && Connected) { | ||||
|                             StorageService()->InventoryDB().CreateFromConnection( | ||||
|                                     SerialNumber, ConnectedIP, Compatible, Locale, isConnection); | ||||
|                             // Now that the entry has been created, we can try to push a config if | ||||
|                             // the connection was a capabilities message. | ||||
|                             if (isConnection){ | ||||
|                                 ComputeAndPushConfig(SerialNumber, Compatible, Logger()); | ||||
|                             } | ||||
|                         } | ||||
|                     } | ||||
| 				} catch (const Poco::Exception &E) { | ||||
|                     std::cout << "EX:" << Msg->Payload() << std::endl; | ||||
| 					Logger().log(E); | ||||
| 				} catch (...) { | ||||
| 				} | ||||
| 			} else { | ||||
| 			} | ||||
| 			Note = Queue_.waitDequeueNotification(); | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| } // namespace OpenWifi | ||||
| @@ -4,53 +4,60 @@ | ||||
|  | ||||
| #pragma once | ||||
|  | ||||
| #include "framework/MicroService.h" | ||||
| #include "framework/OpenWifiTypes.h" | ||||
| #include "framework/SubSystemServer.h" | ||||
|  | ||||
| #include "Poco/Notification.h" | ||||
| #include "Poco/NotificationQueue.h" | ||||
| #include "Poco/JSON/Object.h" | ||||
|  | ||||
| namespace OpenWifi { | ||||
|  | ||||
|     class DiscoveryMessage : public Poco::Notification { | ||||
|         public: | ||||
|             explicit DiscoveryMessage(const std::string &Key, const std::string &Payload ) : | ||||
|                 Key_(Key), | ||||
|                 Payload_(Payload) {} | ||||
|             const std::string & Key() { return Key_; } | ||||
|             const std::string & Payload() { return Payload_; } | ||||
|         private: | ||||
|             std::string     Key_; | ||||
|             std::string     Payload_; | ||||
|     }; | ||||
| 	class DiscoveryMessage : public Poco::Notification { | ||||
| 	  public: | ||||
| 		explicit DiscoveryMessage(const std::string &Key, const std::string &Payload) | ||||
| 			: Key_(Key), Payload_(Payload) {} | ||||
| 		const std::string &Key() { return Key_; } | ||||
| 		const std::string &Payload() { return Payload_; } | ||||
|  | ||||
|     class AutoDiscovery : public SubSystemServer, Poco::Runnable { | ||||
|         public: | ||||
| 	  private: | ||||
| 		std::string Key_; | ||||
| 		std::string Payload_; | ||||
| 	}; | ||||
|  | ||||
|             static auto instance() { | ||||
|                 static auto instance_ = new AutoDiscovery; | ||||
|                 return instance_; | ||||
|             } | ||||
| 	class AutoDiscovery : public SubSystemServer, Poco::Runnable { | ||||
| 	  public: | ||||
| 		static auto instance() { | ||||
| 			static auto instance_ = new AutoDiscovery; | ||||
| 			return instance_; | ||||
| 		} | ||||
|  | ||||
|             int Start() override; | ||||
|             void Stop() override; | ||||
|             void ConnectionReceived( const std::string & Key, const std::string & Payload) { | ||||
|                 std::lock_guard G(Mutex_); | ||||
|                 poco_debug(Logger(),Poco::format("Device(%s): Connection/Ping message.", Key)); | ||||
|                 Queue_.enqueueNotification( new DiscoveryMessage(Key,Payload)); | ||||
|             } | ||||
|             void run() override; | ||||
| 		int Start() override; | ||||
| 		void Stop() override; | ||||
| 		void ConnectionReceived(const std::string &Key, const std::string &Payload) { | ||||
| 			std::lock_guard G(Mutex_); | ||||
| 			poco_trace(Logger(), Poco::format("Device(%s): Connection/Ping message.", Key)); | ||||
| 			Queue_.enqueueNotification(new DiscoveryMessage(Key, Payload)); | ||||
| 		} | ||||
| 		void run() override; | ||||
|  | ||||
|         private: | ||||
|             uint64_t                                ConnectionWatcherId_=0; | ||||
|             Poco::NotificationQueue                 Queue_; | ||||
|             Poco::Thread                            Worker_; | ||||
|             std::atomic_bool                        Running_=false; | ||||
| 	  private: | ||||
| 		uint64_t ConnectionWatcherId_ = 0; | ||||
| 		Poco::NotificationQueue Queue_; | ||||
| 		Poco::Thread Worker_; | ||||
| 		std::atomic_bool Running_ = false; | ||||
|  | ||||
|             AutoDiscovery() noexcept: | ||||
|                 SubSystemServer("AutoDiscovery", "AUTO-DISCOVERY", "discovery") | ||||
|                 { | ||||
|                 } | ||||
|         }; | ||||
|         void ProcessPing(const Poco::JSON::Object::Ptr & P, std::string &FW, std::string &SN, | ||||
|                                         std::string &Compat, std::string &Conn, std::string &locale) ; | ||||
|         void ProcessConnect(const Poco::JSON::Object::Ptr & P, std::string &FW, std::string &SN, | ||||
|                          std::string &Compat, std::string &Conn, std::string &locale) ; | ||||
|         void ProcessDisconnect(const Poco::JSON::Object::Ptr & P, std::string &FW, std::string &SN, | ||||
|                             std::string &Compat, std::string &Conn, std::string &locale) ; | ||||
|  | ||||
|     inline auto AutoDiscovery() { return AutoDiscovery::instance(); } | ||||
|         AutoDiscovery() noexcept | ||||
| 			: SubSystemServer("AutoDiscovery", "AUTO-DISCOVERY", "discovery") {} | ||||
| 	}; | ||||
|  | ||||
| } | ||||
| 	inline auto AutoDiscovery() { return AutoDiscovery::instance(); } | ||||
|  | ||||
| } // namespace OpenWifi | ||||
|   | ||||
| @@ -4,50 +4,44 @@ | ||||
|  | ||||
| #include "ConfigSanityChecker.h" | ||||
| #include "nlohmann/json.hpp" | ||||
| #include <iostream> | ||||
| #include <iomanip> | ||||
| #include <iostream> | ||||
|  | ||||
| namespace OpenWifi { | ||||
|  | ||||
|     bool ConfigSanityChecker::Check() { | ||||
|         try { | ||||
|             auto Doc = nlohmann::json::parse(Config_); | ||||
| 	bool ConfigSanityChecker::Check() { | ||||
| 		try { | ||||
| 			auto Doc = nlohmann::json::parse(Config_); | ||||
|  | ||||
|             for(const auto &[key,value]:Doc.items()) { | ||||
|                 for(const auto &i:Funcs_) | ||||
|                     if(i.first==key) | ||||
|                         i.second(value); | ||||
|             } | ||||
|             return true; | ||||
|         } catch ( ... ) { | ||||
| 			for (const auto &[key, value] : Doc.items()) { | ||||
| 				for (const auto &i : Funcs_) | ||||
| 					if (i.first == key) | ||||
| 						i.second(value); | ||||
| 			} | ||||
| 			return true; | ||||
| 		} catch (...) { | ||||
| 		} | ||||
| 		return false; | ||||
| 	} | ||||
|  | ||||
|         } | ||||
|         return false; | ||||
|     } | ||||
| 	void ConfigSanityChecker::Check_radios([[maybe_unused]] nlohmann::json &d) { | ||||
| 		std::cout << "Validating radios" << std::endl; | ||||
| 	}; | ||||
|  | ||||
|     void ConfigSanityChecker::Check_radios([[maybe_unused]] nlohmann::json &d) { | ||||
|         std::cout << "Validating radios" << std::endl; | ||||
| 	void ConfigSanityChecker::Check_interfaces([[maybe_unused]] nlohmann::json &d) { | ||||
| 		std::cout << "Validating interfaces" << std::endl; | ||||
| 	}; | ||||
|  | ||||
|     }; | ||||
| 	void ConfigSanityChecker::Check_metrics([[maybe_unused]] nlohmann::json &d) { | ||||
| 		std::cout << "Validating metrics" << std::endl; | ||||
| 	}; | ||||
|  | ||||
|     void ConfigSanityChecker::Check_interfaces([[maybe_unused]] nlohmann::json &d) { | ||||
|         std::cout << "Validating interfaces" << std::endl; | ||||
| 	void ConfigSanityChecker::Check_services([[maybe_unused]] nlohmann::json &d) { | ||||
| 		std::cout << "Validating services" << std::endl; | ||||
| 	}; | ||||
|  | ||||
|     }; | ||||
| 	void ConfigSanityChecker::Check_uuid([[maybe_unused]] nlohmann::json &d) { | ||||
| 		std::cout << "Validating uuid" << std::endl; | ||||
| 	}; | ||||
|  | ||||
|     void ConfigSanityChecker::Check_metrics([[maybe_unused]] nlohmann::json &d) { | ||||
|         std::cout << "Validating metrics" << std::endl; | ||||
|  | ||||
|     }; | ||||
|  | ||||
|     void ConfigSanityChecker::Check_services([[maybe_unused]] nlohmann::json &d) { | ||||
|         std::cout << "Validating services" << std::endl; | ||||
|  | ||||
|     }; | ||||
|  | ||||
|     void ConfigSanityChecker::Check_uuid([[maybe_unused]] nlohmann::json &d) { | ||||
|         std::cout << "Validating uuid" << std::endl; | ||||
|  | ||||
|     }; | ||||
|  | ||||
| } | ||||
| } // namespace OpenWifi | ||||
| @@ -4,59 +4,57 @@ | ||||
|  | ||||
| #pragma once | ||||
|  | ||||
| #include <string> | ||||
| #include <list> | ||||
| #include <functional> | ||||
| #include <map> | ||||
| #include <vector> | ||||
| #include <utility> | ||||
| #include "nlohmann/json.hpp" | ||||
| #include <functional> | ||||
| #include <list> | ||||
| #include <map> | ||||
| #include <string> | ||||
| #include <utility> | ||||
| #include <vector> | ||||
|  | ||||
| namespace OpenWifi { | ||||
|     struct SanityError { | ||||
|         std::string     Cause; | ||||
|         std::string     Reason; | ||||
|         std::string     Severity; | ||||
|     }; | ||||
| 	struct SanityError { | ||||
| 		std::string Cause; | ||||
| 		std::string Reason; | ||||
| 		std::string Severity; | ||||
| 	}; | ||||
|  | ||||
|     typedef std::list<SanityError>  SanityErrorList; | ||||
| 	typedef std::list<SanityError> SanityErrorList; | ||||
|  | ||||
|     class ConfigSanityChecker { | ||||
|         public: | ||||
|             explicit ConfigSanityChecker(std::string Config, std::string DeviceType) : | ||||
|                 Config_(std::move(Config)), | ||||
|                 DeviceType_(std::move(DeviceType)){} | ||||
| 	class ConfigSanityChecker { | ||||
| 	  public: | ||||
| 		explicit ConfigSanityChecker(std::string Config, std::string DeviceType) | ||||
| 			: Config_(std::move(Config)), DeviceType_(std::move(DeviceType)) {} | ||||
|  | ||||
|             bool Check(); | ||||
|             const SanityErrorList & Errors() { return Errors_; } | ||||
|             const SanityErrorList & Warnings() { return Warnings_; } | ||||
| 		bool Check(); | ||||
| 		const SanityErrorList &Errors() { return Errors_; } | ||||
| 		const SanityErrorList &Warnings() { return Warnings_; } | ||||
|  | ||||
|             typedef std::function<void(nlohmann::json &)>   CheckFuncType; | ||||
| 		typedef std::function<void(nlohmann::json &)> CheckFuncType; | ||||
|  | ||||
|             struct KeyToFunc { | ||||
|                 std::string        Key; | ||||
|                 CheckFuncType      Func; | ||||
|             }; | ||||
|             typedef std::pair<std::string, CheckFuncType>   FuncPair; | ||||
|             typedef std::vector<FuncPair>    FuncList; | ||||
| 		struct KeyToFunc { | ||||
| 			std::string Key; | ||||
| 			CheckFuncType Func; | ||||
| 		}; | ||||
| 		typedef std::pair<std::string, CheckFuncType> FuncPair; | ||||
| 		typedef std::vector<FuncPair> FuncList; | ||||
|  | ||||
|             void Check_radios(nlohmann::json &); | ||||
|             void Check_interfaces(nlohmann::json &); | ||||
|             void Check_metrics(nlohmann::json &); | ||||
|             void Check_services(nlohmann::json &); | ||||
|             void Check_uuid(nlohmann::json &); | ||||
| 		void Check_radios(nlohmann::json &); | ||||
| 		void Check_interfaces(nlohmann::json &); | ||||
| 		void Check_metrics(nlohmann::json &); | ||||
| 		void Check_services(nlohmann::json &); | ||||
| 		void Check_uuid(nlohmann::json &); | ||||
|  | ||||
|         private: | ||||
|             std::string         Config_; | ||||
|             std::string         DeviceType_; | ||||
|             SanityErrorList     Errors_; | ||||
|             SanityErrorList     Warnings_; | ||||
|             FuncList            Funcs_{ | ||||
|                 std::make_pair("radios", [this](nlohmann::json &d){ this->Check_radios(d);} ) , | ||||
|                 std::make_pair("interfaces", [this](nlohmann::json &d){ this->Check_interfaces(d);} ), | ||||
|                 std::make_pair("metrics", [this](nlohmann::json &d){ this->Check_metrics(d);} ), | ||||
|                 std::make_pair("services", [this](nlohmann::json &d){ this->Check_services(d);} ), | ||||
|                 std::make_pair("uuid", [this](nlohmann::json &d){ this->Check_uuid(d);} ) | ||||
|                 }; | ||||
|     }; | ||||
| } | ||||
| 	  private: | ||||
| 		std::string Config_; | ||||
| 		std::string DeviceType_; | ||||
| 		SanityErrorList Errors_; | ||||
| 		SanityErrorList Warnings_; | ||||
| 		FuncList Funcs_{ | ||||
| 			std::make_pair("radios", [this](nlohmann::json &d) { this->Check_radios(d); }), | ||||
| 			std::make_pair("interfaces", [this](nlohmann::json &d) { this->Check_interfaces(d); }), | ||||
| 			std::make_pair("metrics", [this](nlohmann::json &d) { this->Check_metrics(d); }), | ||||
| 			std::make_pair("services", [this](nlohmann::json &d) { this->Check_services(d); }), | ||||
| 			std::make_pair("uuid", [this](nlohmann::json &d) { this->Check_uuid(d); })}; | ||||
| 	}; | ||||
| } // namespace OpenWifi | ||||
|   | ||||
							
								
								
									
										135
									
								
								src/Daemon.cpp
									
									
									
									
									
								
							
							
						
						| @@ -6,92 +6,99 @@ | ||||
| //	Arilia Wireless Inc. | ||||
| // | ||||
|  | ||||
| #include "Poco/Environment.h" | ||||
| #include "Poco/Net/SSLManager.h" | ||||
| #include "Poco/Util/Application.h" | ||||
| #include "Poco/Util/Option.h" | ||||
| #include "Poco/Environment.h" | ||||
|  | ||||
| #include "Daemon.h" | ||||
| #include "StorageService.h" | ||||
| #include "AutoDiscovery.h" | ||||
| #include "framework/ConfigurationValidator.h" | ||||
| #include "SerialNumberCache.h" | ||||
| #include "JobController.h" | ||||
| #include "FindCountry.h" | ||||
| #include "Signup.h" | ||||
| #include "Daemon.h" | ||||
| #include "DeviceTypeCache.h" | ||||
| #include "FileDownloader.h" | ||||
| #include "FindCountry.h" | ||||
| #include "JobController.h" | ||||
| #include "SerialNumberCache.h" | ||||
| #include "Signup.h" | ||||
| #include "StorageService.h" | ||||
| #include "UI_Prov_WebSocketNotifications.h" | ||||
| #include "framework/ConfigurationValidator.h" | ||||
| #include "framework/UI_WebSocketClientServer.h" | ||||
| #include <RadiusEndpointTypes/GlobalReach.h> | ||||
| #include <RadiusEndpointTypes/OrionWifi.h> | ||||
| #include <RadiusEndpointTypes/Radsec.h> | ||||
| #include <RadiusEndpointTypes/GenericRadius.h> | ||||
|  | ||||
| namespace OpenWifi { | ||||
| 	class Daemon *Daemon::instance_ = nullptr; | ||||
|  | ||||
| 	class Daemon *Daemon::instance() { | ||||
| 		if (instance_ == nullptr) { | ||||
| 			instance_ = new Daemon(vDAEMON_PROPERTIES_FILENAME, | ||||
| 								   vDAEMON_ROOT_ENV_VAR, | ||||
| 								   vDAEMON_CONFIG_ENV_VAR, | ||||
| 								   vDAEMON_APP_NAME, | ||||
| 								   vDAEMON_BUS_TIMER, | ||||
| 								   SubSystemVec{ | ||||
| 									   OpenWifi::StorageService(), | ||||
|                                        DeviceTypeCache(), | ||||
| 									   ConfigurationValidator(), | ||||
| 									   SerialNumberCache(), | ||||
| 									   AutoDiscovery(), | ||||
| 									   JobController(), | ||||
| 									   WebSocketClientServer(), | ||||
|                                        FindCountryFromIP(), | ||||
|                                        Signup(), | ||||
|                                        FileDownloader() | ||||
| 								   }); | ||||
| 			instance_ = new Daemon(vDAEMON_PROPERTIES_FILENAME, vDAEMON_ROOT_ENV_VAR, | ||||
| 								   vDAEMON_CONFIG_ENV_VAR, vDAEMON_APP_NAME, vDAEMON_BUS_TIMER, | ||||
| 								   SubSystemVec{OpenWifi::StorageService(), DeviceTypeCache(), | ||||
| 												ConfigurationValidator(), SerialNumberCache(), | ||||
| 												AutoDiscovery(), JobController(), | ||||
| 												UI_WebSocketClientServer(), FindCountryFromIP(), | ||||
| 												Signup(), FileDownloader(), | ||||
|                                                 OpenRoaming_GlobalReach(), | ||||
|                                                 OpenRoaming_Orion(), OpenRoaming_Radsec(), | ||||
|                                                 OpenRoaming_GenericRadius() | ||||
|             }); | ||||
| 		} | ||||
| 		return instance_; | ||||
| 	} | ||||
|  | ||||
| 	void Daemon::PostInitialization([[maybe_unused]] Poco::Util::Application &self) { | ||||
| 	    if(MicroService::instance().ConfigGetBool("firmware.updater.upgrade",false)) { | ||||
| 	        if(MicroService::instance().ConfigGetBool("firmware.updater.releaseonly",false)) { | ||||
| 	            FWRules_ = ProvObjects::upgrade_release_only; | ||||
| 	        } else { | ||||
| 	            FWRules_ = ProvObjects::upgrade_latest; | ||||
| 	        } | ||||
| 	    } else { | ||||
| 	        FWRules_ = ProvObjects::dont_upgrade; | ||||
| 	    } | ||||
| 		if (MicroService::instance().ConfigGetBool("firmware.updater.upgrade", false)) { | ||||
| 			if (MicroService::instance().ConfigGetBool("firmware.updater.releaseonly", false)) { | ||||
| 				FWRules_ = ProvObjects::upgrade_release_only; | ||||
| 			} else { | ||||
| 				FWRules_ = ProvObjects::upgrade_latest; | ||||
| 			} | ||||
| 		} else { | ||||
| 			FWRules_ = ProvObjects::dont_upgrade; | ||||
| 		} | ||||
|  | ||||
|         WebSocketProcessor_ = std::make_unique<ProvWebSocketClient>(logger()); | ||||
| 		WebSocketProcessor_ = std::make_unique<ProvWebSocketClient>(logger()); | ||||
|  | ||||
|         AssetDir_ = MicroService::instance().DataDir() + "/wwwassets"; | ||||
|         Poco::File	DataDir(AssetDir_); | ||||
|         if(!DataDir.exists()) { | ||||
|             try { | ||||
|                 DataDir.createDirectory(); | ||||
|             } catch (const Poco::Exception &E) { | ||||
|                 logger().log(E); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 		AssetDir_ = MicroService::instance().DataDir() + "/wwwassets"; | ||||
| 		Poco::File DataDir(AssetDir_); | ||||
| 		if (!DataDir.exists()) { | ||||
| 			try { | ||||
| 				DataDir.createDirectory(); | ||||
| 			} catch (const Poco::Exception &E) { | ||||
| 				logger().log(E); | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	void DaemonPostInitialization(Poco::Util::Application &self) { | ||||
| 		Daemon()->PostInitialization(self); | ||||
| 		ProvWebSocketNotifications::Register(); | ||||
| 	} | ||||
|  | ||||
| } // namespace OpenWifi | ||||
|  | ||||
| int main(int argc, char **argv) { | ||||
|     int ExitCode; | ||||
|     try { | ||||
|         Poco::Net::SSLManager::instance().initializeServer(nullptr, nullptr, nullptr); | ||||
|         auto App = OpenWifi::Daemon::instance(); | ||||
|         ExitCode =  App->run(argc, argv); | ||||
|         Poco::Net::SSLManager::instance().shutdown(); | ||||
|     } catch (Poco::Exception &exc) { | ||||
|         ExitCode = Poco::Util::Application::EXIT_SOFTWARE; | ||||
|         std::cout << exc.displayText() << std::endl; | ||||
|     } catch (std::exception &exc) { | ||||
|         ExitCode = Poco::Util::Application::EXIT_TEMPFAIL; | ||||
|         std::cout << exc.what() << std::endl; | ||||
|     } catch (...) { | ||||
|         ExitCode = Poco::Util::Application::EXIT_TEMPFAIL; | ||||
|         std::cout << "Exception on closure" << std::endl; | ||||
|     } | ||||
| 	int ExitCode; | ||||
| 	try { | ||||
| 		Poco::Net::SSLManager::instance().initializeServer(nullptr, nullptr, nullptr); | ||||
| 		auto App = OpenWifi::Daemon::instance(); | ||||
| 		ExitCode = App->run(argc, argv); | ||||
| 		Poco::Net::SSLManager::instance().shutdown(); | ||||
| 	} catch (Poco::Exception &exc) { | ||||
| 		ExitCode = Poco::Util::Application::EXIT_SOFTWARE; | ||||
| 		std::cout << exc.displayText() << std::endl; | ||||
| 	} catch (std::exception &exc) { | ||||
| 		ExitCode = Poco::Util::Application::EXIT_TEMPFAIL; | ||||
| 		std::cout << exc.what() << std::endl; | ||||
| 	} catch (...) { | ||||
| 		ExitCode = Poco::Util::Application::EXIT_TEMPFAIL; | ||||
| 		std::cout << "Exception on closure" << std::endl; | ||||
| 	} | ||||
|  | ||||
|     std::cout << "Exitcode: " << ExitCode << std::endl; | ||||
|     return ExitCode; | ||||
| 	std::cout << "Exitcode: " << ExitCode << std::endl; | ||||
| 	return ExitCode; | ||||
| } | ||||
|  | ||||
| // end of namespace | ||||
							
								
								
									
										71
									
								
								src/Daemon.h
									
									
									
									
									
								
							
							
						
						| @@ -9,53 +9,48 @@ | ||||
| #pragma once | ||||
|  | ||||
| #include <array> | ||||
| #include <iostream> | ||||
| #include <cstdlib> | ||||
| #include <vector> | ||||
| #include <iostream> | ||||
| #include <set> | ||||
| #include <vector> | ||||
|  | ||||
| #include "Dashboard.h" | ||||
| #include "framework/MicroService.h" | ||||
| #include "framework/OpenWifiTypes.h" | ||||
| #include "RESTObjects/RESTAPI_ProvObjects.h" | ||||
| #include "ProvWebSocketClient.h" | ||||
| #include "RESTObjects/RESTAPI_ProvObjects.h" | ||||
| #include "framework/MicroService.h" | ||||
| #include "framework/MicroServiceNames.h" | ||||
| #include "framework/OpenWifiTypes.h" | ||||
|  | ||||
| namespace OpenWifi { | ||||
|  | ||||
| 	[[maybe_unused]] static const char * vDAEMON_PROPERTIES_FILENAME = "owprov.properties"; | ||||
|     [[maybe_unused]] static const char * vDAEMON_ROOT_ENV_VAR = "OWPROV_ROOT"; | ||||
|     [[maybe_unused]] static const char * vDAEMON_CONFIG_ENV_VAR = "OWPROV_CONFIG"; | ||||
|     [[maybe_unused]] static const char * vDAEMON_APP_NAME = uSERVICE_PROVISIONING.c_str() ; | ||||
|     [[maybe_unused]] static const uint64_t vDAEMON_BUS_TIMER = 10000; | ||||
| 	[[maybe_unused]] static const char *vDAEMON_PROPERTIES_FILENAME = "owprov.properties"; | ||||
| 	[[maybe_unused]] static const char *vDAEMON_ROOT_ENV_VAR = "OWPROV_ROOT"; | ||||
| 	[[maybe_unused]] static const char *vDAEMON_CONFIG_ENV_VAR = "OWPROV_CONFIG"; | ||||
| 	[[maybe_unused]] static const char *vDAEMON_APP_NAME = uSERVICE_PROVISIONING.c_str(); | ||||
| 	[[maybe_unused]] static const uint64_t vDAEMON_BUS_TIMER = 10000; | ||||
|  | ||||
|     class Daemon : public MicroService { | ||||
| 		public: | ||||
| 			explicit Daemon(const std::string & PropFile, | ||||
| 							const std::string & RootEnv, | ||||
| 							const std::string & ConfigEnv, | ||||
| 							const std::string & AppName, | ||||
| 						  	uint64_t 	BusTimer, | ||||
| 							const SubSystemVec & SubSystems) : | ||||
| 				MicroService( PropFile, RootEnv, ConfigEnv, AppName, BusTimer, SubSystems) {}; | ||||
| 	class Daemon : public MicroService { | ||||
| 	  public: | ||||
| 		explicit Daemon(const std::string &PropFile, const std::string &RootEnv, | ||||
| 						const std::string &ConfigEnv, const std::string &AppName, uint64_t BusTimer, | ||||
| 						const SubSystemVec &SubSystems) | ||||
| 			: MicroService(PropFile, RootEnv, ConfigEnv, AppName, BusTimer, SubSystems){}; | ||||
|  | ||||
| 			static Daemon *instance(); | ||||
| 			inline OpenWifi::ProvisioningDashboard & GetDashboard() { return DB_; } | ||||
| 			Poco::Logger & Log() { return Poco::Logger::get(AppName()); } | ||||
| 			ProvObjects::FIRMWARE_UPGRADE_RULES FirmwareRules() const { return FWRules_; } | ||||
|             inline const std::string & AssetDir() { return AssetDir_; } | ||||
|             void PostInitialization(Poco::Util::Application &self); | ||||
| 		static Daemon *instance(); | ||||
| 		inline OpenWifi::ProvisioningDashboard &GetDashboard() { return DB_; } | ||||
| 		Poco::Logger &Log() { return Poco::Logger::get(AppName()); } | ||||
| 		ProvObjects::FIRMWARE_UPGRADE_RULES FirmwareRules() const { return FWRules_; } | ||||
| 		inline const std::string &AssetDir() { return AssetDir_; } | ||||
| 		void PostInitialization(Poco::Util::Application &self); | ||||
|  | ||||
| 	  	private: | ||||
| 			static Daemon 				            *instance_; | ||||
| 			OpenWifi::ProvisioningDashboard		    DB_{}; | ||||
| 			ProvObjects::FIRMWARE_UPGRADE_RULES     FWRules_{ProvObjects::dont_upgrade}; | ||||
|             std::string                             AssetDir_; | ||||
|             std::unique_ptr<ProvWebSocketClient>    WebSocketProcessor_; | ||||
|     }; | ||||
|  | ||||
| 	inline Daemon * Daemon() { return Daemon::instance(); } | ||||
|     inline void DaemonPostInitialization(Poco::Util::Application &self) { | ||||
|         Daemon()->PostInitialization(self); | ||||
|     } | ||||
| } | ||||
| 	  private: | ||||
| 		static Daemon *instance_; | ||||
| 		OpenWifi::ProvisioningDashboard DB_{}; | ||||
| 		ProvObjects::FIRMWARE_UPGRADE_RULES FWRules_{ProvObjects::dont_upgrade}; | ||||
| 		std::string AssetDir_; | ||||
| 		std::unique_ptr<ProvWebSocketClient> WebSocketProcessor_; | ||||
| 	}; | ||||
|  | ||||
| 	inline Daemon *Daemon() { return Daemon::instance(); } | ||||
| 	void DaemonPostInitialization(Poco::Util::Application &self); | ||||
| } // namespace OpenWifi | ||||
|   | ||||
| @@ -6,15 +6,15 @@ | ||||
| //	Arilia Wireless Inc. | ||||
| // | ||||
| #include "Dashboard.h" | ||||
| #include "StorageService.h" | ||||
| #include "framework/utils.h" | ||||
|  | ||||
| namespace OpenWifi { | ||||
| 	void ProvisioningDashboard::Create() { | ||||
| 		uint64_t Now = OpenWifi::Now(); | ||||
| 		if(LastRun_==0 || (Now-LastRun_)>120) { | ||||
| 		uint64_t Now = Utils::Now(); | ||||
| 		if (LastRun_ == 0 || (Now - LastRun_) > 120) { | ||||
| 			DB_.reset(); | ||||
| 			//  Todo: call dashboard creation code. | ||||
| 			LastRun_ = Now; | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| } // namespace OpenWifi | ||||
|   | ||||
| @@ -8,17 +8,21 @@ | ||||
|  | ||||
| #pragma once | ||||
|  | ||||
| #include "framework/OpenWifiTypes.h" | ||||
| #include "RESTObjects/RESTAPI_ProvObjects.h" | ||||
| #include "framework/OpenWifiTypes.h" | ||||
|  | ||||
| namespace OpenWifi { | ||||
| 	class ProvisioningDashboard { | ||||
| 	  public: | ||||
| 			void Create(); | ||||
| 			[[nodiscard]] const ProvObjects::Report & Report() const { return DB_;} | ||||
| 			inline void Reset() { LastRun_=0; DB_.reset(); } | ||||
| 		void Create(); | ||||
| 		[[nodiscard]] const ProvObjects::Report &Report() const { return DB_; } | ||||
| 		inline void Reset() { | ||||
| 			LastRun_ = 0; | ||||
| 			DB_.reset(); | ||||
| 		} | ||||
|  | ||||
| 	  private: | ||||
| 	        ProvObjects::Report  	DB_{}; | ||||
| 			uint64_t 				LastRun_=0; | ||||
| 		ProvObjects::Report DB_{}; | ||||
| 		uint64_t LastRun_ = 0; | ||||
| 	}; | ||||
| } | ||||
| } // namespace OpenWifi | ||||
|   | ||||
| @@ -6,121 +6,105 @@ | ||||
|  | ||||
| #include <set> | ||||
|  | ||||
| #include "framework/MicroService.h" | ||||
| #include "framework/AppServiceRegistry.h" | ||||
| #include "framework/MicroServiceNames.h" | ||||
| #include "framework/OpenAPIRequests.h" | ||||
| #include "framework/SubSystemServer.h" | ||||
|  | ||||
| #include "Poco/Timer.h" | ||||
|  | ||||
| namespace OpenWifi { | ||||
|  | ||||
|     class DeviceTypeCache : public SubSystemServer { | ||||
|     public: | ||||
|         inline static auto instance() { | ||||
|             static auto instance_ = new DeviceTypeCache; | ||||
|             return instance_; | ||||
|         } | ||||
| 	class DeviceTypeCache : public SubSystemServer { | ||||
| 	  public: | ||||
| 		inline static auto instance() { | ||||
| 			static auto instance_ = new DeviceTypeCache; | ||||
| 			return instance_; | ||||
| 		} | ||||
|  | ||||
|         inline int Start() final { | ||||
|             InitializeCache(); | ||||
|             TimerCallback_ = std::make_unique<Poco::TimerCallback<DeviceTypeCache>>(*this,&DeviceTypeCache::onTimer); | ||||
|             Timer_.setStartInterval( 60 * 1000);            // first run in 60 seconds | ||||
|             Timer_.setPeriodicInterval(1 * 60 * 60 * 1000); // 1 hours | ||||
|             Timer_.start(*TimerCallback_); | ||||
|             return 0; | ||||
|         } | ||||
| 		inline int Start() final { | ||||
| 			InitializeCache(); | ||||
| 			TimerCallback_ = std::make_unique<Poco::TimerCallback<DeviceTypeCache>>( | ||||
| 				*this, &DeviceTypeCache::onTimer); | ||||
| 			Timer_.setStartInterval(60 * 1000);				// first run in 60 seconds | ||||
| 			Timer_.setPeriodicInterval(1 * 60 * 60 * 1000); // 1 hours | ||||
| 			Timer_.start(*TimerCallback_); | ||||
| 			return 0; | ||||
| 		} | ||||
|  | ||||
|         inline void Stop() final { | ||||
|             Timer_.stop(); | ||||
|         } | ||||
| 		inline void Stop() final { Timer_.stop(); } | ||||
|  | ||||
|         inline void onTimer([[maybe_unused]] Poco::Timer & timer) { | ||||
|             UpdateDeviceTypes(); | ||||
|         } | ||||
| 		inline void onTimer([[maybe_unused]] Poco::Timer &timer) { UpdateDeviceTypes(); } | ||||
|  | ||||
|         inline bool IsAcceptableDeviceType(const std::string &D) const { return (DeviceTypes_.find(D)!=DeviceTypes_.end());}; | ||||
|         inline bool AreAcceptableDeviceTypes(const Types::StringVec &S, bool WildCardAllowed=true) const { | ||||
|             for(const auto &i:S) { | ||||
|                 if(WildCardAllowed && i=="*") { | ||||
|                     //   We allow wildcards | ||||
|                 } else if(DeviceTypes_.find(i)==DeviceTypes_.end()) | ||||
|                     return false; | ||||
|             } | ||||
|             return true; | ||||
|         } | ||||
| 		inline bool IsAcceptableDeviceType(const std::string &D) const { | ||||
| 			return (DeviceTypes_.find(D) != DeviceTypes_.end()); | ||||
| 		}; | ||||
| 		inline bool AreAcceptableDeviceTypes(const Types::StringVec &S, | ||||
| 											 bool WildCardAllowed = true) const { | ||||
| 			for (const auto &i : S) { | ||||
| 				if (WildCardAllowed && i == "*") { | ||||
| 					//   We allow wildcards | ||||
| 				} else if (DeviceTypes_.find(i) == DeviceTypes_.end()) | ||||
| 					return false; | ||||
| 			} | ||||
| 			return true; | ||||
| 		} | ||||
|  | ||||
|     private: | ||||
|         std::atomic_bool                                        Initialized_=false; | ||||
|         Poco::Timer                                             Timer_; | ||||
|         std::set<std::string>                                   DeviceTypes_; | ||||
|         std::unique_ptr<Poco::TimerCallback<DeviceTypeCache>>   TimerCallback_; | ||||
| 	  private: | ||||
| 		std::atomic_bool Initialized_ = false; | ||||
| 		Poco::Timer Timer_; | ||||
| 		std::set<std::string> DeviceTypes_; | ||||
| 		std::unique_ptr<Poco::TimerCallback<DeviceTypeCache>> TimerCallback_; | ||||
|  | ||||
|         inline DeviceTypeCache() noexcept: | ||||
|                 SubSystemServer("DeviceTypes", "DEV-TYPES", "devicetypes") | ||||
|         { | ||||
|         } | ||||
| 		inline DeviceTypeCache() noexcept | ||||
| 			: SubSystemServer("DeviceTypes", "DEV-TYPES", "devicetypes") {} | ||||
|  | ||||
|         inline void InitializeCache() { | ||||
|             std::lock_guard G(Mutex_); | ||||
| 		inline void InitializeCache() { | ||||
| 			std::lock_guard G(Mutex_); | ||||
|  | ||||
|             Initialized_ = true; | ||||
|             std::string DeviceTypes; | ||||
|             if(AppServiceRegistry().Get("deviceTypes",DeviceTypes)) { | ||||
|                 Poco::JSON::Parser  P; | ||||
|                 try { | ||||
|                     auto O = P.parse(DeviceTypes).extract<Poco::JSON::Array::Ptr>(); | ||||
|                     for(const auto &i:*O) { | ||||
|                         DeviceTypes_.insert(i.toString()); | ||||
|                     } | ||||
|                 } catch (...) { | ||||
| 			Initialized_ = true; | ||||
| 			std::vector<std::string> DeviceTypes; | ||||
| 			AppServiceRegistry().Get("deviceTypes", DeviceTypes); | ||||
|             std::for_each(DeviceTypes.begin(),DeviceTypes.end(),[&](const std::string &s){ DeviceTypes_.insert(s);}); | ||||
| 		} | ||||
|  | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
| 		inline bool UpdateDeviceTypes() { | ||||
| 			try { | ||||
| 				Types::StringPairVec QueryData; | ||||
|  | ||||
|         inline bool UpdateDeviceTypes() { | ||||
|             try { | ||||
|                 Types::StringPairVec QueryData; | ||||
| 				QueryData.push_back(std::make_pair("deviceSet", "true")); | ||||
| 				OpenAPIRequestGet Req(uSERVICE_FIRMWARE, "/api/v1/firmwares", QueryData, 10000); | ||||
|  | ||||
|                 QueryData.push_back(std::make_pair("deviceSet","true")); | ||||
|                 OpenAPIRequestGet	Req(    uSERVICE_FIRMWARE, | ||||
|                                              "/api/v1/firmwares", | ||||
|                                              QueryData, | ||||
|                                              10000); | ||||
| 				auto Response = Poco::makeShared<Poco::JSON::Object>(); | ||||
| 				auto StatusCode = Req.Do(Response); | ||||
| 				if (StatusCode == Poco::Net::HTTPResponse::HTTP_OK) { | ||||
| 					if (Response->isArray("deviceTypes")) { | ||||
| 						std::lock_guard G(Mutex_); | ||||
| 						DeviceTypes_.clear(); | ||||
| 						auto Array = Response->getArray("deviceTypes"); | ||||
| 						for (const auto &i : *Array) { | ||||
| 							// std::cout << "Adding deviceType:" << i.toString() << std::endl; | ||||
| 							DeviceTypes_.insert(i.toString()); | ||||
| 						} | ||||
| 						SaveCache(); | ||||
| 						return true; | ||||
| 					} | ||||
| 				} else { | ||||
| 				} | ||||
| 			} catch (const Poco::Exception &E) { | ||||
| 				Logger().log(E); | ||||
| 			} | ||||
| 			return false; | ||||
| 		} | ||||
|  | ||||
|                 auto Response = Poco::makeShared<Poco::JSON::Object>(); | ||||
|                 auto StatusCode = Req.Do(Response); | ||||
|                 if( StatusCode == Poco::Net::HTTPResponse::HTTP_OK) { | ||||
|                     if(Response->isArray("deviceTypes")) { | ||||
|                         std::lock_guard G(Mutex_); | ||||
|                         DeviceTypes_.clear(); | ||||
|                         auto Array = Response->getArray("deviceTypes"); | ||||
|                         for(const auto &i:*Array) { | ||||
|                             // std::cout << "Adding deviceType:" << i.toString() << std::endl; | ||||
|                             DeviceTypes_.insert(i.toString()); | ||||
|                         } | ||||
|                         SaveCache(); | ||||
|                         return true; | ||||
|                     } | ||||
|                 } else { | ||||
|                 } | ||||
|             } catch (const Poco::Exception &E) { | ||||
|                 Logger().log(E); | ||||
|             } | ||||
|             return false; | ||||
|         } | ||||
| 		inline void SaveCache() { | ||||
| 			std::lock_guard G(Mutex_); | ||||
|             std::vector<std::string>    DeviceTypes; | ||||
|             std::for_each(DeviceTypes_.begin(),DeviceTypes_.end(),[&](const std::string &s){DeviceTypes.emplace_back(s);}); | ||||
| 			AppServiceRegistry().Set("deviceTypes", DeviceTypes); | ||||
| 		} | ||||
| 	}; | ||||
|  | ||||
|         inline void SaveCache() { | ||||
|             std::lock_guard G(Mutex_); | ||||
| 	inline auto DeviceTypeCache() { return DeviceTypeCache::instance(); } | ||||
|  | ||||
|             Poco::JSON::Array   Arr; | ||||
|             for(auto const &i:DeviceTypes_) | ||||
|                 Arr.add(i); | ||||
|  | ||||
|             std::stringstream OS; | ||||
|             Arr.stringify(OS); | ||||
|  | ||||
|             AppServiceRegistry().Set("deviceTypes", OS.str()); | ||||
|         } | ||||
|     }; | ||||
|  | ||||
|     inline auto DeviceTypeCache() { return DeviceTypeCache::instance(); } | ||||
|  | ||||
| } | ||||
| } // namespace OpenWifi | ||||
| @@ -6,40 +6,48 @@ | ||||
| #include "Daemon.h" | ||||
|  | ||||
| namespace OpenWifi { | ||||
|     int FileDownloader::Start() { | ||||
|         TimerCallback_ = std::make_unique<Poco::TimerCallback<FileDownloader>>(*this,&FileDownloader::onTimer); | ||||
|         Timer_.setStartInterval( 20 * 1000);  // first run in 20 seconds | ||||
|         Timer_.setPeriodicInterval(2 * 60 * 60 * 1000); // 1 hours | ||||
|         Timer_.start(*TimerCallback_); | ||||
|         return 0; | ||||
|     } | ||||
| 	int FileDownloader::Start() { | ||||
| 		poco_information(Logger(), "Starting..."); | ||||
| 		TimerCallback_ = | ||||
| 			std::make_unique<Poco::TimerCallback<FileDownloader>>(*this, &FileDownloader::onTimer); | ||||
| 		Timer_.setStartInterval(20 * 1000);				// first run in 20 seconds | ||||
| 		Timer_.setPeriodicInterval(2 * 60 * 60 * 1000); // 1 hours | ||||
| 		Timer_.start(*TimerCallback_); | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
|     void FileDownloader::Stop() { | ||||
|         Timer_.stop(); | ||||
|         Logger().notice("Stopping."); | ||||
|     } | ||||
| 	void FileDownloader::Stop() { | ||||
| 		poco_information(Logger(), "Stopping..."); | ||||
| 		Timer_.stop(); | ||||
| 		poco_information(Logger(), "Stopped..."); | ||||
| 	} | ||||
|  | ||||
|     void FileDownloader::onTimer([[maybe_unused]] Poco::Timer &timer) { | ||||
|         const static std::vector<std::pair<std::string,std::string>> Files | ||||
| 	void FileDownloader::onTimer([[maybe_unused]] Poco::Timer &timer) { | ||||
| 		const static std::vector<std::pair<std::string, std::string>> Files{ | ||||
|             { | ||||
|                 {"https://raw.githubusercontent.com/blogic/ucentral-schema/main/ucentral.schema.json", "ucentral.schema.json" }, | ||||
|                 {"https://ucentral.io/ucentral.schema.pretty.json", "ucentral.schema.pretty.json" } | ||||
|             }; | ||||
|  | ||||
|         Utils::SetThreadName("file-dmnldr"); | ||||
|  | ||||
|         for(const auto &[url,filename]:Files) { | ||||
|             try { | ||||
|                 std::string FileContent; | ||||
|                 if (Utils::wgets(url, FileContent)) { | ||||
|                     std::ofstream OutputStream(Daemon()->AssetDir() + "/" + filename, | ||||
|                                      std::ios_base::out | std::ios_base::trunc); | ||||
|                     OutputStream << FileContent; | ||||
|                     Logger().warning(Poco::format("File %s was downloaded",url)); | ||||
|                 } | ||||
|             } catch(...) { | ||||
|                 Logger().warning(Poco::format("File %s could not be downloaded",url)); | ||||
|                 "https://raw.githubusercontent.com/Telecominfraproject/wlan-ucentral-schema/main/ucentral.schema.pretty.json", | ||||
|                 "ucentral.schema.pretty.json" | ||||
|             }, | ||||
|             { | ||||
|                 "https://raw.githubusercontent.com/Telecominfraproject/wlan-ucentral-schema/main/ucentral.schema.json", | ||||
|                 "ucentral.schema.json" | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| } | ||||
|         }; | ||||
|  | ||||
| 		Utils::SetThreadName("file-dmnldr"); | ||||
|  | ||||
| 		for (const auto &[url, filename] : Files) { | ||||
| 			try { | ||||
| 				std::string FileContent; | ||||
| 				if (Utils::wgets(url, FileContent)) { | ||||
| 					std::ofstream OutputStream(Daemon()->AssetDir() + "/" + filename, | ||||
| 											   std::ios_base::out | std::ios_base::trunc); | ||||
| 					OutputStream << FileContent; | ||||
| 					Logger().warning(Poco::format("File %s was downloaded", url)); | ||||
| 				} | ||||
| 			} catch (...) { | ||||
| 				Logger().warning(Poco::format("File %s could not be downloaded", url)); | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| } // namespace OpenWifi | ||||
| @@ -3,32 +3,30 @@ | ||||
| // | ||||
|  | ||||
| #pragma once | ||||
| #include "framework/MicroService.h" | ||||
| #include "Poco/Timer.h" | ||||
| #include "framework/SubSystemServer.h" | ||||
|  | ||||
| namespace OpenWifi { | ||||
|  | ||||
|     class FileDownloader : public SubSystemServer { | ||||
|     public: | ||||
| 	class FileDownloader : public SubSystemServer { | ||||
| 	  public: | ||||
| 		static auto instance() { | ||||
| 			static auto instance_ = new FileDownloader; | ||||
| 			return instance_; | ||||
| 		} | ||||
|  | ||||
|         static auto instance() { | ||||
|             static auto instance_ = new FileDownloader; | ||||
|             return instance_; | ||||
|         } | ||||
| 		int Start() override; | ||||
| 		void Stop() override; | ||||
| 		void onTimer(Poco::Timer &timer); | ||||
|  | ||||
|         int Start() override; | ||||
|         void Stop() override; | ||||
|         void onTimer(Poco::Timer & timer); | ||||
| 	  private: | ||||
| 		Poco::Timer Timer_; | ||||
| 		std::unique_ptr<Poco::TimerCallback<FileDownloader>> TimerCallback_; | ||||
| 		std::atomic_bool Running_ = false; | ||||
|  | ||||
|     private: | ||||
|         Poco::Timer                                         Timer_; | ||||
|         std::unique_ptr<Poco::TimerCallback<FileDownloader>>       TimerCallback_; | ||||
|         std::atomic_bool Running_ = false; | ||||
| 		FileDownloader() noexcept | ||||
| 			: SubSystemServer("FileDownloader", "FILE-DOWNLOADER", "downloader") {} | ||||
| 	}; | ||||
|  | ||||
|         FileDownloader() noexcept: | ||||
|                 SubSystemServer("FileDownloader", "FILE-DOWNLOADER", "downloader") { | ||||
|         } | ||||
|     }; | ||||
|  | ||||
|     inline auto FileDownloader() { return FileDownloader::instance(); } | ||||
| } | ||||
| 	inline auto FileDownloader() { return FileDownloader::instance(); } | ||||
| } // namespace OpenWifi | ||||
|   | ||||
| @@ -4,79 +4,79 @@ | ||||
|  | ||||
| #pragma once | ||||
|  | ||||
| #include "framework/MicroService.h" | ||||
| #include "Poco/Net/IPAddress.h" | ||||
|  | ||||
| #include "framework/MicroServiceFuncs.h" | ||||
| #include "framework/SubSystemServer.h" | ||||
|  | ||||
| #include "nlohmann/json.hpp" | ||||
|  | ||||
| namespace OpenWifi { | ||||
|  | ||||
| 	class IPToCountryProvider { | ||||
| 	  public: | ||||
| 		virtual bool Init() = 0 ; | ||||
| 		virtual Poco::URI URI(const std::string & IPAddress) = 0; | ||||
| 		virtual std::string Country( const std::string & Response ) = 0 ; | ||||
| 		virtual ~IPToCountryProvider() { | ||||
| 		}; | ||||
| 		virtual bool Init() = 0; | ||||
| 		virtual Poco::URI URI(const std::string &IPAddress) = 0; | ||||
| 		virtual std::string Country(const std::string &Response) = 0; | ||||
| 		virtual ~IPToCountryProvider(){}; | ||||
| 	}; | ||||
|  | ||||
| 	class IPInfo : public IPToCountryProvider { | ||||
| 	  public: | ||||
| 		static std::string Name() { return "ipinfo"; } | ||||
| 		inline bool Init() override { | ||||
| 			Key_ = MicroService::instance().ConfigGetString("iptocountry.ipinfo.token", ""); | ||||
| 			Key_ = MicroServiceConfigGetString("iptocountry.ipinfo.token", ""); | ||||
| 			return !Key_.empty(); | ||||
| 		} | ||||
|  | ||||
| 		[[nodiscard]] inline Poco::URI URI(const std::string & IPAddress) override { | ||||
| 			Poco::URI	U("https://ipinfo.io"); | ||||
| 		[[nodiscard]] inline Poco::URI URI(const std::string &IPAddress) override { | ||||
| 			Poco::URI U("https://ipinfo.io"); | ||||
| 			U.setPath("/" + IPAddress); | ||||
| 			U.addQueryParameter("token",Key_); | ||||
| 			U.addQueryParameter("token", Key_); | ||||
| 			return U; | ||||
| 		} | ||||
|  | ||||
| 		inline std::string Country( const std::string & Response ) override { | ||||
| 		inline std::string Country(const std::string &Response) override { | ||||
| 			try { | ||||
| 				nlohmann::json IPInfo = nlohmann::json::parse(Response); | ||||
| 				if (IPInfo.contains("country") && IPInfo["country"].is_string()) { | ||||
| 					return IPInfo["country"]; | ||||
| 				} | ||||
| 			} catch (...) { | ||||
|  | ||||
| 			} | ||||
| 			return ""; | ||||
| 		} | ||||
|  | ||||
| 	  private: | ||||
| 		std::string Key_; | ||||
|  | ||||
| 	}; | ||||
|  | ||||
| 	class IPData : public IPToCountryProvider { | ||||
| 	  public: | ||||
| 		static std::string Name() { return "ipdata"; } | ||||
| 		inline bool Init() override { | ||||
| 			Key_ = MicroService::instance().ConfigGetString("iptocountry.ipdata.apikey", ""); | ||||
| 			Key_ = MicroServiceConfigGetString("iptocountry.ipdata.apikey", ""); | ||||
| 			return !Key_.empty(); | ||||
| 		} | ||||
|  | ||||
| 		[[nodiscard]] inline Poco::URI URI(const std::string & IPAddress) override { | ||||
| 			Poco::URI	U("https://api.ipdata.co"); | ||||
| 		[[nodiscard]] inline Poco::URI URI(const std::string &IPAddress) override { | ||||
| 			Poco::URI U("https://api.ipdata.co"); | ||||
| 			U.setPath("/" + IPAddress); | ||||
| 			U.addQueryParameter("api-key",Key_); | ||||
| 			U.addQueryParameter("api-key", Key_); | ||||
| 			return U; | ||||
| 		} | ||||
|  | ||||
| 		inline std::string Country( const std::string & Response ) override { | ||||
| 		inline std::string Country(const std::string &Response) override { | ||||
| 			try { | ||||
| 				nlohmann::json IPInfo = nlohmann::json::parse(Response); | ||||
| 				if (IPInfo.contains("country_code") && IPInfo["country_code"].is_string()) { | ||||
| 					return IPInfo["country_code"]; | ||||
| 				} | ||||
| 			} catch (...) { | ||||
|  | ||||
| 			} | ||||
| 			return ""; | ||||
| 		} | ||||
|  | ||||
| 	  private: | ||||
| 		std::string Key_; | ||||
| 	}; | ||||
| @@ -85,37 +85,37 @@ namespace OpenWifi { | ||||
| 	  public: | ||||
| 		static std::string Name() { return "ip2location"; } | ||||
| 		inline bool Init() override { | ||||
| 			Key_ = MicroService::instance().ConfigGetString("iptocountry.ip2location.apikey", ""); | ||||
| 			Key_ = MicroServiceConfigGetString("iptocountry.ip2location.apikey", ""); | ||||
| 			return !Key_.empty(); | ||||
| 		} | ||||
|  | ||||
| 		[[nodiscard]] inline Poco::URI URI(const std::string & IPAddress) override { | ||||
| 			Poco::URI	U("https://api.ip2location.com/v2"); | ||||
| 		[[nodiscard]] inline Poco::URI URI(const std::string &IPAddress) override { | ||||
| 			Poco::URI U("https://api.ip2location.com/v2"); | ||||
| 			U.setPath("/"); | ||||
| 			U.addQueryParameter("ip", IPAddress); | ||||
| 			U.addQueryParameter("package", "WS1"); | ||||
| 			U.addQueryParameter("key",Key_); | ||||
| 			U.addQueryParameter("key", Key_); | ||||
| 			return U; | ||||
| 		} | ||||
|  | ||||
| 		inline std::string Country( const std::string & Response ) override { | ||||
| 		inline std::string Country(const std::string &Response) override { | ||||
| 			try { | ||||
| 				nlohmann::json IPInfo = nlohmann::json::parse(Response); | ||||
| 				if (IPInfo.contains("country_code") && IPInfo["country_code"].is_string()) { | ||||
| 					return IPInfo["country_code"]; | ||||
| 				} | ||||
| 			} catch (...) { | ||||
|  | ||||
| 			} | ||||
| 			return ""; | ||||
| 		} | ||||
|  | ||||
| 	  private: | ||||
| 		std::string Key_; | ||||
| 	}; | ||||
|  | ||||
| 	template<typename BaseClass, typename T, typename... Args> | ||||
| 	std::unique_ptr<BaseClass> IPLocationProvider(const std::string & RequestProvider ) { | ||||
| 		if(T::Name()==RequestProvider) { | ||||
| 	template <typename BaseClass, typename T, typename... Args> | ||||
| 	std::unique_ptr<BaseClass> IPLocationProvider(const std::string &RequestProvider) { | ||||
| 		if (T::Name() == RequestProvider) { | ||||
| 			return std::make_unique<T>(); | ||||
| 		} | ||||
| 		if constexpr (sizeof...(Args) == 0) { | ||||
| @@ -133,37 +133,40 @@ namespace OpenWifi { | ||||
| 		} | ||||
|  | ||||
| 		inline int Start() final { | ||||
| 			ProviderName_ = MicroService::instance().ConfigGetString("iptocountry.provider",""); | ||||
| 			if(!ProviderName_.empty()) { | ||||
| 				Provider_ = IPLocationProvider<IPToCountryProvider, IPInfo, IPData, IP2Location>(ProviderName_); | ||||
| 				if(Provider_!= nullptr) { | ||||
| 			poco_notice(Logger(), "Starting..."); | ||||
| 			ProviderName_ = MicroServiceConfigGetString("iptocountry.provider", ""); | ||||
| 			if (!ProviderName_.empty()) { | ||||
| 				Provider_ = IPLocationProvider<IPToCountryProvider, IPInfo, IPData, IP2Location>( | ||||
| 					ProviderName_); | ||||
| 				if (Provider_ != nullptr) { | ||||
| 					Enabled_ = Provider_->Init(); | ||||
| 				} | ||||
| 			} | ||||
| 			Default_ = MicroService::instance().ConfigGetString("iptocountry.default", "US"); | ||||
| 			Default_ = MicroServiceConfigGetString("iptocountry.default", "US"); | ||||
| 			return 0; | ||||
| 		} | ||||
|  | ||||
| 		inline void Stop() final { | ||||
| 			poco_notice(Logger(), "Stopping..."); | ||||
| 			//	Nothing to do - just to provide the same look at the others. | ||||
| 			poco_notice(Logger(), "Stopped..."); | ||||
| 		} | ||||
|  | ||||
| 		[[nodiscard]] static inline std::string ReformatAddress(const std::string & I ) | ||||
| 		{ | ||||
| 			if(I.substr(0,7) == "::ffff:") | ||||
| 			{ | ||||
| 				std::string ip = I.substr(7 ); | ||||
| 		[[nodiscard]] static inline std::string ReformatAddress(const std::string &I) { | ||||
| 			if (I.substr(0, 7) == "::ffff:") { | ||||
| 				std::string ip = I.substr(7); | ||||
| 				return ip; | ||||
| 			} | ||||
| 			return I; | ||||
| 		} | ||||
|  | ||||
| 		inline std::string Get(const Poco::Net::IPAddress & IP) { | ||||
| 		inline std::string Get(const Poco::Net::IPAddress &IP) { | ||||
| 			if (!Enabled_) | ||||
| 				return Default_; | ||||
| 			return Get(ReformatAddress(IP.toString())); | ||||
| 		} | ||||
|  | ||||
| 		inline std::string Get(const std::string & IP) { | ||||
| 		inline std::string Get(const std::string &IP) { | ||||
| 			if (!Enabled_) | ||||
| 				return Default_; | ||||
| 			try { | ||||
| @@ -171,10 +174,10 @@ namespace OpenWifi { | ||||
| 				std::string Response; | ||||
| 				if (Utils::wgets(URL, Response)) { | ||||
| 					auto Answer = Provider_->Country(Response); | ||||
| 					if(!Answer.empty()) | ||||
| 					if (!Answer.empty()) | ||||
| 						return Answer; | ||||
| 				} | ||||
| 			} catch(...) { | ||||
| 			} catch (...) { | ||||
| 			} | ||||
| 			return Default_; | ||||
| 		} | ||||
| @@ -182,17 +185,14 @@ namespace OpenWifi { | ||||
| 		inline auto Enabled() const { return Enabled_; } | ||||
|  | ||||
| 	  private: | ||||
| 		bool 									Enabled_=false; | ||||
| 		std::string 							Default_; | ||||
| 		std::unique_ptr<IPToCountryProvider>	Provider_; | ||||
| 		std::string 							ProviderName_; | ||||
| 		bool Enabled_ = false; | ||||
| 		std::string Default_; | ||||
| 		std::unique_ptr<IPToCountryProvider> Provider_; | ||||
| 		std::string ProviderName_; | ||||
|  | ||||
| 		FindCountryFromIP() noexcept: | ||||
| 			SubSystemServer("IpToCountry", "IPTOC-SVR", "iptocountry") | ||||
| 		{ | ||||
| 		} | ||||
| 		FindCountryFromIP() noexcept : SubSystemServer("IpToCountry", "IPTOC-SVR", "iptocountry") {} | ||||
| 	}; | ||||
|  | ||||
| 	inline auto FindCountryFromIP() { return FindCountryFromIP::instance(); } | ||||
|  | ||||
| } | ||||
| } // namespace OpenWifi | ||||
|   | ||||
| @@ -3,56 +3,63 @@ | ||||
| // | ||||
|  | ||||
| #include "JobController.h" | ||||
| #include "fmt/format.h" | ||||
| #include "framework/utils.h" | ||||
|  | ||||
| namespace OpenWifi { | ||||
|  | ||||
|     void RegisterJobTypes(); | ||||
| 	void RegisterJobTypes(); | ||||
|  | ||||
|     int JobController::Start() { | ||||
| 	int JobController::Start() { | ||||
| 		poco_information(Logger(), "Starting..."); | ||||
| 		RegisterJobTypes(); | ||||
| 		if (!Running_) | ||||
| 			Thr_.start(*this); | ||||
|  | ||||
|         RegisterJobTypes(); | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
|         if(!Running_) | ||||
|             Thr_.start(*this); | ||||
| 	void JobController::Stop() { | ||||
| 		if (Running_) { | ||||
| 			poco_information(Logger(), "Stopping..."); | ||||
| 			Running_ = false; | ||||
| 			Thr_.join(); | ||||
| 			poco_information(Logger(), "Stopped..."); | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
|         return 0; | ||||
|     } | ||||
| 	void JobController::run() { | ||||
| 		Running_ = true; | ||||
| 		Utils::SetThreadName("job-controller"); | ||||
| 		while (Running_) { | ||||
| 			Poco::Thread::trySleep(2000); | ||||
|  | ||||
|     void JobController::Stop() { | ||||
|         if(Running_) { | ||||
|             Running_ = false; | ||||
|             Thr_.join(); | ||||
|         } | ||||
|     } | ||||
| 			std::lock_guard G(Mutex_); | ||||
|  | ||||
|     void JobController::run() { | ||||
|         Running_ = true ; | ||||
|         Utils::SetThreadName("job-controller"); | ||||
|         while(Running_) { | ||||
|             Poco::Thread::trySleep(2000); | ||||
| 			for (auto ¤t_job : jobs_) { | ||||
| 				if (current_job != nullptr) { | ||||
| 					if (current_job->Started() == 0 && Pool_.used() < Pool_.available()) { | ||||
| 						poco_information(current_job->Logger(), | ||||
| 										 fmt::format("Starting {}: {}", current_job->JobId(), | ||||
| 													 current_job->Name())); | ||||
| 						current_job->Start(); | ||||
| 						Pool_.start(*current_job); | ||||
| 					} | ||||
| 				} | ||||
| 			} | ||||
|  | ||||
|             std::lock_guard G(Mutex_); | ||||
|  | ||||
|             for(auto ¤t_job:jobs_) { | ||||
|                 if(current_job!=nullptr) { | ||||
|                     if(current_job->Started()==0 && Pool_.used()<Pool_.available()) { | ||||
|                         current_job->Logger().information(fmt::format("Starting {}: {}",current_job->JobId(),current_job->Name())); | ||||
|                         current_job->Start(); | ||||
|                         Pool_.start(*current_job); | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
|  | ||||
|             for(auto it = jobs_.begin(); it!=jobs_.end();) {\ | ||||
|                 auto current_job = *it; | ||||
|                 if(current_job!=nullptr && current_job->Completed()!=0) { | ||||
|                     current_job->Logger().information(fmt::format("Completed {}: {}",current_job->JobId(),current_job->Name())); | ||||
|                     it = jobs_.erase(it); | ||||
|                     delete current_job; | ||||
|                 } else { | ||||
|                     ++it; | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 			for (auto it = jobs_.begin(); it != jobs_.end();) { | ||||
| 				auto current_job = *it; | ||||
| 				if (current_job != nullptr && current_job->Completed() != 0) { | ||||
| 					poco_information( | ||||
| 						current_job->Logger(), | ||||
| 						fmt::format("Completed {}: {}", current_job->JobId(), current_job->Name())); | ||||
| 					it = jobs_.erase(it); | ||||
| 					delete current_job; | ||||
| 				} else { | ||||
| 					++it; | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| } // namespace OpenWifi | ||||
| @@ -4,77 +4,72 @@ | ||||
|  | ||||
| #pragma once | ||||
|  | ||||
| #include <vector> | ||||
| #include <utility> | ||||
| #include "RESTObjects/RESTAPI_SecurityObjects.h" | ||||
| #include "framework/SubSystemServer.h" | ||||
| #include "framework/utils.h" | ||||
| #include <functional> | ||||
| #include <list> | ||||
| #include "framework/MicroService.h" | ||||
| #include <utility> | ||||
| #include <vector> | ||||
|  | ||||
| namespace OpenWifi { | ||||
|  | ||||
|     class Job : public Poco::Runnable { | ||||
|     public: | ||||
|         Job(const std::string &JobID, const std::string &name, const std::vector<std::string> & parameters, uint64_t when, const SecurityObjects::UserInfo &UI, Poco::Logger &L) : | ||||
|             jobId_(JobID), | ||||
|             name_(name), | ||||
|             parameters_(parameters), | ||||
|             when_(when), | ||||
|             userinfo_(UI), | ||||
|             Logger_(L) | ||||
|         {}; | ||||
| 	class Job : public Poco::Runnable { | ||||
| 	  public: | ||||
| 		Job(const std::string &JobID, const std::string &name, | ||||
| 			const std::vector<std::string> ¶meters, uint64_t when, | ||||
| 			const SecurityObjects::UserInfo &UI, Poco::Logger &L) | ||||
| 			: jobId_(JobID), name_(name), parameters_(parameters), when_(when), userinfo_(UI), | ||||
| 			  Logger_(L){}; | ||||
|  | ||||
|         virtual void run() = 0; | ||||
|         [[nodiscard]] std::string Name() const { return name_; } | ||||
|         const SecurityObjects::UserInfo & UserInfo() const { return userinfo_; } | ||||
|         Poco::Logger & Logger() { return Logger_; } | ||||
|         const std::string & JobId() const { return jobId_; } | ||||
|         const std::string & Parameter(int x) const { return parameters_[x];} | ||||
|         uint64_t When() const { return when_; } | ||||
|         void Start() { started_ = OpenWifi::Now(); } | ||||
|         uint64_t Started() const { return started_; } | ||||
|         uint64_t Completed() const { return completed_;} | ||||
|         void Complete() { completed_ = OpenWifi::Now(); } | ||||
| 		virtual void run() = 0; | ||||
| 		[[nodiscard]] std::string Name() const { return name_; } | ||||
| 		const SecurityObjects::UserInfo &UserInfo() const { return userinfo_; } | ||||
| 		Poco::Logger &Logger() { return Logger_; } | ||||
| 		const std::string &JobId() const { return jobId_; } | ||||
| 		const std::string &Parameter(int x) const { return parameters_[x]; } | ||||
| 		uint64_t When() const { return when_; } | ||||
| 		void Start() { started_ = Utils::Now(); } | ||||
| 		uint64_t Started() const { return started_; } | ||||
| 		uint64_t Completed() const { return completed_; } | ||||
| 		void Complete() { completed_ = Utils::Now(); } | ||||
|  | ||||
|     private: | ||||
|         std::string                 jobId_; | ||||
|         std::string                 name_; | ||||
|         std::vector<std::string>    parameters_; | ||||
|         uint64_t                    when_=0; | ||||
|         SecurityObjects::UserInfo   userinfo_; | ||||
|         Poco::Logger                & Logger_; | ||||
|         uint64_t                    started_=0; | ||||
|         uint64_t                    completed_=0; | ||||
|     }; | ||||
| 	  private: | ||||
| 		std::string jobId_; | ||||
| 		std::string name_; | ||||
| 		std::vector<std::string> parameters_; | ||||
| 		uint64_t when_ = 0; | ||||
| 		SecurityObjects::UserInfo userinfo_; | ||||
| 		Poco::Logger &Logger_; | ||||
| 		uint64_t started_ = 0; | ||||
| 		uint64_t completed_ = 0; | ||||
| 	}; | ||||
|  | ||||
|     class JobController : public SubSystemServer, Poco::Runnable { | ||||
|         public: | ||||
|             static auto instance() { | ||||
|                 static auto instance_ = new JobController; | ||||
|                 return instance_; | ||||
|             } | ||||
| 	class JobController : public SubSystemServer, Poco::Runnable { | ||||
| 	  public: | ||||
| 		static auto instance() { | ||||
| 			static auto instance_ = new JobController; | ||||
| 			return instance_; | ||||
| 		} | ||||
|  | ||||
|             int Start() override; | ||||
|             void Stop() override; | ||||
|             void run() override; | ||||
|             inline void wakeup() { Thr_.wakeUp(); } | ||||
| 		int Start() override; | ||||
| 		void Stop() override; | ||||
| 		void run() override; | ||||
| 		inline void wakeup() { Thr_.wakeUp(); } | ||||
|  | ||||
|             void AddJob( Job* newJob ) { | ||||
|                 std::lock_guard G(Mutex_); | ||||
|                 jobs_.push_back(newJob); | ||||
|             } | ||||
| 		void AddJob(Job *newJob) { | ||||
| 			std::lock_guard G(Mutex_); | ||||
| 			jobs_.push_back(newJob); | ||||
| 		} | ||||
|  | ||||
|         private: | ||||
|             Poco::Thread                        Thr_; | ||||
|             std::atomic_bool                    Running_=false; | ||||
|             std::list<Job *>                    jobs_; | ||||
|             Poco::ThreadPool                    Pool_; | ||||
| 	  private: | ||||
| 		Poco::Thread Thr_; | ||||
| 		std::atomic_bool Running_ = false; | ||||
| 		std::list<Job *> jobs_; | ||||
| 		Poco::ThreadPool Pool_; | ||||
|  | ||||
|         JobController() noexcept: | ||||
|             SubSystemServer("JobController", "JOB-SVR", "job") | ||||
|             { | ||||
|             } | ||||
|     }; | ||||
|     inline auto JobController() { return JobController::instance(); } | ||||
|  | ||||
| } | ||||
| 		JobController() noexcept : SubSystemServer("JobController", "JOB-SVR", "job") {} | ||||
| 	}; | ||||
| 	inline auto JobController() { return JobController::instance(); } | ||||
|  | ||||
| } // namespace OpenWifi | ||||
|   | ||||
| @@ -4,8 +4,6 @@ | ||||
|  | ||||
| namespace OpenWifi { | ||||
|  | ||||
|     void RegisterJobTypes() { | ||||
| 	void RegisterJobTypes() {} | ||||
|  | ||||
|     } | ||||
|  | ||||
| } | ||||
| } // namespace OpenWifi | ||||
|   | ||||
| @@ -4,45 +4,43 @@ | ||||
|  | ||||
| #pragma once | ||||
|  | ||||
| #include "framework/MicroService.h" | ||||
| #include "RESTObjects/RESTAPI_ProvObjects.h" | ||||
| #include "framework/KafkaManager.h" | ||||
| #include "framework/KafkaTopics.h" | ||||
|  | ||||
| namespace OpenWifi { | ||||
|  | ||||
|     enum ProvisioningOperation { | ||||
|         creation=0, modification, removal | ||||
|     }; | ||||
| 	enum ProvisioningOperation { creation = 0, modification, removal }; | ||||
|  | ||||
|     template <typename ObjectType> inline bool UpdateKafkaProvisioningObject( ProvisioningOperation op, const ObjectType & obj) { | ||||
|         static std::vector<std::string> Ops{ "creation", "modification", "removal" }; | ||||
| 	template <typename ObjectType> | ||||
| 	inline bool UpdateKafkaProvisioningObject(ProvisioningOperation op, const ObjectType &obj) { | ||||
| 		static std::vector<std::string> Ops{"creation", "modification", "removal"}; | ||||
|  | ||||
|         std::string OT{"object"}; | ||||
|         if constexpr(std::is_same_v<ObjectType,ProvObjects::Venue>) { | ||||
|             OT = "Venue"; | ||||
|         } | ||||
|         if constexpr(std::is_same_v<ObjectType,ProvObjects::Entity>) { | ||||
|             OT = "Entity"; | ||||
|         } | ||||
|         if constexpr(std::is_same_v<ObjectType,ProvObjects::InventoryTag>) { | ||||
|             OT = "InventoryTag"; | ||||
|         } | ||||
|         if constexpr(std::is_same_v<ObjectType,ProvObjects::Contact>) { | ||||
|             OT = "Contact"; | ||||
|         } | ||||
|         if constexpr(std::is_same_v<ObjectType,ProvObjects::Location>) { | ||||
|             OT = "Location"; | ||||
|         } | ||||
|         if constexpr(std::is_same_v<ObjectType,ProvObjects::DeviceConfiguration>) { | ||||
|             OT = "DeviceConfiguration"; | ||||
|         } | ||||
| 		std::string OT{"object"}; | ||||
| 		if constexpr (std::is_same_v<ObjectType, ProvObjects::Venue>) { | ||||
| 			OT = "Venue"; | ||||
| 		} | ||||
| 		if constexpr (std::is_same_v<ObjectType, ProvObjects::Entity>) { | ||||
| 			OT = "Entity"; | ||||
| 		} | ||||
| 		if constexpr (std::is_same_v<ObjectType, ProvObjects::InventoryTag>) { | ||||
| 			OT = "InventoryTag"; | ||||
| 		} | ||||
| 		if constexpr (std::is_same_v<ObjectType, ProvObjects::Contact>) { | ||||
| 			OT = "Contact"; | ||||
| 		} | ||||
| 		if constexpr (std::is_same_v<ObjectType, ProvObjects::Location>) { | ||||
| 			OT = "Location"; | ||||
| 		} | ||||
| 		if constexpr (std::is_same_v<ObjectType, ProvObjects::DeviceConfiguration>) { | ||||
| 			OT = "DeviceConfiguration"; | ||||
| 		} | ||||
|  | ||||
|         Poco::JSON::Object  Payload; | ||||
|         obj.to_json(Payload); | ||||
|         Payload.set("ObjectType",OT); | ||||
|         std::ostringstream OS; | ||||
|         Payload.stringify(OS); | ||||
|         KafkaManager()->PostMessage(KafkaTopics::PROVISIONING_CHANGE, Ops[op] , OS.str()); | ||||
| 		Poco::JSON::Object Payload; | ||||
| 		obj.to_json(Payload); | ||||
| 		Payload.set("ObjectType", OT); | ||||
| 		KafkaManager()->PostMessage(KafkaTopics::PROVISIONING_CHANGE, Ops[op], Payload); | ||||
|  | ||||
|         return true; | ||||
|     } | ||||
| } | ||||
| 		return true; | ||||
| 	} | ||||
| } // namespace OpenWifi | ||||
| @@ -4,164 +4,180 @@ | ||||
|  | ||||
| #include "ProvWebSocketClient.h" | ||||
|  | ||||
| #include "StorageService.h" | ||||
| #include "SerialNumberCache.h" | ||||
| #include "StorageService.h" | ||||
| #include "framework/UI_WebSocketClientServer.h" | ||||
| #include "sdks/SDK_sec.h" | ||||
|  | ||||
| namespace OpenWifi { | ||||
|  | ||||
|     ProvWebSocketClient::ProvWebSocketClient(Poco::Logger &Logger) : | ||||
|             Logger_(Logger){ | ||||
|         WebSocketClientServer()->SetProcessor(this); | ||||
|     } | ||||
| 	ProvWebSocketClient::ProvWebSocketClient(Poco::Logger &Logger) : Logger_(Logger) { | ||||
| 		UI_WebSocketClientServer()->SetProcessor(this); | ||||
| 	} | ||||
|  | ||||
|     ProvWebSocketClient::~ProvWebSocketClient() { | ||||
|         WebSocketClientServer()->SetProcessor(nullptr); | ||||
|     } | ||||
| 	ProvWebSocketClient::~ProvWebSocketClient() { | ||||
| 		UI_WebSocketClientServer()->SetProcessor(nullptr); | ||||
| 	} | ||||
|  | ||||
|     void ProvWebSocketClient::ws_command_serial_number_search(const Poco::JSON::Object::Ptr &O, | ||||
|                                                               bool &Done, std::string &Answer) { | ||||
|         Done = false; | ||||
|         auto Prefix = O->get("serial_prefix").toString(); | ||||
|         Poco::toLowerInPlace(Prefix); | ||||
|         Logger().information(Poco::format("serial_number_search: %s", Prefix)); | ||||
|         if (!Prefix.empty() && Prefix.length() < 13) { | ||||
|             std::vector<uint64_t> Numbers; | ||||
|             SerialNumberCache()->FindNumbers(Prefix, 50, Numbers); | ||||
|             Poco::JSON::Array Arr; | ||||
|             for (const auto &i : Numbers) | ||||
|                 Arr.add(Utils::int_to_hex(i)); | ||||
|             Poco::JSON::Object RetObj; | ||||
|             RetObj.set("serialNumbers", Arr); | ||||
|             std::ostringstream SS; | ||||
|             Poco::JSON::Stringifier::stringify(RetObj, SS); | ||||
|             Answer = SS.str(); | ||||
|         } | ||||
|     } | ||||
| 	void ProvWebSocketClient::ws_command_serial_number_search(const Poco::JSON::Object::Ptr &O, | ||||
| 															  bool &Done, std::string &Answer) { | ||||
| 		Done = false; | ||||
| 		auto Prefix = ORM::Escape(O->get("serial_prefix").toString()); | ||||
| 		Poco::toLowerInPlace(Prefix); | ||||
| 		Logger().information(Poco::format("serial_number_search: %s", Prefix)); | ||||
| 		if (!Prefix.empty() && Prefix.length() < 13) { | ||||
| 			std::vector<uint64_t> Numbers; | ||||
| 			SerialNumberCache()->FindNumbers(Prefix, 50, Numbers); | ||||
| 			Poco::JSON::Array Arr; | ||||
| 			for (const auto &i : Numbers) | ||||
| 				Arr.add(Utils::int_to_hex(i)); | ||||
| 			Poco::JSON::Object RetObj; | ||||
| 			RetObj.set("serialNumbers", Arr); | ||||
| 			std::ostringstream SS; | ||||
| 			Poco::JSON::Stringifier::stringify(RetObj, SS); | ||||
| 			Answer = SS.str(); | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
|     void ProvWebSocketClient::ws_command_address_completion(const Poco::JSON::Object::Ptr &O, bool &Done, std::string &Answer) { | ||||
|         Done = false; | ||||
|         auto Address = O->get("address").toString(); | ||||
|         Answer = GoogleGeoCodeCall(Address); | ||||
|     } | ||||
| 	void ProvWebSocketClient::ws_command_address_completion(const Poco::JSON::Object::Ptr &O, | ||||
| 															bool &Done, std::string &Answer) { | ||||
| 		Done = false; | ||||
| 		auto Address = O->get("address").toString(); | ||||
| 		Answer = GoogleGeoCodeCall(Address); | ||||
| 	} | ||||
|  | ||||
|     void ProvWebSocketClient::ws_command_exit([[maybe_unused]] const Poco::JSON::Object::Ptr &O, bool &Done, std::string &Answer) { | ||||
|         Done = true; | ||||
|         Answer = R"lit({ "closing" : "Goodbye! Aurevoir! Hasta la vista!" })lit"; | ||||
|     } | ||||
| 	void ProvWebSocketClient::ws_command_exit([[maybe_unused]] const Poco::JSON::Object::Ptr &O, | ||||
| 											  bool &Done, std::string &Answer) { | ||||
| 		Done = true; | ||||
| 		Answer = R"lit({ "closing" : "Goodbye! Aurevoir! Hasta la vista!" })lit"; | ||||
| 	} | ||||
|  | ||||
|     void ProvWebSocketClient::ws_command_invalid([[maybe_unused]] const Poco::JSON::Object::Ptr &O, bool &Done, std::string &Answer) { | ||||
|         Done = false; | ||||
|         Answer = std::string{R"lit({ "error" : "invalid command" })lit"}; | ||||
|     } | ||||
| 	void ProvWebSocketClient::ws_command_invalid([[maybe_unused]] const Poco::JSON::Object::Ptr &O, | ||||
| 												 bool &Done, std::string &Answer) { | ||||
| 		Done = false; | ||||
| 		Answer = std::string{R"lit({ "error" : "invalid command" })lit"}; | ||||
| 	} | ||||
|  | ||||
|     void ProvWebSocketClient::ws_command_subuser_search( const Poco::JSON::Object::Ptr &O, bool &Done, std::string &Answer) { | ||||
|         Done = false; | ||||
|         auto operatorId = O->get("operatorId").toString(); | ||||
|         std::string nameSearch, emailSearch; | ||||
|         OpenWifi::RESTAPIHandler::AssignIfPresent(O,"nameSearch",nameSearch); | ||||
|         OpenWifi::RESTAPIHandler::AssignIfPresent(O,"emailSearch",emailSearch); | ||||
|         SecurityObjects::UserInfoList   Users; | ||||
|         SDK::Sec::Subscriber::Search(nullptr,operatorId,nameSearch,emailSearch,Users); | ||||
| 	void ProvWebSocketClient::ws_command_subuser_search(const Poco::JSON::Object::Ptr &O, | ||||
| 														bool &Done, std::string &Answer) { | ||||
| 		Done = false; | ||||
| 		auto operatorId = ORM::Escape(O->get("operatorId").toString()); | ||||
| 		std::string nameSearch, emailSearch; | ||||
| 		OpenWifi::RESTAPIHandler::AssignIfPresent(O, "nameSearch", nameSearch); | ||||
| 		OpenWifi::RESTAPIHandler::AssignIfPresent(O, "emailSearch", emailSearch); | ||||
| 		SecurityObjects::UserInfoList Users; | ||||
| 		SDK::Sec::Subscriber::Search(nullptr, operatorId, nameSearch, emailSearch, Users); | ||||
|  | ||||
|         Poco::JSON::Array   Arr; | ||||
|         for(const auto &i:Users.users) { | ||||
|             Poco::JSON::Object  OO; | ||||
|             OO.set("name", i.name); | ||||
|             OO.set("email", i.email); | ||||
|             OO.set("id", i.id); | ||||
|             i.to_json(OO); | ||||
|             Arr.add(OO); | ||||
|         } | ||||
|         Poco::JSON::Object  ObjAnswer; | ||||
|         ObjAnswer.set("users", Arr); | ||||
|         std::ostringstream SS; | ||||
|         Poco::JSON::Stringifier::stringify(ObjAnswer, SS); | ||||
|         Answer = SS.str(); | ||||
|     } | ||||
| 		Poco::JSON::Array Arr; | ||||
| 		for (const auto &i : Users.users) { | ||||
| 			Poco::JSON::Object OO; | ||||
| 			OO.set("name", i.name); | ||||
| 			OO.set("email", i.email); | ||||
| 			OO.set("id", i.id); | ||||
| 			i.to_json(OO); | ||||
| 			Arr.add(OO); | ||||
| 		} | ||||
| 		Poco::JSON::Object ObjAnswer; | ||||
| 		ObjAnswer.set("users", Arr); | ||||
| 		std::ostringstream SS; | ||||
| 		Poco::JSON::Stringifier::stringify(ObjAnswer, SS); | ||||
| 		Answer = SS.str(); | ||||
| 	} | ||||
|  | ||||
|     void ProvWebSocketClient::ws_command_subdevice_search( const Poco::JSON::Object::Ptr &O, bool &Done, std::string &Answer) { | ||||
|         Done = false; | ||||
|         auto operatorId = O->get("operatorId").toString(); | ||||
|         auto Prefix = O->get("serial_prefix").toString(); | ||||
|         Poco::toLowerInPlace(Prefix); | ||||
|         std::string Query; | ||||
| 	void ProvWebSocketClient::ws_command_subdevice_search(const Poco::JSON::Object::Ptr &O, | ||||
| 														  bool &Done, std::string &Answer) { | ||||
| 		Done = false; | ||||
| 		auto operatorId = O->get("operatorId").toString(); | ||||
| 		auto Prefix = O->get("serial_prefix").toString(); | ||||
| 		Poco::toLowerInPlace(Prefix); | ||||
| 		std::string Query; | ||||
|  | ||||
|         if(Prefix[0]=='*') { | ||||
|             Query = fmt::format(" operatorId='{}' and (right(serialNumber,{})='{}' or right(realMacAddress,{})='{}' ) ", | ||||
|                                 operatorId, Prefix.size()-1, Prefix.substr(1), Prefix.size()-1, Prefix.substr(1)); | ||||
|         } else { | ||||
|             Query = fmt::format(" operatorId='{}' and (left(serialNumber,{})='{}'  or left(realMacAddress,{})='{}' ) ", | ||||
|                                 operatorId, Prefix.size(), Prefix, Prefix.size(), Prefix); | ||||
|         } | ||||
| 		if (Prefix[0] == '*') { | ||||
| 			Query = fmt::format(" operatorId='{}' and (right(serialNumber,{})='{}' or " | ||||
| 								"right(realMacAddress,{})='{}' ) ", | ||||
| 								operatorId, Prefix.size() - 1, Prefix.substr(1), Prefix.size() - 1, | ||||
| 								Prefix.substr(1)); | ||||
| 		} else { | ||||
| 			Query = fmt::format(" operatorId='{}' and (left(serialNumber,{})='{}'  or " | ||||
| 								"left(realMacAddress,{})='{}' ) ", | ||||
| 								operatorId, Prefix.size(), Prefix, Prefix.size(), Prefix); | ||||
| 		} | ||||
|  | ||||
|         std::vector<ProvObjects::SubscriberDevice>  SubDevices; | ||||
| 		std::vector<ProvObjects::SubscriberDevice> SubDevices; | ||||
|  | ||||
|         StorageService()->SubscriberDeviceDB().GetRecords(0,200,SubDevices,Query); | ||||
|         Poco::JSON::Array   Arr; | ||||
|         for(const auto &i:SubDevices) { | ||||
|             Arr.add(i.serialNumber); | ||||
|         } | ||||
|         Poco::JSON::Object  RetObj; | ||||
|         RetObj.set("serialNumbers", Arr); | ||||
|         std::ostringstream SS; | ||||
|         Poco::JSON::Stringifier::stringify(RetObj, SS); | ||||
|         Answer = SS.str(); | ||||
|     } | ||||
| 		StorageService()->SubscriberDeviceDB().GetRecords(0, 200, SubDevices, Query); | ||||
| 		Poco::JSON::Array Arr; | ||||
| 		for (const auto &i : SubDevices) { | ||||
| 			Arr.add(i.serialNumber); | ||||
| 		} | ||||
| 		Poco::JSON::Object RetObj; | ||||
| 		RetObj.set("serialNumbers", Arr); | ||||
| 		std::ostringstream SS; | ||||
| 		Poco::JSON::Stringifier::stringify(RetObj, SS); | ||||
| 		Answer = SS.str(); | ||||
| 	} | ||||
|  | ||||
|     void ProvWebSocketClient::Processor(const Poco::JSON::Object::Ptr &O, std::string &Result, bool &Done ) { | ||||
|         try { | ||||
|             if (O->has("command") && O->has("id")) { | ||||
|                 auto id = (uint64_t) O->get("id"); | ||||
|                 std::string Answer; | ||||
|                 auto Command = O->get("command").toString(); | ||||
|                 if (Command == "serial_number_search" && O->has("serial_prefix")) { | ||||
|                     ws_command_serial_number_search(O,Done,Answer); | ||||
|                 } else if (WebSocketClientServer()->GeoCodeEnabled() && Command == "address_completion" && O->has("address")) { | ||||
|                     ws_command_address_completion(O,Done,Answer); | ||||
|                 } else if (WebSocketClientServer()->GeoCodeEnabled() && Command == "subuser_search" && O->has("operatorId")) { | ||||
|                     ws_command_subuser_search(O,Done,Answer); | ||||
|                 } else if (WebSocketClientServer()->GeoCodeEnabled() && Command == "subdevice_search" && O->has("operatorId") && O->has("serial_prefix")) { | ||||
|                     ws_command_subdevice_search(O,Done,Answer); | ||||
|                 } else if (Command=="exit") { | ||||
|                     ws_command_exit(O,Done,Answer); | ||||
|                 } else { | ||||
|                     ws_command_invalid(O,Done,Answer); | ||||
|                 } | ||||
| 	void | ||||
| 	ProvWebSocketClient::Processor(const Poco::JSON::Object::Ptr &O, std::string &Result, | ||||
| 								   bool &Done, | ||||
| 								   [[maybe_unused]] const SecurityObjects::UserInfo &UserInfo) { | ||||
| 		try { | ||||
| 			if (O->has("command") && O->has("id")) { | ||||
| 				auto id = (uint64_t)O->get("id"); | ||||
| 				std::string Answer; | ||||
| 				auto Command = O->get("command").toString(); | ||||
| 				if (Command == "serial_number_search" && O->has("serial_prefix")) { | ||||
| 					ws_command_serial_number_search(O, Done, Answer); | ||||
| 				} else if (UI_WebSocketClientServer()->GeoCodeEnabled() && | ||||
| 						   Command == "address_completion" && O->has("address")) { | ||||
| 					ws_command_address_completion(O, Done, Answer); | ||||
| 				} else if (UI_WebSocketClientServer()->GeoCodeEnabled() && | ||||
| 						   Command == "subuser_search" && O->has("operatorId")) { | ||||
| 					ws_command_subuser_search(O, Done, Answer); | ||||
| 				} else if (UI_WebSocketClientServer()->GeoCodeEnabled() && | ||||
| 						   Command == "subdevice_search" && O->has("operatorId") && | ||||
| 						   O->has("serial_prefix")) { | ||||
| 					ws_command_subdevice_search(O, Done, Answer); | ||||
| 				} else if (Command == "exit") { | ||||
| 					ws_command_exit(O, Done, Answer); | ||||
| 				} else { | ||||
| 					ws_command_invalid(O, Done, Answer); | ||||
| 				} | ||||
|  | ||||
|                 Result = fmt::format("{{ \"command_response_id\" : {} , \"response\" : {}  }}" , id, Answer); | ||||
|             } | ||||
|         } catch (const Poco::Exception &E) { | ||||
|             Logger().log(E); | ||||
|         } | ||||
|     } | ||||
| 				Result = fmt::format("{{ \"command_response_id\" : {} , \"response\" : {}  }}", id, | ||||
| 									 Answer); | ||||
| 			} | ||||
| 		} catch (const Poco::Exception &E) { | ||||
| 			Logger().log(E); | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
|     std::string ProvWebSocketClient::GoogleGeoCodeCall(const std::string &A) { | ||||
|         try { | ||||
|             std::string URI = { "https://maps.googleapis.com/maps/api/geocode/json"}; | ||||
|             Poco::URI   uri(URI); | ||||
| 	std::string ProvWebSocketClient::GoogleGeoCodeCall(const std::string &A) { | ||||
| 		try { | ||||
| 			std::string URI = {"https://maps.googleapis.com/maps/api/geocode/json"}; | ||||
| 			Poco::URI uri(URI); | ||||
|  | ||||
|             uri.addQueryParameter("address",A); | ||||
|             uri.addQueryParameter("key", WebSocketClientServer()->GoogleApiKey()); | ||||
| 			uri.addQueryParameter("address", A); | ||||
| 			uri.addQueryParameter("key", UI_WebSocketClientServer()->GoogleApiKey()); | ||||
|  | ||||
|             Poco::Net::HTTPSClientSession session(uri.getHost(), uri.getPort()); | ||||
|             Poco::Net::HTTPRequest req(Poco::Net::HTTPRequest::HTTP_GET, uri.getPathAndQuery(), Poco::Net::HTTPMessage::HTTP_1_1); | ||||
|             session.sendRequest(req); | ||||
|             Poco::Net::HTTPResponse res; | ||||
|             std::istream& rs = session.receiveResponse(res); | ||||
|             if(res.getStatus()==Poco::Net::HTTPResponse::HTTP_OK) { | ||||
|                 std::ostringstream os; | ||||
|                 Poco::StreamCopier::copyStream(rs,os); | ||||
|                 return os.str(); | ||||
|             } else { | ||||
|                 std::ostringstream os; | ||||
|                 Poco::StreamCopier::copyStream(rs,os); | ||||
|                 return R"lit({ "error: )lit" + os.str() + R"lit( })lit"; | ||||
|             } | ||||
|         } catch(...) { | ||||
| 			Poco::Net::HTTPSClientSession session(uri.getHost(), uri.getPort()); | ||||
| 			Poco::Net::HTTPRequest req(Poco::Net::HTTPRequest::HTTP_GET, uri.getPathAndQuery(), | ||||
| 									   Poco::Net::HTTPMessage::HTTP_1_1); | ||||
| 			session.sendRequest(req); | ||||
| 			Poco::Net::HTTPResponse res; | ||||
| 			std::istream &rs = session.receiveResponse(res); | ||||
| 			if (res.getStatus() == Poco::Net::HTTPResponse::HTTP_OK) { | ||||
| 				std::ostringstream os; | ||||
| 				Poco::StreamCopier::copyStream(rs, os); | ||||
| 				return os.str(); | ||||
| 			} else { | ||||
| 				std::ostringstream os; | ||||
| 				Poco::StreamCopier::copyStream(rs, os); | ||||
| 				return R"lit({ "error: )lit" + os.str() + R"lit( })lit"; | ||||
| 			} | ||||
| 		} catch (...) { | ||||
| 		} | ||||
| 		return "{ \"error\" : \"No call made\" }"; | ||||
| 	} | ||||
|  | ||||
|         } | ||||
|         return "{ \"error\" : \"No call made\" }"; | ||||
|     } | ||||
|  | ||||
| } | ||||
| } // namespace OpenWifi | ||||
| @@ -4,25 +4,31 @@ | ||||
|  | ||||
| #pragma once | ||||
|  | ||||
| #include "framework/MicroService.h" | ||||
| #include "framework/UI_WebSocketClientServer.h" | ||||
|  | ||||
| namespace OpenWifi { | ||||
|  | ||||
|     class ProvWebSocketClient : public WebSocketClientProcessor { | ||||
|     public: | ||||
|         explicit ProvWebSocketClient(Poco::Logger &Logger); | ||||
|         virtual ~ProvWebSocketClient(); | ||||
|         virtual void Processor(const Poco::JSON::Object::Ptr &O, std::string &Answer, bool &Done ); | ||||
|         void ws_command_serial_number_search( const Poco::JSON::Object::Ptr &O, bool &Done, std::string &Answer); | ||||
|         void ws_command_address_completion( const Poco::JSON::Object::Ptr &O, bool &Done, std::string &Answer); | ||||
|         void ws_command_exit( const Poco::JSON::Object::Ptr &O, bool &Done, std::string &Answer); | ||||
|         void ws_command_invalid( const Poco::JSON::Object::Ptr &O, bool &Done, std::string &Answer); | ||||
|         void ws_command_subuser_search( const Poco::JSON::Object::Ptr &O, bool &Done, std::string &Answer); | ||||
|         void ws_command_subdevice_search( const Poco::JSON::Object::Ptr &O, bool &Done, std::string &Answer); | ||||
|         std::string GoogleGeoCodeCall(const std::string &A); | ||||
|     private: | ||||
|         Poco::Logger & Logger_; | ||||
|         inline Poco::Logger & Logger() { return Logger_; } | ||||
|     }; | ||||
| 	class ProvWebSocketClient : public UI_WebSocketClientProcessor { | ||||
| 	  public: | ||||
| 		explicit ProvWebSocketClient(Poco::Logger &Logger); | ||||
| 		virtual ~ProvWebSocketClient(); | ||||
| 		virtual void Processor(const Poco::JSON::Object::Ptr &O, std::string &Answer, bool &Done, | ||||
| 							   const SecurityObjects::UserInfo &UserInfo); | ||||
| 		void ws_command_serial_number_search(const Poco::JSON::Object::Ptr &O, bool &Done, | ||||
| 											 std::string &Answer); | ||||
| 		void ws_command_address_completion(const Poco::JSON::Object::Ptr &O, bool &Done, | ||||
| 										   std::string &Answer); | ||||
| 		void ws_command_exit(const Poco::JSON::Object::Ptr &O, bool &Done, std::string &Answer); | ||||
| 		void ws_command_invalid(const Poco::JSON::Object::Ptr &O, bool &Done, std::string &Answer); | ||||
| 		void ws_command_subuser_search(const Poco::JSON::Object::Ptr &O, bool &Done, | ||||
| 									   std::string &Answer); | ||||
| 		void ws_command_subdevice_search(const Poco::JSON::Object::Ptr &O, bool &Done, | ||||
| 										 std::string &Answer); | ||||
| 		std::string GoogleGeoCodeCall(const std::string &A); | ||||
|  | ||||
| } | ||||
| 	  private: | ||||
| 		Poco::Logger &Logger_; | ||||
| 		inline Poco::Logger &Logger() { return Logger_; } | ||||
| 	}; | ||||
|  | ||||
| } // namespace OpenWifi | ||||
|   | ||||
| @@ -3,19 +3,19 @@ | ||||
| // | ||||
|  | ||||
| #include "RESTAPI_asset_server.h" | ||||
| #include "Daemon.h" | ||||
| #include "Poco/File.h" | ||||
| #include "framework/ow_constants.h" | ||||
| #include "Daemon.h" | ||||
|  | ||||
| namespace OpenWifi { | ||||
|     void RESTAPI_asset_server::DoGet() { | ||||
|         Poco::File  AssetFile; | ||||
| 	void RESTAPI_asset_server::DoGet() { | ||||
| 		Poco::File AssetFile; | ||||
|  | ||||
|         std::string AssetName = GetBinding(RESTAPI::Protocol::ID, ""); | ||||
|         AssetFile = Daemon()->AssetDir() + "/" + AssetName; | ||||
|         if(!AssetFile.isFile()) { | ||||
|             return NotFound(); | ||||
|         } | ||||
|         SendFile(AssetFile); | ||||
|     } | ||||
| } | ||||
| 		std::string AssetName = GetBinding(RESTAPI::Protocol::ID, ""); | ||||
| 		AssetFile = Daemon()->AssetDir() + "/" + AssetName; | ||||
| 		if (!AssetFile.isFile()) { | ||||
| 			return NotFound(); | ||||
| 		} | ||||
| 		SendFile(AssetFile); | ||||
| 	} | ||||
| } // namespace OpenWifi | ||||
| @@ -3,29 +3,25 @@ | ||||
| // | ||||
|  | ||||
| #pragma once | ||||
|  | ||||
| #include "../framework/MicroService.h" | ||||
| #include "StorageService.h" | ||||
| #include "framework/RESTAPI_Handler.h" | ||||
|  | ||||
| namespace OpenWifi { | ||||
|     class RESTAPI_asset_server : public RESTAPIHandler { | ||||
|     public: | ||||
|         RESTAPI_asset_server(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L, RESTAPI_GenericServer &Server, uint64_t TransactionId, bool Internal) | ||||
|                 : RESTAPIHandler(bindings, L, | ||||
|                                  std::vector<std::string> | ||||
|                                          { | ||||
|                                           Poco::Net::HTTPRequest::HTTP_GET, | ||||
|                                           Poco::Net::HTTPRequest::HTTP_OPTIONS}, | ||||
|                                           Server, | ||||
|                                           TransactionId, | ||||
|                                           Internal, false) {} | ||||
|         static auto PathName() { return std::list<std::string>{"/wwwassets/{id}"}; }; | ||||
|         void DoGet() final; | ||||
|         void DoPost() final {}; | ||||
|         void DoDelete() final {}; | ||||
|         void DoPut() final {}; | ||||
|  | ||||
|     private: | ||||
|  | ||||
|     }; | ||||
| } | ||||
| 	class RESTAPI_asset_server : public RESTAPIHandler { | ||||
| 	  public: | ||||
| 		RESTAPI_asset_server(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L, | ||||
| 							 RESTAPI_GenericServerAccounting &Server, uint64_t TransactionId, | ||||
| 							 bool Internal) | ||||
| 			: RESTAPIHandler(bindings, L, | ||||
| 							 std::vector<std::string>{Poco::Net::HTTPRequest::HTTP_GET, | ||||
| 													  Poco::Net::HTTPRequest::HTTP_OPTIONS}, | ||||
| 							 Server, TransactionId, Internal, false) {} | ||||
| 		static auto PathName() { return std::list<std::string>{"/wwwassets/{id}"}; }; | ||||
| 		void DoGet() final; | ||||
| 		void DoPost() final{}; | ||||
| 		void DoDelete() final{}; | ||||
| 		void DoPut() final{}; | ||||
|  | ||||
| 	  private: | ||||
| 	}; | ||||
| } // namespace OpenWifi | ||||
|   | ||||
| @@ -6,225 +6,262 @@ | ||||
| //	Arilia Wireless Inc. | ||||
| // | ||||
|  | ||||
| #include "framework/MicroService.h" | ||||
|  | ||||
| #include "RESTAPI_configurations_handler.h" | ||||
| #include "DeviceTypeCache.h" | ||||
| #include "RESTAPI/RESTAPI_db_helpers.h" | ||||
| #include "RESTObjects/RESTAPI_ProvObjects.h" | ||||
| #include "StorageService.h" | ||||
| #include "framework/ConfigurationValidator.h" | ||||
| #include "RESTAPI/RESTAPI_db_helpers.h" | ||||
| #include "DeviceTypeCache.h" | ||||
|  | ||||
| namespace OpenWifi{ | ||||
| namespace OpenWifi { | ||||
|  | ||||
|     void RESTAPI_configurations_handler::DoGet() { | ||||
|         std::string UUID = GetBinding("uuid",""); | ||||
|         ProvObjects::DeviceConfiguration   Existing; | ||||
|         if(UUID.empty() || !DB_.GetRecord("id", UUID, Existing)) { | ||||
|             return NotFound(); | ||||
|         } | ||||
| 	void RESTAPI_configurations_handler::DoGet() { | ||||
| 		std::string UUID = GetBinding("uuid", ""); | ||||
| 		ProvObjects::DeviceConfiguration Existing; | ||||
| 		if (UUID.empty() || !DB_.GetRecord("id", UUID, Existing)) { | ||||
| 			return NotFound(); | ||||
| 		} | ||||
|  | ||||
|         Poco::JSON::Object  Answer; | ||||
|         std::string Arg; | ||||
|         if(HasParameter("expandInUse",Arg) && Arg=="true") { | ||||
|             Storage::ExpandedListMap    M; | ||||
|             std::vector<std::string>    Errors; | ||||
|             Poco::JSON::Object          Inner; | ||||
|             if(StorageService()->ExpandInUse(Existing.inUse,M,Errors)) { | ||||
|                 for(const auto &[type,list]:M) { | ||||
|                     Poco::JSON::Array   ObjList; | ||||
|                     for(const auto &i:list.entries) { | ||||
|                         Poco::JSON::Object  O; | ||||
|                         i.to_json(O); | ||||
|                         ObjList.add(O); | ||||
|                     } | ||||
|                     Inner.set(type,ObjList); | ||||
|                 } | ||||
|             } | ||||
|             Answer.set("entries", Inner); | ||||
|             return ReturnObject(Answer); | ||||
|         } else if(HasParameter("computedAffected",Arg) && Arg=="true") { | ||||
|             Types::UUIDvec_t DeviceSerialNumbers; | ||||
|             DB_.GetListOfAffectedDevices(UUID,DeviceSerialNumbers); | ||||
|             return ReturnObject("affectedDevices", DeviceSerialNumbers); | ||||
|         } else if(QB_.AdditionalInfo) { | ||||
|             AddExtendedInfo(Existing,Answer); | ||||
|         } | ||||
|         Existing.to_json(Answer); | ||||
|         ReturnObject(Answer); | ||||
|     } | ||||
| 		Poco::JSON::Object Answer; | ||||
| 		std::string Arg; | ||||
| 		if (HasParameter("expandInUse", Arg) && Arg == "true") { | ||||
| 			Storage::ExpandedListMap M; | ||||
| 			std::vector<std::string> Errors; | ||||
| 			Poco::JSON::Object Inner; | ||||
| 			if (StorageService()->ExpandInUse(Existing.inUse, M, Errors)) { | ||||
| 				for (const auto &[type, list] : M) { | ||||
| 					Poco::JSON::Array ObjList; | ||||
| 					for (const auto &i : list.entries) { | ||||
| 						Poco::JSON::Object O; | ||||
| 						i.to_json(O); | ||||
| 						ObjList.add(O); | ||||
| 					} | ||||
| 					Inner.set(type, ObjList); | ||||
| 				} | ||||
| 			} | ||||
| 			Answer.set("entries", Inner); | ||||
| 			return ReturnObject(Answer); | ||||
| 		} else if (HasParameter("computedAffected", Arg) && Arg == "true") { | ||||
| 			Types::UUIDvec_t DeviceSerialNumbers; | ||||
| 			DB_.GetListOfAffectedDevices(UUID, DeviceSerialNumbers); | ||||
| 			return ReturnObject("affectedDevices", DeviceSerialNumbers); | ||||
| 		} else if (QB_.AdditionalInfo) { | ||||
| 			AddExtendedInfo(Existing, Answer); | ||||
| 		} | ||||
| 		Existing.to_json(Answer); | ||||
| 		ReturnObject(Answer); | ||||
| 	} | ||||
|  | ||||
|     void RESTAPI_configurations_handler::DoDelete() { | ||||
|         std::string UUID = GetBinding("uuid",""); | ||||
|         ProvObjects::DeviceConfiguration   Existing; | ||||
|         if(UUID.empty() || !DB_.GetRecord("id", UUID, Existing)) { | ||||
|             return NotFound(); | ||||
|         } | ||||
| 	void RESTAPI_configurations_handler::DoDelete() { | ||||
| 		std::string UUID = GetBinding("uuid", ""); | ||||
| 		ProvObjects::DeviceConfiguration Existing; | ||||
| 		if (UUID.empty() || !DB_.GetRecord("id", UUID, Existing)) { | ||||
| 			return NotFound(); | ||||
| 		} | ||||
|  | ||||
|         if(!Existing.inUse.empty()) { | ||||
|             return BadRequest(RESTAPI::Errors::StillInUse); | ||||
|         } | ||||
| 		if (!Existing.inUse.empty()) { | ||||
| 			return BadRequest(RESTAPI::Errors::StillInUse); | ||||
| 		} | ||||
|  | ||||
|         DB_.DeleteRecord("id", UUID); | ||||
|         MoveUsage(StorageService()->PolicyDB(),DB_,Existing.managementPolicy,"",Existing.info.id); | ||||
|         RemoveMembership(StorageService()->VenueDB(),&ProvObjects::Venue::configurations,Existing.venue,Existing.info.id); | ||||
|         RemoveMembership(StorageService()->EntityDB(),&ProvObjects::Entity::configurations,Existing.entity,Existing.info.id); | ||||
|         for(const auto &i:Existing.variables) | ||||
|             RemoveMembership(StorageService()->VariablesDB(),&ProvObjects::VariableBlock::configurations,i,Existing.info.id); | ||||
| 		DB_.DeleteRecord("id", UUID); | ||||
| 		MoveUsage(StorageService()->PolicyDB(), DB_, Existing.managementPolicy, "", | ||||
| 				  Existing.info.id); | ||||
| 		RemoveMembership(StorageService()->VenueDB(), &ProvObjects::Venue::configurations, | ||||
| 						 Existing.venue, Existing.info.id); | ||||
| 		RemoveMembership(StorageService()->EntityDB(), &ProvObjects::Entity::configurations, | ||||
| 						 Existing.entity, Existing.info.id); | ||||
| 		for (const auto &i : Existing.variables) | ||||
| 			RemoveMembership(StorageService()->VariablesDB(), | ||||
| 							 &ProvObjects::VariableBlock::configurations, i, Existing.info.id); | ||||
|  | ||||
|         return OK(); | ||||
|     } | ||||
| 		return OK(); | ||||
| 	} | ||||
|  | ||||
|     void RESTAPI_configurations_handler::DoPost() { | ||||
|         auto UUID = GetBinding("uuid",""); | ||||
|         if(UUID.empty()) { | ||||
|             return BadRequest(RESTAPI::Errors::MissingUUID); | ||||
|         } | ||||
| 	void RESTAPI_configurations_handler::DoPost() { | ||||
| 		auto UUID = GetBinding("uuid", ""); | ||||
| 		if (UUID.empty()) { | ||||
| 			return BadRequest(RESTAPI::Errors::MissingUUID); | ||||
| 		} | ||||
|  | ||||
|         const auto & RawObject = ParsedBody_; | ||||
|         std::string Arg; | ||||
|         if(HasParameter("validateOnly",Arg) && Arg=="true") { | ||||
|             if(!RawObject->has("configuration")) { | ||||
|                 return BadRequest(RESTAPI::Errors::MustHaveConfigElement); | ||||
|             } | ||||
|             auto Config=RawObject->get("configuration").toString(); | ||||
|             Poco::JSON::Object  Answer; | ||||
| 		const auto &RawObject = ParsedBody_; | ||||
| 		std::string Arg; | ||||
| 		if (HasParameter("validateOnly", Arg) && Arg == "true") { | ||||
| 			if (!RawObject->has("configuration")) { | ||||
| 				return BadRequest(RESTAPI::Errors::MustHaveConfigElement); | ||||
| 			} | ||||
| 			auto Config = RawObject->get("configuration").toString(); | ||||
| 			Poco::JSON::Object Answer; | ||||
|             auto deviceType = GetParameter("deviceType", "AP"); | ||||
|             std::string Error; | ||||
|             auto Res = ValidateUCentralConfiguration(Config,Error); | ||||
|             Answer.set("valid",Res); | ||||
|             Answer.set("error", Error); | ||||
|             return ReturnObject(Answer); | ||||
| 			auto Res = | ||||
| 				ValidateUCentralConfiguration(ConfigurationValidator::GetType(deviceType),Config, Error, GetBoolParameter("strict", true)); | ||||
| 			Answer.set("valid", Res); | ||||
| 			Answer.set("error", Error); | ||||
| 			return ReturnObject(Answer); | ||||
| 		} | ||||
|  | ||||
| 		ProvObjects::DeviceConfiguration NewObject; | ||||
| 		if (!NewObject.from_json(RawObject)) { | ||||
| 			return BadRequest(RESTAPI::Errors::InvalidJSONDocument); | ||||
| 		} | ||||
|  | ||||
| 		if ((RawObject->has("deviceRules") && !ValidDeviceRules(NewObject.deviceRules, *this))) { | ||||
| 			return; | ||||
| 		} | ||||
|  | ||||
| 		if (!ProvObjects::CreateObjectInfo(RawObject, UserInfo_.userinfo, NewObject.info)) { | ||||
| 			return BadRequest(RESTAPI::Errors::NameMustBeSet); | ||||
| 		} | ||||
|  | ||||
| 		if (!NewObject.entity.empty() && | ||||
| 			!StorageService()->EntityDB().Exists("id", NewObject.entity)) { | ||||
| 			return BadRequest(RESTAPI::Errors::EntityMustExist); | ||||
| 		} | ||||
|  | ||||
| 		if (!NewObject.venue.empty() && | ||||
| 			!StorageService()->VenueDB().Exists("id", NewObject.venue)) { | ||||
| 			return BadRequest(RESTAPI::Errors::VenueMustExist); | ||||
| 		} | ||||
|  | ||||
| 		if (!NewObject.managementPolicy.empty() && | ||||
| 			!StorageService()->PolicyDB().Exists("id", NewObject.managementPolicy)) { | ||||
| 			return BadRequest(RESTAPI::Errors::UnknownManagementPolicyUUID); | ||||
| 		} | ||||
|  | ||||
| 		NewObject.inUse.clear(); | ||||
| 		if (NewObject.deviceTypes.empty() || | ||||
| 			!DeviceTypeCache()->AreAcceptableDeviceTypes(NewObject.deviceTypes, true)) { | ||||
| 			return BadRequest(RESTAPI::Errors::InvalidDeviceTypes); | ||||
| 		} | ||||
|  | ||||
| 		std::vector<std::string> Errors; | ||||
|         auto deviceType = GetParameter("deviceType", "AP"); | ||||
|         if (!ValidateConfigBlock(ConfigurationValidator::GetType(deviceType), NewObject, Errors)) { | ||||
|             return BadRequest(RESTAPI::Errors::ConfigBlockInvalid); | ||||
|         } | ||||
|  | ||||
|         ProvObjects::DeviceConfiguration NewObject; | ||||
|         if (!NewObject.from_json(RawObject)) { | ||||
|             return BadRequest(RESTAPI::Errors::InvalidJSONDocument); | ||||
| 		Types::UUIDvec_t ToVariables; | ||||
| 		if (RawObject->has("variables")) { | ||||
| 			for (const auto &i : NewObject.variables) { | ||||
| 				if (!i.empty() && !StorageService()->VariablesDB().Exists("id", i)) { | ||||
| 					return BadRequest(RESTAPI::Errors::VariableMustExist); | ||||
| 				} | ||||
| 			} | ||||
| 			for (const auto &i : NewObject.variables) | ||||
| 				ToVariables.emplace_back(i); | ||||
| 			 | ||||
| 			ToVariables = NewObject.variables; | ||||
| 		} | ||||
|  | ||||
| 		if (DB_.CreateRecord(NewObject)) { | ||||
| 			AddMembership(StorageService()->VariablesDB(), | ||||
| 							 &ProvObjects::VariableBlock::configurations, ToVariables, NewObject.info.id); | ||||
| 			MoveUsage(StorageService()->PolicyDB(), DB_, "", NewObject.managementPolicy, | ||||
| 					  NewObject.info.id); | ||||
| 			AddMembership(StorageService()->VenueDB(), &ProvObjects::Venue::configurations, | ||||
| 						  NewObject.venue, NewObject.info.id); | ||||
| 			AddMembership(StorageService()->EntityDB(), &ProvObjects::Entity::configurations, | ||||
| 						  NewObject.entity, NewObject.info.id); | ||||
|  | ||||
| 			ConfigurationDB::RecordName AddedRecord; | ||||
| 			DB_.GetRecord("id", NewObject.info.id, AddedRecord); | ||||
| 			Poco::JSON::Object Answer; | ||||
| 			AddedRecord.to_json(Answer); | ||||
| 			return ReturnObject(Answer); | ||||
| 		} | ||||
| 		InternalError(RESTAPI::Errors::RecordNotCreated); | ||||
| 	} | ||||
|  | ||||
| 	void RESTAPI_configurations_handler::DoPut() { | ||||
| 		auto UUID = GetBinding("uuid", ""); | ||||
| 		ProvObjects::DeviceConfiguration Existing; | ||||
| 		if (UUID.empty() || !DB_.GetRecord("id", UUID, Existing)) { | ||||
| 			return NotFound(); | ||||
| 		} | ||||
|  | ||||
| 		ProvObjects::DeviceConfiguration NewObject; | ||||
| 		const auto &RawObject = ParsedBody_; | ||||
| 		if (!NewObject.from_json(RawObject)) { | ||||
| 			return BadRequest(RESTAPI::Errors::InvalidJSONDocument); | ||||
| 		} | ||||
|  | ||||
| 		if ((RawObject->has("deviceRules") && !ValidDeviceRules(NewObject.deviceRules, *this))) { | ||||
| 			return; | ||||
| 		} | ||||
|  | ||||
| 		if (!UpdateObjectInfo(RawObject, UserInfo_.userinfo, Existing.info)) { | ||||
| 			return BadRequest(RESTAPI::Errors::NameMustBeSet); | ||||
| 		} | ||||
|  | ||||
| 		if (!NewObject.deviceTypes.empty() && | ||||
| 			!DeviceTypeCache()->AreAcceptableDeviceTypes(NewObject.deviceTypes, true)) { | ||||
| 			return BadRequest(RESTAPI::Errors::InvalidDeviceTypes); | ||||
| 		} | ||||
|  | ||||
| 		if (!NewObject.deviceTypes.empty()) | ||||
| 			Existing.deviceTypes = NewObject.deviceTypes; | ||||
|  | ||||
| 		std::vector<std::string> Errors; | ||||
|         auto deviceType = GetParameter("deviceType", "AP"); | ||||
|         if (!ValidateConfigBlock(ConfigurationValidator::GetType(deviceType), NewObject, Errors)) { | ||||
|             return BadRequest(RESTAPI::Errors::ConfigBlockInvalid); | ||||
|         } | ||||
|  | ||||
|         if((RawObject->has("deviceRules") && !ValidDeviceRules(NewObject.deviceRules,*this))) { | ||||
|             return; | ||||
|         } | ||||
| 		if (RawObject->has("configuration")) { | ||||
| 			Existing.configuration = NewObject.configuration; | ||||
| 		} | ||||
|  | ||||
|         if(!ProvObjects::CreateObjectInfo(RawObject,UserInfo_.userinfo,NewObject.info)) { | ||||
|             return BadRequest(RESTAPI::Errors::NameMustBeSet); | ||||
|         } | ||||
| 		std::string FromPolicy, ToPolicy; | ||||
| 		if (!CreateMove(RawObject, "managementPolicy", | ||||
| 						&ConfigurationDB::RecordName::managementPolicy, Existing, FromPolicy, | ||||
| 						ToPolicy, StorageService()->PolicyDB())) | ||||
| 			return BadRequest(RESTAPI::Errors::EntityMustExist); | ||||
|  | ||||
|         if(!NewObject.entity.empty() && !StorageService()->EntityDB().Exists("id",NewObject.entity)) { | ||||
|             return BadRequest(RESTAPI::Errors::EntityMustExist); | ||||
|         } | ||||
| 		std::string FromEntity, ToEntity; | ||||
| 		if (!CreateMove(RawObject, "entity", &ConfigurationDB::RecordName::entity, Existing, | ||||
| 						FromEntity, ToEntity, StorageService()->EntityDB())) | ||||
| 			return BadRequest(RESTAPI::Errors::EntityMustExist); | ||||
|  | ||||
|         if(!NewObject.venue.empty() && !StorageService()->VenueDB().Exists("id",NewObject.venue)) { | ||||
|             return BadRequest(RESTAPI::Errors::VenueMustExist); | ||||
|         } | ||||
| 		std::string FromVenue, ToVenue; | ||||
| 		if (!CreateMove(RawObject, "venue", &ConfigurationDB::RecordName::venue, Existing, | ||||
| 						FromVenue, ToVenue, StorageService()->VenueDB())) | ||||
| 			return BadRequest(RESTAPI::Errors::VenueMustExist); | ||||
|  | ||||
|         if(!NewObject.managementPolicy.empty() && !StorageService()->PolicyDB().Exists("id",NewObject.managementPolicy)) { | ||||
|             return BadRequest(RESTAPI::Errors::UnknownManagementPolicyUUID); | ||||
|         } | ||||
| 		Types::UUIDvec_t FromVariables, ToVariables; | ||||
| 		if (RawObject->has("variables")) { | ||||
| 			for (const auto &i : NewObject.variables) { | ||||
| 				if (!i.empty() && !StorageService()->VariablesDB().Exists("id", i)) { | ||||
| 					return BadRequest(RESTAPI::Errors::VariableMustExist); | ||||
| 				} | ||||
| 			} | ||||
| 			for (const auto &i : Existing.variables) | ||||
| 				FromVariables.emplace_back(i); | ||||
| 			for (const auto &i : NewObject.variables) | ||||
| 				ToVariables.emplace_back(i); | ||||
| 			FromVariables = Existing.variables; | ||||
| 			ToVariables = NewObject.variables; | ||||
| 			Existing.variables = ToVariables; | ||||
| 		} | ||||
|  | ||||
|         NewObject.inUse.clear(); | ||||
|         if(NewObject.deviceTypes.empty() || !DeviceTypeCache()->AreAcceptableDeviceTypes(NewObject.deviceTypes, true)) { | ||||
|             return BadRequest(RESTAPI::Errors::InvalidDeviceTypes); | ||||
|         } | ||||
| 		if (RawObject->has("deviceRules")) | ||||
| 			Existing.deviceRules = NewObject.deviceRules; | ||||
|  | ||||
|         RESTAPI::Errors::msg Error; | ||||
|         if(!ValidateConfigBlock(NewObject,Error)) { | ||||
|             return BadRequest(Error); | ||||
|         } | ||||
| 		if (DB_.UpdateRecord("id", UUID, Existing)) { | ||||
| 			ManageMembership(StorageService()->VariablesDB(), | ||||
| 							 &ProvObjects::VariableBlock::configurations, FromVariables, | ||||
| 							 ToVariables, Existing.info.id); | ||||
| 			ManageMembership(StorageService()->VenueDB(), &ProvObjects::Venue::configurations, | ||||
| 							 FromVenue, ToVenue, Existing.info.id); | ||||
| 			ManageMembership(StorageService()->EntityDB(), &ProvObjects::Entity::configurations, | ||||
| 							 FromEntity, ToEntity, Existing.info.id); | ||||
| 			MoveUsage(StorageService()->PolicyDB(), DB_, FromPolicy, ToPolicy, Existing.info.id); | ||||
|  | ||||
|         if(DB_.CreateRecord(NewObject)) { | ||||
|             MoveUsage(StorageService()->PolicyDB(),DB_,"",NewObject.managementPolicy,NewObject.info.id); | ||||
|             AddMembership(StorageService()->VenueDB(),&ProvObjects::Venue::configurations,NewObject.venue, NewObject.info.id); | ||||
|             AddMembership(StorageService()->EntityDB(),&ProvObjects::Entity::configurations,NewObject.entity, NewObject.info.id); | ||||
|  | ||||
|             ConfigurationDB::RecordName AddedRecord; | ||||
|             DB_.GetRecord("id", NewObject.info.id, AddedRecord); | ||||
|             Poco::JSON::Object  Answer; | ||||
|             AddedRecord.to_json(Answer); | ||||
|             return ReturnObject(Answer); | ||||
|         } | ||||
|         InternalError(RESTAPI::Errors::RecordNotCreated); | ||||
|     } | ||||
|  | ||||
|     void RESTAPI_configurations_handler::DoPut() { | ||||
|         auto UUID = GetBinding("uuid",""); | ||||
|         ProvObjects::DeviceConfiguration    Existing; | ||||
|         if(UUID.empty() || !DB_.GetRecord("id", UUID, Existing)) { | ||||
|             return NotFound(); | ||||
|         } | ||||
|  | ||||
|         ProvObjects::DeviceConfiguration    NewObject; | ||||
|         const auto & RawObject = ParsedBody_; | ||||
|         if (!NewObject.from_json(RawObject)) { | ||||
|             return BadRequest(RESTAPI::Errors::InvalidJSONDocument); | ||||
|         } | ||||
|  | ||||
|         if((RawObject->has("deviceRules") && !ValidDeviceRules(NewObject.deviceRules,*this))) { | ||||
|             return; | ||||
|         } | ||||
|  | ||||
|         if(!UpdateObjectInfo(RawObject, UserInfo_.userinfo, Existing.info)) { | ||||
|             return BadRequest(RESTAPI::Errors::NameMustBeSet); | ||||
|         } | ||||
|  | ||||
|         if(!NewObject.deviceTypes.empty() && !DeviceTypeCache()->AreAcceptableDeviceTypes(NewObject.deviceTypes, true)) { | ||||
|             return BadRequest(RESTAPI::Errors::InvalidDeviceTypes); | ||||
|         } | ||||
|  | ||||
|         if(!NewObject.deviceTypes.empty()) | ||||
|             Existing.deviceTypes = NewObject.deviceTypes; | ||||
|  | ||||
|         RESTAPI::Errors::msg Error; | ||||
|         if(!ValidateConfigBlock( NewObject,Error)) { | ||||
|             return BadRequest(Error); | ||||
|         } | ||||
|  | ||||
|         if(RawObject->has("configuration")) { | ||||
|             Existing.configuration = NewObject.configuration; | ||||
|         } | ||||
|  | ||||
|         std::string FromPolicy, ToPolicy; | ||||
|         if(!CreateMove(RawObject,"managementPolicy",&ConfigurationDB::RecordName::managementPolicy, Existing, FromPolicy, ToPolicy, StorageService()->PolicyDB())) | ||||
|             return BadRequest(RESTAPI::Errors::EntityMustExist); | ||||
|  | ||||
|         std::string FromEntity, ToEntity; | ||||
|         if(!CreateMove(RawObject,"entity",&ConfigurationDB::RecordName::entity, Existing, FromEntity, ToEntity, StorageService()->EntityDB())) | ||||
|             return BadRequest(RESTAPI::Errors::EntityMustExist); | ||||
|  | ||||
|         std::string FromVenue, ToVenue; | ||||
|         if(!CreateMove(RawObject,"venue",&ConfigurationDB::RecordName::venue, Existing, FromVenue, ToVenue, StorageService()->VenueDB())) | ||||
|             return BadRequest(RESTAPI::Errors::VenueMustExist); | ||||
|  | ||||
|         Types::UUIDvec_t FromVariables, ToVariables; | ||||
|         if(RawObject->has("variables")) { | ||||
|             for(const auto &i:NewObject.variables) { | ||||
|                 if(!i.empty() && !StorageService()->VariablesDB().Exists("id",i)) { | ||||
|                     return BadRequest(RESTAPI::Errors::VariableMustExist); | ||||
|                 } | ||||
|             } | ||||
|             for(const auto &i:Existing.variables) | ||||
|                 FromVariables.emplace_back(i); | ||||
|             for(const auto &i:NewObject.variables) | ||||
|                 ToVariables.emplace_back(i); | ||||
|             FromVariables = Existing.variables; | ||||
|             ToVariables = NewObject.variables; | ||||
|             Existing.variables = ToVariables; | ||||
|         } | ||||
|  | ||||
|         if(RawObject->has("deviceRules")) | ||||
|             Existing.deviceRules = NewObject.deviceRules; | ||||
|  | ||||
|         if(DB_.UpdateRecord("id",UUID,Existing)) { | ||||
|             ManageMembership(StorageService()->VariablesDB(),&ProvObjects::VariableBlock::configurations, FromVariables, ToVariables, Existing.info.id); | ||||
|             ManageMembership(StorageService()->VenueDB(), &ProvObjects::Venue::configurations, FromVenue, ToVenue, Existing.info.id); | ||||
|             ManageMembership(StorageService()->EntityDB(), &ProvObjects::Entity::configurations, FromEntity, ToEntity, Existing.info.id); | ||||
|             MoveUsage(StorageService()->PolicyDB(),DB_,FromPolicy,ToPolicy,Existing.info.id); | ||||
|  | ||||
|             ProvObjects::DeviceConfiguration    D; | ||||
|             DB_.GetRecord("id",UUID,D); | ||||
|             Poco::JSON::Object  Answer; | ||||
|             D.to_json(Answer); | ||||
|             return ReturnObject(Answer); | ||||
|         } | ||||
|         InternalError(RESTAPI::Errors::RecordNotUpdated); | ||||
|     } | ||||
| } | ||||
| 			ProvObjects::DeviceConfiguration D; | ||||
| 			DB_.GetRecord("id", UUID, D); | ||||
| 			Poco::JSON::Object Answer; | ||||
| 			D.to_json(Answer); | ||||
| 			return ReturnObject(Answer); | ||||
| 		} | ||||
| 		InternalError(RESTAPI::Errors::RecordNotUpdated); | ||||
| 	} | ||||
| } // namespace OpenWifi | ||||
| @@ -5,30 +5,31 @@ | ||||
| //	Created by Stephane Bourque on 2021-03-04. | ||||
| //	Arilia Wireless Inc. | ||||
| // | ||||
| #pragma once | ||||
|  | ||||
| #include "framework/MicroService.h" | ||||
| #include "RESTObjects/RESTAPI_ProvObjects.h" | ||||
| #pragma once | ||||
| #include "StorageService.h" | ||||
| #include "framework/RESTAPI_Handler.h" | ||||
|  | ||||
| namespace OpenWifi { | ||||
|     class RESTAPI_configurations_handler : public RESTAPIHandler { | ||||
|     public: | ||||
|         RESTAPI_configurations_handler(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L, RESTAPI_GenericServer & Server, uint64_t TransactionId, bool Internal) | ||||
|         : RESTAPIHandler(bindings, L, | ||||
|                          std::vector<std::string>{ | ||||
|             Poco::Net::HTTPRequest::HTTP_GET, Poco::Net::HTTPRequest::HTTP_POST, | ||||
|             Poco::Net::HTTPRequest::HTTP_PUT, Poco::Net::HTTPRequest::HTTP_DELETE, | ||||
|             Poco::Net::HTTPRequest::HTTP_OPTIONS}, | ||||
|             Server, | ||||
|             TransactionId, | ||||
|             Internal){} | ||||
|         static auto PathName() { return std::list<std::string>{"/api/v1/configuration/{uuid}"}; }; | ||||
|     private: | ||||
|         ConfigurationDB     &DB_=StorageService()->ConfigurationDB(); | ||||
|         void DoGet(); | ||||
|         void DoPost(); | ||||
|         void DoPut(); | ||||
|         void DoDelete(); | ||||
|     }; | ||||
| } | ||||
| 	class RESTAPI_configurations_handler : public RESTAPIHandler { | ||||
| 	  public: | ||||
| 		RESTAPI_configurations_handler(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L, | ||||
| 									   RESTAPI_GenericServerAccounting &Server, | ||||
| 									   uint64_t TransactionId, bool Internal) | ||||
| 			: RESTAPIHandler(bindings, L, | ||||
| 							 std::vector<std::string>{Poco::Net::HTTPRequest::HTTP_GET, | ||||
| 													  Poco::Net::HTTPRequest::HTTP_POST, | ||||
| 													  Poco::Net::HTTPRequest::HTTP_PUT, | ||||
| 													  Poco::Net::HTTPRequest::HTTP_DELETE, | ||||
| 													  Poco::Net::HTTPRequest::HTTP_OPTIONS}, | ||||
| 							 Server, TransactionId, Internal) {} | ||||
| 		static auto PathName() { return std::list<std::string>{"/api/v1/configuration/{uuid}"}; }; | ||||
|  | ||||
| 	  private: | ||||
| 		ConfigurationDB &DB_ = StorageService()->ConfigurationDB(); | ||||
| 		void DoGet(); | ||||
| 		void DoPost(); | ||||
| 		void DoPut(); | ||||
| 		void DoDelete(); | ||||
| 	}; | ||||
| } // namespace OpenWifi | ||||
|   | ||||
| @@ -4,12 +4,12 @@ | ||||
|  | ||||
| #include "RESTAPI_configurations_list_handler.h" | ||||
|  | ||||
| #include "RESTAPI_db_helpers.h" | ||||
| #include "RESTObjects/RESTAPI_ProvObjects.h" | ||||
| #include "StorageService.h" | ||||
| #include "RESTAPI_db_helpers.h" | ||||
|  | ||||
| namespace OpenWifi{ | ||||
|     void RESTAPI_configurations_list_handler::DoGet() { | ||||
|         return ListHandler<ConfigurationDB>("configurations", DB_, *this); | ||||
|     } | ||||
| } | ||||
| namespace OpenWifi { | ||||
| 	void RESTAPI_configurations_list_handler::DoGet() { | ||||
| 		return ListHandler<ConfigurationDB>("configurations", DB_, *this); | ||||
| 	} | ||||
| } // namespace OpenWifi | ||||
| @@ -3,28 +3,28 @@ | ||||
| // | ||||
|  | ||||
| #pragma once | ||||
|  | ||||
| #include "framework/MicroService.h" | ||||
| #include "StorageService.h" | ||||
| #include "framework/RESTAPI_Handler.h" | ||||
|  | ||||
| namespace OpenWifi { | ||||
|  | ||||
|     class RESTAPI_configurations_list_handler : public RESTAPIHandler { | ||||
|     public: | ||||
|         RESTAPI_configurations_list_handler(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L, RESTAPI_GenericServer & Server, uint64_t TransactionId, bool Internal) | ||||
|         : RESTAPIHandler(bindings, L, | ||||
|                          std::vector<std::string>{ | ||||
|             Poco::Net::HTTPRequest::HTTP_GET, | ||||
|             Poco::Net::HTTPRequest::HTTP_OPTIONS}, | ||||
|             Server, | ||||
|             TransactionId, | ||||
|             Internal){} | ||||
|         static auto PathName() { return std::list<std::string>{"/api/v1/configuration"}; }; | ||||
|     private: | ||||
|         ConfigurationDB & DB_=StorageService()->ConfigurationDB(); | ||||
|         void DoGet() final; | ||||
|         void DoPost() final {}; | ||||
|         void DoPut() final {}; | ||||
|         void DoDelete() final {}; | ||||
|     }; | ||||
| } | ||||
| 	class RESTAPI_configurations_list_handler : public RESTAPIHandler { | ||||
| 	  public: | ||||
| 		RESTAPI_configurations_list_handler(const RESTAPIHandler::BindingMap &bindings, | ||||
| 											Poco::Logger &L, | ||||
| 											RESTAPI_GenericServerAccounting &Server, | ||||
| 											uint64_t TransactionId, bool Internal) | ||||
| 			: RESTAPIHandler(bindings, L, | ||||
| 							 std::vector<std::string>{Poco::Net::HTTPRequest::HTTP_GET, | ||||
| 													  Poco::Net::HTTPRequest::HTTP_OPTIONS}, | ||||
| 							 Server, TransactionId, Internal) {} | ||||
| 		static auto PathName() { return std::list<std::string>{"/api/v1/configuration"}; }; | ||||
|  | ||||
| 	  private: | ||||
| 		ConfigurationDB &DB_ = StorageService()->ConfigurationDB(); | ||||
| 		void DoGet() final; | ||||
| 		void DoPost() final{}; | ||||
| 		void DoPut() final{}; | ||||
| 		void DoDelete() final{}; | ||||
| 	}; | ||||
| } // namespace OpenWifi | ||||
|   | ||||
| @@ -8,163 +8,171 @@ | ||||
|  | ||||
| #include "RESTAPI_contact_handler.h" | ||||
|  | ||||
| #include "framework/ow_constants.h" | ||||
| #include "RESTObjects/RESTAPI_ProvObjects.h" | ||||
| #include "RESTAPI_db_helpers.h" | ||||
| #include "RESTObjects/RESTAPI_ProvObjects.h" | ||||
| #include "framework/ow_constants.h" | ||||
|  | ||||
| namespace OpenWifi{ | ||||
|     void RESTAPI_contact_handler::DoGet() { | ||||
| namespace OpenWifi { | ||||
| 	void RESTAPI_contact_handler::DoGet() { | ||||
|  | ||||
|         std::string UUID = GetBinding("uuid",""); | ||||
|         ProvObjects::Contact   Existing; | ||||
|         if(UUID.empty() || !DB_.GetRecord("id", UUID, Existing)) { | ||||
|             return NotFound(); | ||||
|         } | ||||
| 		std::string UUID = GetBinding("uuid", ""); | ||||
| 		ProvObjects::Contact Existing; | ||||
| 		if (UUID.empty() || !DB_.GetRecord("id", UUID, Existing)) { | ||||
| 			return NotFound(); | ||||
| 		} | ||||
|  | ||||
|         Poco::JSON::Object  Answer; | ||||
|         std::string Arg; | ||||
| 		Poco::JSON::Object Answer; | ||||
| 		std::string Arg; | ||||
|  | ||||
|         if(HasParameter("expandInUse",Arg) && Arg=="true") { | ||||
|             Storage::ExpandedListMap    M; | ||||
|             std::vector<std::string>    Errors; | ||||
|             Poco::JSON::Object  Inner; | ||||
|             if(StorageService()->ExpandInUse(Existing.inUse,M,Errors)) { | ||||
|                 for(const auto &[type,list]:M) { | ||||
|                     Poco::JSON::Array   ObjList; | ||||
|                     for(const auto &i:list.entries) { | ||||
|                         Poco::JSON::Object  O; | ||||
|                         i.to_json(O); | ||||
|                         ObjList.add(O); | ||||
|                     } | ||||
|                     Inner.set(type,ObjList); | ||||
|                 } | ||||
|             } | ||||
|             Answer.set("entries", Inner); | ||||
|             return ReturnObject(Answer); | ||||
|         } else if(QB_.AdditionalInfo) { | ||||
|             AddExtendedInfo(Existing, Answer); | ||||
|         } | ||||
| 		if (HasParameter("expandInUse", Arg) && Arg == "true") { | ||||
| 			Storage::ExpandedListMap M; | ||||
| 			std::vector<std::string> Errors; | ||||
| 			Poco::JSON::Object Inner; | ||||
| 			if (StorageService()->ExpandInUse(Existing.inUse, M, Errors)) { | ||||
| 				for (const auto &[type, list] : M) { | ||||
| 					Poco::JSON::Array ObjList; | ||||
| 					for (const auto &i : list.entries) { | ||||
| 						Poco::JSON::Object O; | ||||
| 						i.to_json(O); | ||||
| 						ObjList.add(O); | ||||
| 					} | ||||
| 					Inner.set(type, ObjList); | ||||
| 				} | ||||
| 			} | ||||
| 			Answer.set("entries", Inner); | ||||
| 			return ReturnObject(Answer); | ||||
| 		} else if (QB_.AdditionalInfo) { | ||||
| 			AddExtendedInfo(Existing, Answer); | ||||
| 		} | ||||
|  | ||||
|         Existing.to_json(Answer); | ||||
|         ReturnObject(Answer); | ||||
|     } | ||||
| 		Existing.to_json(Answer); | ||||
| 		ReturnObject(Answer); | ||||
| 	} | ||||
|  | ||||
|     void RESTAPI_contact_handler::DoDelete() { | ||||
| 	void RESTAPI_contact_handler::DoDelete() { | ||||
|  | ||||
|         std::string UUID = GetBinding("uuid",""); | ||||
|         ProvObjects::Contact   Existing; | ||||
|         if(UUID.empty() || !DB_.GetRecord("id", UUID, Existing)) { | ||||
|             return NotFound(); | ||||
|         } | ||||
| 		std::string UUID = GetBinding("uuid", ""); | ||||
| 		ProvObjects::Contact Existing; | ||||
| 		if (UUID.empty() || !DB_.GetRecord("id", UUID, Existing)) { | ||||
| 			return NotFound(); | ||||
| 		} | ||||
|  | ||||
|         bool Force=false; | ||||
|         std::string Arg; | ||||
|         if(HasParameter("force",Arg) && Arg=="true") | ||||
|             Force=true; | ||||
| 		bool Force = false; | ||||
| 		std::string Arg; | ||||
| 		if (HasParameter("force", Arg) && Arg == "true") | ||||
| 			Force = true; | ||||
|  | ||||
|         if(!Force && !Existing.inUse.empty()) { | ||||
|             return BadRequest(RESTAPI::Errors::StillInUse); | ||||
|         } | ||||
| 		if (!Force && !Existing.inUse.empty()) { | ||||
| 			return BadRequest(RESTAPI::Errors::StillInUse); | ||||
| 		} | ||||
|  | ||||
|         DB_.DeleteRecord("id",UUID); | ||||
|         RemoveMembership(StorageService()->EntityDB(),&ProvObjects::Entity::contacts,Existing.entity,Existing.info.id); | ||||
|         MoveUsage(StorageService()->PolicyDB(),DB_,Existing.info.id,"",Existing.info.id); | ||||
|         return OK(); | ||||
|     } | ||||
| 		DB_.DeleteRecord("id", UUID); | ||||
| 		RemoveMembership(StorageService()->EntityDB(), &ProvObjects::Entity::contacts, | ||||
| 						 Existing.entity, Existing.info.id); | ||||
| 		MoveUsage(StorageService()->PolicyDB(), DB_, Existing.info.id, "", Existing.info.id); | ||||
| 		return OK(); | ||||
| 	} | ||||
|  | ||||
|     void RESTAPI_contact_handler::DoPost() { | ||||
|         std::string UUID = GetBinding(RESTAPI::Protocol::UUID,""); | ||||
| 	void RESTAPI_contact_handler::DoPost() { | ||||
| 		std::string UUID = GetBinding(RESTAPI::Protocol::UUID, ""); | ||||
|  | ||||
|         if(UUID.empty()) { | ||||
|             return BadRequest(RESTAPI::Errors::MissingUUID); | ||||
|         } | ||||
| 		if (UUID.empty()) { | ||||
| 			return BadRequest(RESTAPI::Errors::MissingUUID); | ||||
| 		} | ||||
|  | ||||
|         const auto & Obj = ParsedBody_; | ||||
|         ProvObjects::Contact NewObject; | ||||
|         if (!NewObject.from_json(Obj)) { | ||||
|             return BadRequest(RESTAPI::Errors::InvalidJSONDocument); | ||||
|         } | ||||
| 		const auto &Obj = ParsedBody_; | ||||
| 		ProvObjects::Contact NewObject; | ||||
| 		if (!NewObject.from_json(Obj)) { | ||||
| 			return BadRequest(RESTAPI::Errors::InvalidJSONDocument); | ||||
| 		} | ||||
|  | ||||
|         if(!ProvObjects::CreateObjectInfo(Obj,UserInfo_.userinfo,NewObject.info)) { | ||||
|             return BadRequest(RESTAPI::Errors::NameMustBeSet); | ||||
|         } | ||||
| 		if (!ProvObjects::CreateObjectInfo(Obj, UserInfo_.userinfo, NewObject.info)) { | ||||
| 			return BadRequest(RESTAPI::Errors::NameMustBeSet); | ||||
| 		} | ||||
|  | ||||
|         if(NewObject.entity.empty() && !StorageService()->EntityDB().Exists("id",NewObject.entity)) { | ||||
|             return BadRequest(RESTAPI::Errors::EntityMustExist); | ||||
|         } | ||||
| 		if (NewObject.entity.empty() && | ||||
| 			!StorageService()->EntityDB().Exists("id", NewObject.entity)) { | ||||
| 			return BadRequest(RESTAPI::Errors::EntityMustExist); | ||||
| 		} | ||||
|  | ||||
|         if(!NewObject.managementPolicy.empty() && !StorageService()->PolicyDB().Exists("id",NewObject.managementPolicy)) { | ||||
|             return BadRequest(RESTAPI::Errors::UnknownManagementPolicyUUID); | ||||
|         } | ||||
| 		if (!NewObject.managementPolicy.empty() && | ||||
| 			!StorageService()->PolicyDB().Exists("id", NewObject.managementPolicy)) { | ||||
| 			return BadRequest(RESTAPI::Errors::UnknownManagementPolicyUUID); | ||||
| 		} | ||||
|  | ||||
|         NewObject.inUse.clear(); | ||||
| 		NewObject.inUse.clear(); | ||||
|  | ||||
|         if(DB_.CreateRecord(NewObject)) { | ||||
|             AddMembership(StorageService()->EntityDB(),&ProvObjects::Entity::contacts,NewObject.entity,NewObject.info.id); | ||||
|             MoveUsage(StorageService()->PolicyDB(),DB_,"",NewObject.managementPolicy,NewObject.info.id); | ||||
| 		if (DB_.CreateRecord(NewObject)) { | ||||
| 			AddMembership(StorageService()->EntityDB(), &ProvObjects::Entity::contacts, | ||||
| 						  NewObject.entity, NewObject.info.id); | ||||
| 			MoveUsage(StorageService()->PolicyDB(), DB_, "", NewObject.managementPolicy, | ||||
| 					  NewObject.info.id); | ||||
|  | ||||
|             ProvObjects::Contact    NewContact; | ||||
|             StorageService()->ContactDB().GetRecord("id", NewObject.info.id, NewContact); | ||||
| 			ProvObjects::Contact NewContact; | ||||
| 			StorageService()->ContactDB().GetRecord("id", NewObject.info.id, NewContact); | ||||
|  | ||||
|             Poco::JSON::Object Answer; | ||||
|             NewContact.to_json(Answer); | ||||
|             ReturnObject(Answer); | ||||
|             return; | ||||
|         } | ||||
|         InternalError(RESTAPI::Errors::RecordNotCreated); | ||||
|     } | ||||
| 			Poco::JSON::Object Answer; | ||||
| 			NewContact.to_json(Answer); | ||||
| 			ReturnObject(Answer); | ||||
| 			return; | ||||
| 		} | ||||
| 		InternalError(RESTAPI::Errors::RecordNotCreated); | ||||
| 	} | ||||
|  | ||||
|     void RESTAPI_contact_handler::DoPut() { | ||||
|         std::string UUID = GetBinding(RESTAPI::Protocol::UUID,""); | ||||
|         ProvObjects::Contact   Existing; | ||||
|         if(UUID.empty() || !DB_.GetRecord("id", UUID, Existing)) { | ||||
|             return NotFound(); | ||||
|         } | ||||
| 	void RESTAPI_contact_handler::DoPut() { | ||||
| 		std::string UUID = GetBinding(RESTAPI::Protocol::UUID, ""); | ||||
| 		ProvObjects::Contact Existing; | ||||
| 		if (UUID.empty() || !DB_.GetRecord("id", UUID, Existing)) { | ||||
| 			return NotFound(); | ||||
| 		} | ||||
|  | ||||
|         const auto & RawObject = ParsedBody_; | ||||
|         ProvObjects::Contact NewObject; | ||||
|         if (!NewObject.from_json(RawObject)) { | ||||
|             return BadRequest(RESTAPI::Errors::InvalidJSONDocument); | ||||
|         } | ||||
| 		const auto &RawObject = ParsedBody_; | ||||
| 		ProvObjects::Contact NewObject; | ||||
| 		if (!NewObject.from_json(RawObject)) { | ||||
| 			return BadRequest(RESTAPI::Errors::InvalidJSONDocument); | ||||
| 		} | ||||
|  | ||||
|         if(!UpdateObjectInfo(RawObject, UserInfo_.userinfo, Existing.info)) { | ||||
|             return BadRequest(RESTAPI::Errors::NameMustBeSet); | ||||
|         } | ||||
| 		if (!UpdateObjectInfo(RawObject, UserInfo_.userinfo, Existing.info)) { | ||||
| 			return BadRequest(RESTAPI::Errors::NameMustBeSet); | ||||
| 		} | ||||
|  | ||||
|         std::string FromPolicy, ToPolicy; | ||||
|         if(!CreateMove(RawObject,"managementPolicy",&ContactDB::RecordName::managementPolicy, Existing, FromPolicy, ToPolicy, StorageService()->PolicyDB())) | ||||
|             return BadRequest(RESTAPI::Errors::EntityMustExist); | ||||
| 		std::string FromPolicy, ToPolicy; | ||||
| 		if (!CreateMove(RawObject, "managementPolicy", &ContactDB::RecordName::managementPolicy, | ||||
| 						Existing, FromPolicy, ToPolicy, StorageService()->PolicyDB())) | ||||
| 			return BadRequest(RESTAPI::Errors::EntityMustExist); | ||||
|  | ||||
|         std::string FromEntity, ToEntity; | ||||
|         if(!CreateMove(RawObject,"entity",&ContactDB::RecordName::entity, Existing, FromEntity, ToEntity, StorageService()->EntityDB())) | ||||
|             return BadRequest(RESTAPI::Errors::EntityMustExist); | ||||
| 		std::string FromEntity, ToEntity; | ||||
| 		if (!CreateMove(RawObject, "entity", &ContactDB::RecordName::entity, Existing, FromEntity, | ||||
| 						ToEntity, StorageService()->EntityDB())) | ||||
| 			return BadRequest(RESTAPI::Errors::EntityMustExist); | ||||
|  | ||||
|         AssignIfPresent(RawObject, "title", Existing.title); | ||||
|         AssignIfPresent(RawObject, "salutation", Existing.salutation); | ||||
|         AssignIfPresent(RawObject, "firstname", Existing.firstname); | ||||
|         AssignIfPresent(RawObject, "lastname", Existing.lastname); | ||||
|         AssignIfPresent(RawObject, "initials", Existing.initials); | ||||
|         AssignIfPresent(RawObject, "visual", Existing.visual); | ||||
|         AssignIfPresent(RawObject, "primaryEmail", Existing.primaryEmail); | ||||
|         AssignIfPresent(RawObject, "secondaryEmail", Existing.secondaryEmail); | ||||
|         AssignIfPresent(RawObject, "accessPIN", Existing.accessPIN); | ||||
|         if(RawObject->has("type")) | ||||
|             Existing.type = NewObject.type; | ||||
|         if(RawObject->has("mobiles")) | ||||
|             Existing.mobiles = NewObject.mobiles; | ||||
|         if(RawObject->has("phones")) | ||||
|             Existing.phones = NewObject.phones; | ||||
| 		AssignIfPresent(RawObject, "title", Existing.title); | ||||
| 		AssignIfPresent(RawObject, "salutation", Existing.salutation); | ||||
| 		AssignIfPresent(RawObject, "firstname", Existing.firstname); | ||||
| 		AssignIfPresent(RawObject, "lastname", Existing.lastname); | ||||
| 		AssignIfPresent(RawObject, "initials", Existing.initials); | ||||
| 		AssignIfPresent(RawObject, "visual", Existing.visual); | ||||
| 		AssignIfPresent(RawObject, "primaryEmail", Existing.primaryEmail); | ||||
| 		AssignIfPresent(RawObject, "secondaryEmail", Existing.secondaryEmail); | ||||
| 		AssignIfPresent(RawObject, "accessPIN", Existing.accessPIN); | ||||
| 		if (RawObject->has("type")) | ||||
| 			Existing.type = NewObject.type; | ||||
| 		if (RawObject->has("mobiles")) | ||||
| 			Existing.mobiles = NewObject.mobiles; | ||||
| 		if (RawObject->has("phones")) | ||||
| 			Existing.phones = NewObject.phones; | ||||
|  | ||||
|         if(DB_.UpdateRecord("id", UUID, Existing)) { | ||||
|             MoveUsage(StorageService()->PolicyDB(),DB_,FromPolicy,ToPolicy,Existing.info.id); | ||||
|             ManageMembership(StorageService()->EntityDB(),&ProvObjects::Entity::contacts,FromEntity,ToEntity,Existing.info.id); | ||||
| 		if (DB_.UpdateRecord("id", UUID, Existing)) { | ||||
| 			MoveUsage(StorageService()->PolicyDB(), DB_, FromPolicy, ToPolicy, Existing.info.id); | ||||
| 			ManageMembership(StorageService()->EntityDB(), &ProvObjects::Entity::contacts, | ||||
| 							 FromEntity, ToEntity, Existing.info.id); | ||||
|  | ||||
|             ProvObjects::Contact    NewObjectAdded; | ||||
|             DB_.GetRecord("id", UUID, NewObjectAdded); | ||||
|             Poco::JSON::Object  Answer; | ||||
|             NewObjectAdded.to_json(Answer); | ||||
|             return ReturnObject(Answer); | ||||
|         } | ||||
|         InternalError(RESTAPI::Errors::RecordNotUpdated); | ||||
|     } | ||||
| } | ||||
| 			ProvObjects::Contact NewObjectAdded; | ||||
| 			DB_.GetRecord("id", UUID, NewObjectAdded); | ||||
| 			Poco::JSON::Object Answer; | ||||
| 			NewObjectAdded.to_json(Answer); | ||||
| 			return ReturnObject(Answer); | ||||
| 		} | ||||
| 		InternalError(RESTAPI::Errors::RecordNotUpdated); | ||||
| 	} | ||||
| } // namespace OpenWifi | ||||
| @@ -7,29 +7,29 @@ | ||||
| // | ||||
|  | ||||
| #pragma once | ||||
|  | ||||
| #include "framework/MicroService.h" | ||||
| #include "StorageService.h" | ||||
| #include "framework/RESTAPI_Handler.h" | ||||
|  | ||||
| namespace OpenWifi { | ||||
|     class RESTAPI_contact_handler : public RESTAPIHandler { | ||||
|     public: | ||||
|         RESTAPI_contact_handler(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L, RESTAPI_GenericServer & Server, uint64_t TransactionId, bool Internal) | ||||
|         : RESTAPIHandler(bindings, L, | ||||
|                          std::vector<std::string>{ | ||||
|             Poco::Net::HTTPRequest::HTTP_GET, Poco::Net::HTTPRequest::HTTP_POST, | ||||
|             Poco::Net::HTTPRequest::HTTP_PUT, Poco::Net::HTTPRequest::HTTP_DELETE, | ||||
|             Poco::Net::HTTPRequest::HTTP_OPTIONS}, | ||||
|             Server, | ||||
|             TransactionId, | ||||
|             Internal){} | ||||
|         static auto PathName() { return std::list<std::string>{"/api/v1/contact/{uuid}"}; }; | ||||
| 	class RESTAPI_contact_handler : public RESTAPIHandler { | ||||
| 	  public: | ||||
| 		RESTAPI_contact_handler(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L, | ||||
| 								RESTAPI_GenericServerAccounting &Server, uint64_t TransactionId, | ||||
| 								bool Internal) | ||||
| 			: RESTAPIHandler(bindings, L, | ||||
| 							 std::vector<std::string>{Poco::Net::HTTPRequest::HTTP_GET, | ||||
| 													  Poco::Net::HTTPRequest::HTTP_POST, | ||||
| 													  Poco::Net::HTTPRequest::HTTP_PUT, | ||||
| 													  Poco::Net::HTTPRequest::HTTP_DELETE, | ||||
| 													  Poco::Net::HTTPRequest::HTTP_OPTIONS}, | ||||
| 							 Server, TransactionId, Internal) {} | ||||
| 		static auto PathName() { return std::list<std::string>{"/api/v1/contact/{uuid}"}; }; | ||||
|  | ||||
|     private: | ||||
|         ContactDB       &DB_=StorageService()->ContactDB(); | ||||
|         void DoGet() final; | ||||
|         void DoPost() final; | ||||
|         void DoPut() final; | ||||
|         void DoDelete() final; | ||||
|     }; | ||||
| } | ||||
| 	  private: | ||||
| 		ContactDB &DB_ = StorageService()->ContactDB(); | ||||
| 		void DoGet() final; | ||||
| 		void DoPost() final; | ||||
| 		void DoPut() final; | ||||
| 		void DoDelete() final; | ||||
| 	}; | ||||
| } // namespace OpenWifi | ||||
|   | ||||
| @@ -4,12 +4,12 @@ | ||||
|  | ||||
| #include "RESTAPI_contact_list_handler.h" | ||||
|  | ||||
| #include "RESTAPI_db_helpers.h" | ||||
| #include "RESTObjects/RESTAPI_ProvObjects.h" | ||||
| #include "StorageService.h" | ||||
| #include "RESTAPI_db_helpers.h" | ||||
|  | ||||
| namespace OpenWifi{ | ||||
|     void RESTAPI_contact_list_handler::DoGet() { | ||||
|         return ListHandler<ContactDB>("contacts", DB_, *this); | ||||
|     } | ||||
| } | ||||
| namespace OpenWifi { | ||||
| 	void RESTAPI_contact_list_handler::DoGet() { | ||||
| 		return ListHandler<ContactDB>("contacts", DB_, *this); | ||||
| 	} | ||||
| } // namespace OpenWifi | ||||
| @@ -3,29 +3,27 @@ | ||||
| // | ||||
|  | ||||
| #pragma once | ||||
|  | ||||
| #include "framework/MicroService.h" | ||||
| #include "RESTObjects/RESTAPI_ProvObjects.h" | ||||
| #include "StorageService.h" | ||||
| #include "framework/RESTAPI_Handler.h" | ||||
|  | ||||
| namespace OpenWifi { | ||||
|  | ||||
|     class RESTAPI_contact_list_handler : public RESTAPIHandler { | ||||
|     public: | ||||
|         RESTAPI_contact_list_handler(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L, RESTAPI_GenericServer & Server, uint64_t TransactionId, bool Internal) | ||||
|         : RESTAPIHandler(bindings, L, | ||||
|                          std::vector<std::string>{ | ||||
|             Poco::Net::HTTPRequest::HTTP_GET, | ||||
|             Poco::Net::HTTPRequest::HTTP_OPTIONS}, | ||||
|             Server, | ||||
|             TransactionId, | ||||
|             Internal){} | ||||
|         static auto PathName() { return std::list<std::string>{"/api/v1/contact"}; }; | ||||
|     private: | ||||
|         ContactDB   & DB_=StorageService()->ContactDB(); | ||||
|         void DoGet() final; | ||||
|         void DoPost() final {}; | ||||
|         void DoPut() final {}; | ||||
|         void DoDelete() final {}; | ||||
|     }; | ||||
| } | ||||
| 	class RESTAPI_contact_list_handler : public RESTAPIHandler { | ||||
| 	  public: | ||||
| 		RESTAPI_contact_list_handler(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L, | ||||
| 									 RESTAPI_GenericServerAccounting &Server, | ||||
| 									 uint64_t TransactionId, bool Internal) | ||||
| 			: RESTAPIHandler(bindings, L, | ||||
| 							 std::vector<std::string>{Poco::Net::HTTPRequest::HTTP_GET, | ||||
| 													  Poco::Net::HTTPRequest::HTTP_OPTIONS}, | ||||
| 							 Server, TransactionId, Internal) {} | ||||
| 		static auto PathName() { return std::list<std::string>{"/api/v1/contact"}; }; | ||||
|  | ||||
| 	  private: | ||||
| 		ContactDB &DB_ = StorageService()->ContactDB(); | ||||
| 		void DoGet() final; | ||||
| 		void DoPost() final{}; | ||||
| 		void DoPut() final{}; | ||||
| 		void DoDelete() final{}; | ||||
| 	}; | ||||
| } // namespace OpenWifi | ||||
|   | ||||
| @@ -6,170 +6,176 @@ | ||||
| //	Arilia Wireless Inc. | ||||
| // | ||||
|  | ||||
|  | ||||
| #include "RESTAPI_entity_handler.h" | ||||
|  | ||||
| #include "RESTAPI_db_helpers.h" | ||||
| #include "RESTObjects/RESTAPI_ProvObjects.h" | ||||
| #include "RESTObjects/RESTAPI_SecurityObjects.h" | ||||
| #include "StorageService.h" | ||||
| #include "RESTAPI_db_helpers.h" | ||||
|  | ||||
| namespace OpenWifi{ | ||||
| #include "framework/CIDR.h" | ||||
|  | ||||
|     void RESTAPI_entity_handler::DoGet() { | ||||
|         std::string UUID = GetBinding("uuid", ""); | ||||
|         ProvObjects::Entity Existing; | ||||
|         if(UUID.empty() || !DB_.GetRecord("id",UUID,Existing)) { | ||||
|             return NotFound(); | ||||
|         } | ||||
| namespace OpenWifi { | ||||
|  | ||||
|         Poco::JSON::Object Answer; | ||||
|         Existing.to_json(Answer); | ||||
|         if(NeedAdditionalInfo()) | ||||
|             AddExtendedInfo( Existing, Answer); | ||||
|         ReturnObject(Answer); | ||||
|     } | ||||
| 	void RESTAPI_entity_handler::DoGet() { | ||||
| 		std::string UUID = GetBinding("uuid", ""); | ||||
| 		ProvObjects::Entity Existing; | ||||
| 		if (UUID.empty() || !DB_.GetRecord("id", UUID, Existing)) { | ||||
| 			return NotFound(); | ||||
| 		} | ||||
|  | ||||
|     void RESTAPI_entity_handler::DoDelete() { | ||||
|         std::string UUID = GetBinding("uuid", ""); | ||||
|         ProvObjects::Entity Existing; | ||||
|         if(UUID.empty() || !DB_.GetRecord("id",UUID,Existing)) { | ||||
|             return NotFound(); | ||||
|         } | ||||
| 		Poco::JSON::Object Answer; | ||||
| 		Existing.to_json(Answer); | ||||
| 		if (NeedAdditionalInfo()) | ||||
| 			AddExtendedInfo(Existing, Answer); | ||||
| 		ReturnObject(Answer); | ||||
| 	} | ||||
|  | ||||
|         if(UUID == EntityDB::RootUUID()) { | ||||
|             return BadRequest(RESTAPI::Errors::CannotDeleteRoot); | ||||
|         } | ||||
| 	void RESTAPI_entity_handler::DoDelete() { | ||||
| 		std::string UUID = GetBinding("uuid", ""); | ||||
| 		ProvObjects::Entity Existing; | ||||
| 		if (UUID.empty() || !DB_.GetRecord("id", UUID, Existing)) { | ||||
| 			return NotFound(); | ||||
| 		} | ||||
|  | ||||
|         if( !Existing.children.empty() || !Existing.devices.empty() || !Existing.venues.empty() || !Existing.locations.empty() | ||||
|             || !Existing.contacts.empty() || !Existing.configurations.empty()) { | ||||
|             return BadRequest(RESTAPI::Errors::StillInUse); | ||||
|         } | ||||
| 		if (UUID == EntityDB::RootUUID()) { | ||||
| 			return BadRequest(RESTAPI::Errors::CannotDeleteRoot); | ||||
| 		} | ||||
|  | ||||
|         MoveUsage(StorageService()->PolicyDB(),DB_,Existing.managementPolicy,"",Existing.info.id); | ||||
|         DB_.DeleteRecord("id",UUID); | ||||
|         DB_.DeleteChild("id",Existing.parent,UUID); | ||||
|         return OK(); | ||||
|     } | ||||
| 		if (!Existing.children.empty() || !Existing.devices.empty() || !Existing.venues.empty() || | ||||
| 			!Existing.locations.empty() || !Existing.contacts.empty() || | ||||
| 			!Existing.configurations.empty()) { | ||||
| 			return BadRequest(RESTAPI::Errors::StillInUse); | ||||
| 		} | ||||
|  | ||||
|     void RESTAPI_entity_handler::DoPost() { | ||||
|         std::string UUID = GetBinding("uuid", ""); | ||||
|         if(UUID.empty()) { | ||||
|             return BadRequest(RESTAPI::Errors::MissingUUID); | ||||
|         } | ||||
| 		MoveUsage(StorageService()->PolicyDB(), DB_, Existing.managementPolicy, "", | ||||
| 				  Existing.info.id); | ||||
| 		DB_.DeleteRecord("id", UUID); | ||||
| 		DB_.DeleteChild("id", Existing.parent, UUID); | ||||
| 		return OK(); | ||||
| 	} | ||||
|  | ||||
|         if(UUID==EntityDB::RootUUID()) { | ||||
|             return BadRequest(RESTAPI::Errors::MissingOrInvalidParameters); | ||||
|         } | ||||
| 	void RESTAPI_entity_handler::DoPost() { | ||||
| 		std::string UUID = GetBinding("uuid", ""); | ||||
| 		if (UUID.empty()) { | ||||
| 			return BadRequest(RESTAPI::Errors::MissingUUID); | ||||
| 		} | ||||
|  | ||||
|         const auto & RawObject = ParsedBody_; | ||||
|         ProvObjects::Entity NewEntity; | ||||
|         if (!NewEntity.from_json(RawObject)) { | ||||
|             return BadRequest(RESTAPI::Errors::InvalidJSONDocument); | ||||
|         } | ||||
| 		if (UUID == EntityDB::RootUUID()) { | ||||
| 			return BadRequest(RESTAPI::Errors::MissingOrInvalidParameters); | ||||
| 		} | ||||
|  | ||||
|         if((RawObject->has("deviceRules") && !ValidDeviceRules(NewEntity.deviceRules,*this))) { | ||||
|             return; | ||||
|         } | ||||
| 		const auto &RawObject = ParsedBody_; | ||||
| 		ProvObjects::Entity NewEntity; | ||||
| 		if (!NewEntity.from_json(RawObject)) { | ||||
| 			return BadRequest(RESTAPI::Errors::InvalidJSONDocument); | ||||
| 		} | ||||
|  | ||||
|         if(!ProvObjects::CreateObjectInfo(RawObject,UserInfo_.userinfo,NewEntity.info)) { | ||||
|             return BadRequest(RESTAPI::Errors::NameMustBeSet); | ||||
|         } | ||||
| 		if ((RawObject->has("deviceRules") && !ValidDeviceRules(NewEntity.deviceRules, *this))) { | ||||
| 			return; | ||||
| 		} | ||||
|  | ||||
|         //  When creating an entity, it cannot have any relations other that parent, notes, name, description. Everything else | ||||
|         //  must be conveyed through PUT. | ||||
|         NewEntity.info.id = (UUID==EntityDB::RootUUID()) ? UUID : MicroService::CreateUUID(); | ||||
| 		if (!ProvObjects::CreateObjectInfo(RawObject, UserInfo_.userinfo, NewEntity.info)) { | ||||
| 			return BadRequest(RESTAPI::Errors::NameMustBeSet); | ||||
| 		} | ||||
|  | ||||
|         if(UUID==EntityDB::RootUUID()) { | ||||
|             NewEntity.parent=""; | ||||
|         } else if(NewEntity.parent.empty() || !DB_.Exists("id",NewEntity.parent)) { | ||||
|             return BadRequest(RESTAPI::Errors::ParentUUIDMustExist); | ||||
|         } | ||||
| 		//  When creating an entity, it cannot have any relations other that parent, notes, name, | ||||
| 		//  description. Everything else must be conveyed through PUT. | ||||
| 		NewEntity.info.id = (UUID == EntityDB::RootUUID()) ? UUID : MicroServiceCreateUUID(); | ||||
|  | ||||
|         if(!NewEntity.managementPolicy.empty() && !StorageService()->PolicyDB().Exists("id", NewEntity.managementPolicy)){ | ||||
|             return BadRequest(RESTAPI::Errors::UnknownManagementPolicyUUID); | ||||
|         } | ||||
| 		if (UUID == EntityDB::RootUUID()) { | ||||
| 			NewEntity.parent = ""; | ||||
| 		} else if (NewEntity.parent.empty() || !DB_.Exists("id", NewEntity.parent)) { | ||||
| 			return BadRequest(RESTAPI::Errors::ParentUUIDMustExist); | ||||
| 		} | ||||
|  | ||||
|         if(!NewEntity.sourceIP.empty() && !CIDR::ValidateIpRanges(NewEntity.sourceIP)) { | ||||
|             return BadRequest(RESTAPI::Errors::InvalidIPRanges); | ||||
|         } | ||||
| 		if (!NewEntity.managementPolicy.empty() && | ||||
| 			!StorageService()->PolicyDB().Exists("id", NewEntity.managementPolicy)) { | ||||
| 			return BadRequest(RESTAPI::Errors::UnknownManagementPolicyUUID); | ||||
| 		} | ||||
|  | ||||
|         NewEntity.venues.clear(); | ||||
|         NewEntity.children.clear(); | ||||
|         NewEntity.contacts.clear(); | ||||
|         NewEntity.locations.clear(); | ||||
|         NewEntity.deviceConfiguration.clear(); | ||||
|         NewEntity.managementRoles.clear(); | ||||
| 		if (!NewEntity.sourceIP.empty() && !CIDR::ValidateIpRanges(NewEntity.sourceIP)) { | ||||
| 			return BadRequest(RESTAPI::Errors::InvalidIPRanges); | ||||
| 		} | ||||
|  | ||||
|         if(DB_.CreateRecord(NewEntity)) { | ||||
|             MoveUsage(StorageService()->PolicyDB(),DB_,"",NewEntity.managementPolicy,NewEntity.info.id); | ||||
|             DB_.AddChild("id",NewEntity.parent,NewEntity.info.id); | ||||
| 		NewEntity.venues.clear(); | ||||
| 		NewEntity.children.clear(); | ||||
| 		NewEntity.contacts.clear(); | ||||
| 		NewEntity.locations.clear(); | ||||
| 		NewEntity.deviceConfiguration.clear(); | ||||
| 		NewEntity.managementRoles.clear(); | ||||
|  | ||||
|             Poco::JSON::Object  Answer; | ||||
|             NewEntity.to_json(Answer); | ||||
|             return ReturnObject(Answer); | ||||
|         } | ||||
|         InternalError(RESTAPI::Errors::RecordNotCreated); | ||||
|     } | ||||
| 		if (DB_.CreateRecord(NewEntity)) { | ||||
| 			MoveUsage(StorageService()->PolicyDB(), DB_, "", NewEntity.managementPolicy, | ||||
| 					  NewEntity.info.id); | ||||
| 			DB_.AddChild("id", NewEntity.parent, NewEntity.info.id); | ||||
|  | ||||
|     /* | ||||
|      * Put is a complex operation, it contains commands only. | ||||
|      *      addContact=UUID, delContact=UUID, | ||||
|      *      addLocation=UUID, delLocation=UUID, | ||||
|      *      addVenue=UUID, delVenue=UUID, | ||||
|      *      addEntity=UUID, delEntity=UUID | ||||
|      *      addDevice=UUID, delDevice=UUID | ||||
|      */ | ||||
| 			Poco::JSON::Object Answer; | ||||
| 			NewEntity.to_json(Answer); | ||||
| 			return ReturnObject(Answer); | ||||
| 		} | ||||
| 		InternalError(RESTAPI::Errors::RecordNotCreated); | ||||
| 	} | ||||
|  | ||||
|     void RESTAPI_entity_handler::DoPut() { | ||||
|         std::string UUID = GetBinding("uuid", ""); | ||||
|         ProvObjects::Entity Existing; | ||||
|         if(UUID.empty() || !DB_.GetRecord("id",UUID,Existing)) { | ||||
|             return NotFound(); | ||||
|         } | ||||
| 	/* | ||||
| 	 * Put is a complex operation, it contains commands only. | ||||
| 	 *      addContact=UUID, delContact=UUID, | ||||
| 	 *      addLocation=UUID, delLocation=UUID, | ||||
| 	 *      addVenue=UUID, delVenue=UUID, | ||||
| 	 *      addEntity=UUID, delEntity=UUID | ||||
| 	 *      addDevice=UUID, delDevice=UUID | ||||
| 	 */ | ||||
|  | ||||
|         const auto & RawObject = ParsedBody_; | ||||
|         ProvObjects::Entity NewEntity; | ||||
|         if(!NewEntity.from_json(RawObject)) { | ||||
|             return BadRequest(RESTAPI::Errors::InvalidJSONDocument); | ||||
|         } | ||||
| 	void RESTAPI_entity_handler::DoPut() { | ||||
| 		std::string UUID = GetBinding("uuid", ""); | ||||
| 		ProvObjects::Entity Existing; | ||||
| 		if (UUID.empty() || !DB_.GetRecord("id", UUID, Existing)) { | ||||
| 			return NotFound(); | ||||
| 		} | ||||
|  | ||||
|         if((RawObject->has("deviceRules") && !ValidDeviceRules(NewEntity.deviceRules,*this))) { | ||||
|             return; | ||||
|         } | ||||
| 		const auto &RawObject = ParsedBody_; | ||||
| 		ProvObjects::Entity NewEntity; | ||||
| 		if (!NewEntity.from_json(RawObject)) { | ||||
| 			return BadRequest(RESTAPI::Errors::InvalidJSONDocument); | ||||
| 		} | ||||
|  | ||||
|         if(!UpdateObjectInfo(RawObject, UserInfo_.userinfo, Existing.info)) { | ||||
|             return BadRequest(RESTAPI::Errors::NameMustBeSet); | ||||
|         } | ||||
| 		if ((RawObject->has("deviceRules") && !ValidDeviceRules(NewEntity.deviceRules, *this))) { | ||||
| 			return; | ||||
| 		} | ||||
|  | ||||
|         std::string FromPolicy, ToPolicy; | ||||
|         if(!CreateMove(RawObject,"managementPolicy",&EntityDB::RecordName::managementPolicy, Existing, FromPolicy, ToPolicy, StorageService()->PolicyDB())) | ||||
|             return BadRequest(RESTAPI::Errors::UnknownManagementPolicyUUID); | ||||
| 		if (!UpdateObjectInfo(RawObject, UserInfo_.userinfo, Existing.info)) { | ||||
| 			return BadRequest(RESTAPI::Errors::NameMustBeSet); | ||||
| 		} | ||||
|  | ||||
|         if(RawObject->has("sourceIP")) { | ||||
|             if(!NewEntity.sourceIP.empty() && !CIDR::ValidateIpRanges(NewEntity.sourceIP)) { | ||||
|                 return BadRequest(RESTAPI::Errors::InvalidIPRanges); | ||||
|             } | ||||
|             Existing.sourceIP = NewEntity.sourceIP; | ||||
|         } | ||||
| 		std::string FromPolicy, ToPolicy; | ||||
| 		if (!CreateMove(RawObject, "managementPolicy", &EntityDB::RecordName::managementPolicy, | ||||
| 						Existing, FromPolicy, ToPolicy, StorageService()->PolicyDB())) | ||||
| 			return BadRequest(RESTAPI::Errors::UnknownManagementPolicyUUID); | ||||
|  | ||||
|         RESTAPI::Errors::msg    Error; | ||||
|         if(!StorageService()->Validate(Parameters_,Error)) { | ||||
|             return BadRequest(Error); | ||||
|         } | ||||
| 		if (RawObject->has("sourceIP")) { | ||||
| 			if (!NewEntity.sourceIP.empty() && !CIDR::ValidateIpRanges(NewEntity.sourceIP)) { | ||||
| 				return BadRequest(RESTAPI::Errors::InvalidIPRanges); | ||||
| 			} | ||||
| 			Existing.sourceIP = NewEntity.sourceIP; | ||||
| 		} | ||||
|  | ||||
|         if(RawObject->has("deviceRules")) | ||||
|             Existing.deviceRules = NewEntity.deviceRules; | ||||
| 		RESTAPI::Errors::msg Error; | ||||
| 		if (!StorageService()->Validate(Parameters_, Error)) { | ||||
| 			return BadRequest(Error); | ||||
| 		} | ||||
|  | ||||
|         if(DB_.UpdateRecord("id",UUID,Existing)) { | ||||
|             MoveUsage(StorageService()->PolicyDB(),DB_,FromPolicy,ToPolicy,Existing.info.id); | ||||
| 		if (RawObject->has("deviceRules")) | ||||
| 			Existing.deviceRules = NewEntity.deviceRules; | ||||
|  | ||||
|             Poco::JSON::Object  Answer; | ||||
|             ProvObjects::Entity NewRecord; | ||||
|             StorageService()->EntityDB().GetRecord("id",UUID, NewRecord); | ||||
|             NewRecord.to_json(Answer); | ||||
|             return ReturnObject(Answer); | ||||
|         } | ||||
|         InternalError(RESTAPI::Errors::RecordNotUpdated); | ||||
|     } | ||||
| } | ||||
| 		if (DB_.UpdateRecord("id", UUID, Existing)) { | ||||
| 			MoveUsage(StorageService()->PolicyDB(), DB_, FromPolicy, ToPolicy, Existing.info.id); | ||||
|  | ||||
| 			Poco::JSON::Object Answer; | ||||
| 			ProvObjects::Entity NewRecord; | ||||
| 			StorageService()->EntityDB().GetRecord("id", UUID, NewRecord); | ||||
| 			NewRecord.to_json(Answer); | ||||
| 			return ReturnObject(Answer); | ||||
| 		} | ||||
| 		InternalError(RESTAPI::Errors::RecordNotUpdated); | ||||
| 	} | ||||
| } // namespace OpenWifi | ||||
| @@ -7,31 +7,29 @@ | ||||
| // | ||||
|  | ||||
| #pragma once | ||||
|  | ||||
| #include "framework/MicroService.h" | ||||
| #include "StorageService.h" | ||||
| #include "framework/RESTAPI_Handler.h" | ||||
|  | ||||
| namespace OpenWifi { | ||||
|     class RESTAPI_entity_handler : public RESTAPIHandler { | ||||
|     public: | ||||
|         RESTAPI_entity_handler(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L, RESTAPI_GenericServer & Server, uint64_t TransactionId, bool Internal) | ||||
|         : RESTAPIHandler(bindings, L, | ||||
|                          std::vector<std::string>{ | ||||
|                                 Poco::Net::HTTPRequest::HTTP_GET, | ||||
|                                 Poco::Net::HTTPRequest::HTTP_POST, | ||||
|                                 Poco::Net::HTTPRequest::HTTP_PUT, | ||||
|                                 Poco::Net::HTTPRequest::HTTP_DELETE, | ||||
|                                 Poco::Net::HTTPRequest::HTTP_OPTIONS}, | ||||
|                                 Server, | ||||
|                                 TransactionId, | ||||
|                                 Internal){} | ||||
|         static auto PathName() { return std::list<std::string>{"/api/v1/entity/{uuid}"}; }; | ||||
| 	class RESTAPI_entity_handler : public RESTAPIHandler { | ||||
| 	  public: | ||||
| 		RESTAPI_entity_handler(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L, | ||||
| 							   RESTAPI_GenericServerAccounting &Server, uint64_t TransactionId, | ||||
| 							   bool Internal) | ||||
| 			: RESTAPIHandler(bindings, L, | ||||
| 							 std::vector<std::string>{Poco::Net::HTTPRequest::HTTP_GET, | ||||
| 													  Poco::Net::HTTPRequest::HTTP_POST, | ||||
| 													  Poco::Net::HTTPRequest::HTTP_PUT, | ||||
| 													  Poco::Net::HTTPRequest::HTTP_DELETE, | ||||
| 													  Poco::Net::HTTPRequest::HTTP_OPTIONS}, | ||||
| 							 Server, TransactionId, Internal) {} | ||||
| 		static auto PathName() { return std::list<std::string>{"/api/v1/entity/{uuid}"}; }; | ||||
|  | ||||
|     private: | ||||
|         EntityDB        & DB_=StorageService()->EntityDB(); | ||||
|         void DoGet() final; | ||||
|         void DoPost() final ; | ||||
|         void DoPut() final; | ||||
|         void DoDelete() final; | ||||
|     }; | ||||
| } | ||||
| 	  private: | ||||
| 		EntityDB &DB_ = StorageService()->EntityDB(); | ||||
| 		void DoGet() final; | ||||
| 		void DoPost() final; | ||||
| 		void DoPut() final; | ||||
| 		void DoDelete() final; | ||||
| 	}; | ||||
| } // namespace OpenWifi | ||||
|   | ||||
| @@ -6,37 +6,35 @@ | ||||
| //	Arilia Wireless Inc. | ||||
| // | ||||
|  | ||||
| #include "framework/MicroService.h" | ||||
| #include "RESTAPI_entity_list_handler.h" | ||||
| #include "StorageService.h" | ||||
| #include "RESTAPI_db_helpers.h" | ||||
| #include "StorageService.h" | ||||
|  | ||||
| namespace OpenWifi{ | ||||
| namespace OpenWifi { | ||||
|  | ||||
|     void RESTAPI_entity_list_handler::DoGet() { | ||||
|         if(!QB_.Select.empty()) { | ||||
|             return ReturnRecordList<decltype(DB_), | ||||
|             ProvObjects::Entity>("entities",DB_,*this ); | ||||
|         } else if(QB_.CountOnly) { | ||||
|             auto C = DB_.Count(); | ||||
|             return ReturnCountOnly(C); | ||||
|         } else if (GetBoolParameter("getTree",false)) { | ||||
|             Poco::JSON::Object  FullTree; | ||||
|             DB_.BuildTree(FullTree); | ||||
|             return ReturnObject(FullTree); | ||||
|         } else { | ||||
|             EntityDB::RecordVec Entities; | ||||
|             DB_.GetRecords(QB_.Offset, QB_.Limit,Entities); | ||||
|             return MakeJSONObjectArray("entities", Entities, *this); | ||||
|         } | ||||
|     } | ||||
| 	void RESTAPI_entity_list_handler::DoGet() { | ||||
| 		if (!QB_.Select.empty()) { | ||||
| 			return ReturnRecordList<decltype(DB_), ProvObjects::Entity>("entities", DB_, *this); | ||||
| 		} else if (QB_.CountOnly) { | ||||
| 			auto C = DB_.Count(); | ||||
| 			return ReturnCountOnly(C); | ||||
| 		} else if (GetBoolParameter("getTree", false)) { | ||||
| 			Poco::JSON::Object FullTree; | ||||
| 			DB_.BuildTree(FullTree); | ||||
| 			return ReturnObject(FullTree); | ||||
| 		} else { | ||||
| 			EntityDB::RecordVec Entities; | ||||
| 			DB_.GetRecords(QB_.Offset, QB_.Limit, Entities); | ||||
| 			return MakeJSONObjectArray("entities", Entities, *this); | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
|     void RESTAPI_entity_list_handler::DoPost() { | ||||
|         if (GetBoolParameter("setTree",false)) { | ||||
|             const auto & FullTree = ParsedBody_; | ||||
|             DB_.ImportTree(FullTree); | ||||
|             return OK(); | ||||
|         } | ||||
|         BadRequest(RESTAPI::Errors::MissingOrInvalidParameters); | ||||
|     } | ||||
| } | ||||
| 	void RESTAPI_entity_list_handler::DoPost() { | ||||
| 		if (GetBoolParameter("setTree", false)) { | ||||
| 			const auto &FullTree = ParsedBody_; | ||||
| 			DB_.ImportTree(FullTree); | ||||
| 			return OK(); | ||||
| 		} | ||||
| 		BadRequest(RESTAPI::Errors::MissingOrInvalidParameters); | ||||
| 	} | ||||
| } // namespace OpenWifi | ||||
| @@ -6,30 +6,28 @@ | ||||
| //	Arilia Wireless Inc. | ||||
| // | ||||
|  | ||||
|  | ||||
| #pragma once | ||||
|  | ||||
| #include "framework/MicroService.h" | ||||
| #include "StorageService.h" | ||||
| #include "framework/RESTAPI_Handler.h" | ||||
|  | ||||
| namespace OpenWifi { | ||||
|     class RESTAPI_entity_list_handler : public RESTAPIHandler { | ||||
|     public: | ||||
|         RESTAPI_entity_list_handler(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L, RESTAPI_GenericServer & Server, uint64_t TransactionId, bool Internal) | ||||
|         : RESTAPIHandler(bindings, L, | ||||
|                          std::vector<std::string>{ | ||||
|             Poco::Net::HTTPRequest::HTTP_GET, | ||||
|             Poco::Net::HTTPRequest::HTTP_POST, | ||||
|             Poco::Net::HTTPRequest::HTTP_OPTIONS}, | ||||
|             Server, | ||||
|             TransactionId, | ||||
|             Internal){} | ||||
|         static auto PathName() { return std::list<std::string>{"/api/v1/entity"}; }; | ||||
|     private: | ||||
|         EntityDB    &DB_=StorageService()->EntityDB(); | ||||
|         void DoGet() final; | ||||
|         void DoPost() final ; | ||||
|         void DoPut() final {}; | ||||
|         void DoDelete() final {}; | ||||
|     }; | ||||
| } | ||||
| 	class RESTAPI_entity_list_handler : public RESTAPIHandler { | ||||
| 	  public: | ||||
| 		RESTAPI_entity_list_handler(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L, | ||||
| 									RESTAPI_GenericServerAccounting &Server, uint64_t TransactionId, | ||||
| 									bool Internal) | ||||
| 			: RESTAPIHandler(bindings, L, | ||||
| 							 std::vector<std::string>{Poco::Net::HTTPRequest::HTTP_GET, | ||||
| 													  Poco::Net::HTTPRequest::HTTP_POST, | ||||
| 													  Poco::Net::HTTPRequest::HTTP_OPTIONS}, | ||||
| 							 Server, TransactionId, Internal) {} | ||||
| 		static auto PathName() { return std::list<std::string>{"/api/v1/entity"}; }; | ||||
|  | ||||
| 	  private: | ||||
| 		EntityDB &DB_ = StorageService()->EntityDB(); | ||||
| 		void DoGet() final; | ||||
| 		void DoPost() final; | ||||
| 		void DoPut() final{}; | ||||
| 		void DoDelete() final{}; | ||||
| 	}; | ||||
| } // namespace OpenWifi | ||||
|   | ||||
| @@ -8,422 +8,469 @@ | ||||
|  | ||||
| #include "RESTAPI_inventory_handler.h" | ||||
|  | ||||
| #include "StorageService.h" | ||||
| #include "APConfig.h" | ||||
| #include "AutoDiscovery.h" | ||||
| #include "sdks/SDK_gw.h" | ||||
| #include "sdks/SDK_sec.h" | ||||
| #include "DeviceTypeCache.h" | ||||
| #include "RESTAPI/RESTAPI_db_helpers.h" | ||||
| #include "SerialNumberCache.h" | ||||
| #include "DeviceTypeCache.h" | ||||
| #include "StorageService.h" | ||||
| #include "Tasks/VenueConfigUpdater.h" | ||||
| #include "framework/utils.h" | ||||
| #include "sdks/SDK_gw.h" | ||||
| #include "sdks/SDK_sec.h" | ||||
|  | ||||
| namespace OpenWifi{ | ||||
| namespace OpenWifi { | ||||
|  | ||||
|     void GetRejectedLines(const Poco::JSON::Object::Ptr &Response, Types::StringVec & Warnings) { | ||||
|         try { | ||||
|             if(Response->has("results")) { | ||||
|                 auto Results = Response->get("results").extract<Poco::JSON::Object::Ptr>(); | ||||
|                 auto Status = Results->get("status").extract<Poco::JSON::Object::Ptr>(); | ||||
|                 auto Rejected = Status->getArray("rejected"); | ||||
|                 std::transform(Rejected->begin(),Rejected->end(),std::back_inserter(Warnings), [](auto i) -> auto { return i.toString(); }); | ||||
| //                for(const auto &i:*Rejected) | ||||
|   //                  Warnings.push_back(i.toString()); | ||||
|             } | ||||
|         } catch (...) { | ||||
|         } | ||||
|     } | ||||
| 	void RESTAPI_inventory_handler::DoGet() { | ||||
|  | ||||
|     void RESTAPI_inventory_handler::DoGet() { | ||||
| 		ProvObjects::InventoryTag Existing; | ||||
| 		std::string SerialNumber = GetBinding(RESTAPI::Protocol::SERIALNUMBER, ""); | ||||
| 		poco_debug(Logger(), fmt::format("{}: Retrieving inventory information.", SerialNumber)); | ||||
| 		if (SerialNumber.empty() || | ||||
| 			!DB_.GetRecord(RESTAPI::Protocol::SERIALNUMBER, SerialNumber, Existing)) { | ||||
| 			return NotFound(); | ||||
| 		} | ||||
| 		poco_debug(Logger(), fmt::format("{},{}: Retrieving inventory information.", | ||||
| 										 Existing.serialNumber, Existing.info.id)); | ||||
|  | ||||
|         ProvObjects::InventoryTag Existing; | ||||
|         std::string SerialNumber = GetBinding(RESTAPI::Protocol::SERIALNUMBER, ""); | ||||
|         Logger().debug(Poco::format("%s: Retrieving inventory information.", SerialNumber)); | ||||
|         if (SerialNumber.empty() || !DB_.GetRecord(RESTAPI::Protocol::SERIALNUMBER, SerialNumber, Existing)) { | ||||
|             return NotFound(); | ||||
|         } | ||||
|         Logger().debug( | ||||
|                 Poco::format("%s,%s: Retrieving inventory information.", Existing.serialNumber, Existing.info.id)); | ||||
| 		Poco::JSON::Object Answer; | ||||
| 		std::string Arg; | ||||
| 		if (GetBoolParameter("config", false)) { | ||||
| 			bool Explain = GetBoolParameter("explain", false); | ||||
|  | ||||
|         Poco::JSON::Object Answer; | ||||
|         std::string Arg; | ||||
|         if (HasParameter("config", Arg) && Arg == "true") { | ||||
|             bool Explain = (HasParameter("explain", Arg) && Arg == "true"); | ||||
|             APConfig Device(SerialNumber, Existing.deviceType, Logger(), Explain); | ||||
| 			APConfig Device(SerialNumber, Existing.deviceType, Logger(), Explain); | ||||
|  | ||||
|             auto Configuration = Poco::makeShared<Poco::JSON::Object>(); | ||||
|             if (Device.Get(Configuration)) { | ||||
|                 Answer.set("config", Configuration); | ||||
|                 if (Explain) | ||||
|                     Answer.set("explanation", Device.Explanation()); | ||||
|             } else { | ||||
|                 Answer.set("config", "none"); | ||||
|             } | ||||
|             return ReturnObject(Answer); | ||||
|         } else if (GetBoolParameter("firmwareOptions", false)) { | ||||
|             ProvObjects::DeviceRules Rules; | ||||
|             StorageService()->InventoryDB().EvaluateDeviceSerialNumberRules(SerialNumber, Rules); | ||||
|             Answer.set("firmwareUpgrade", Rules.firmwareUpgrade); | ||||
|             Answer.set("firmwareRCOnly", Rules.rcOnly == "yes"); | ||||
|             return ReturnObject(Answer); | ||||
|         } else if(GetBoolParameter("rrmSettings",false)) { | ||||
|             ProvObjects::DeviceRules Rules; | ||||
|             StorageService()->InventoryDB().EvaluateDeviceSerialNumberRules(SerialNumber, Rules); | ||||
|             if(Rules.rrm=="no" || Rules.rrm=="inherit") { | ||||
|                 Answer.set("rrm", Rules.rrm); | ||||
|             } else { | ||||
|                 ProvObjects::RRMDetails D; | ||||
|                 Poco::JSON::Parser  P; | ||||
|                 try { | ||||
|                     auto Obj = P.parse(Rules.rrm).extract<Poco::JSON::Object::Ptr>(); | ||||
|                     Answer.set("rrm", Obj); | ||||
|                 } catch (...) { | ||||
|                     Answer.set("rrm", "invalid"); | ||||
|                 } | ||||
|             } | ||||
|             return ReturnObject(Answer); | ||||
|         } else if(GetBoolParameter("applyConfiguration", false)) { | ||||
|             Logger().debug(Poco::format("%s: Retrieving configuration.",Existing.serialNumber)); | ||||
|             auto Device = std::make_shared<APConfig>(SerialNumber, Existing.deviceType, Logger(), false); | ||||
|             auto Configuration = Poco::makeShared<Poco::JSON::Object>(); | ||||
|             Poco::JSON::Object ErrorsObj, WarningsObj; | ||||
|             ProvObjects::InventoryConfigApplyResult Results; | ||||
|             Logger().debug(Poco::format("%s: Computing configuration.",Existing.serialNumber)); | ||||
|             if (Device->Get(Configuration)) { | ||||
|                 std::ostringstream OS; | ||||
|                 Configuration->stringify(OS); | ||||
|                 Results.appliedConfiguration = OS.str(); | ||||
|                 auto Response=Poco::makeShared<Poco::JSON::Object>(); | ||||
|                 Logger().debug(Poco::format("%s: Sending configuration push.",Existing.serialNumber)); | ||||
|                 if (SDK::GW::Device::Configure(this, SerialNumber, Configuration, Response)) { | ||||
|                     Logger().debug(Poco::format("%s: Sending configuration pushed.",Existing.serialNumber)); | ||||
|                     GetRejectedLines(Response, Results.warnings); | ||||
|                     Results.errorCode = 0; | ||||
|                 } else { | ||||
|                     Logger().debug(Poco::format("%s: Sending configuration failed.",Existing.serialNumber)); | ||||
|                     Results.errorCode = 1; | ||||
|                 } | ||||
|             } else { | ||||
|                 Logger().debug(Poco::format("%s: Configuration is bad.",Existing.serialNumber)); | ||||
|                 Results.errorCode = 1; | ||||
|             } | ||||
|             Results.to_json(Answer); | ||||
|             return ReturnObject(Answer); | ||||
|         } else if(GetBoolParameter("resolveConfig", false)) { | ||||
|             Logger().debug(Poco::format("%s: Retrieving configuration.",Existing.serialNumber)); | ||||
|             auto Device = std::make_shared<APConfig>(SerialNumber, Existing.deviceType, Logger(), false); | ||||
|             auto Configuration = Poco::makeShared<Poco::JSON::Object>(); | ||||
|             Poco::JSON::Object ErrorsObj, WarningsObj; | ||||
|             ProvObjects::InventoryConfigApplyResult Results; | ||||
|             Logger().debug(Poco::format("%s: Computing configuration.",Existing.serialNumber)); | ||||
|             if (Device->Get(Configuration)) { | ||||
|                 Answer.set("configuration", Configuration); | ||||
|             } else { | ||||
|                 Answer.set("error", 1); | ||||
|             } | ||||
|             return ReturnObject(Answer); | ||||
|         }   else if(QB_.AdditionalInfo) { | ||||
|             AddExtendedInfo(Existing,Answer); | ||||
|         } | ||||
|         Existing.to_json(Answer); | ||||
|         ReturnObject(Answer); | ||||
|     } | ||||
| 			auto Configuration = Poco::makeShared<Poco::JSON::Object>(); | ||||
| 			if (Device.Get(Configuration)) { | ||||
| 				Answer.set("config", Configuration); | ||||
| 				if (Explain) | ||||
| 					Answer.set("explanation", Device.Explanation()); | ||||
| 			} else { | ||||
| 				Answer.set("config", "none"); | ||||
| 			} | ||||
| 			return ReturnObject(Answer); | ||||
| 		} else if (GetBoolParameter("firmwareOptions", false)) { | ||||
| 			ProvObjects::DeviceRules Rules; | ||||
| 			StorageService()->InventoryDB().EvaluateDeviceSerialNumberRules(SerialNumber, Rules); | ||||
| 			Answer.set("firmwareUpgrade", Rules.firmwareUpgrade); | ||||
| 			Answer.set("firmwareRCOnly", Rules.rcOnly == "yes"); | ||||
| 			return ReturnObject(Answer); | ||||
| 		} else if (GetBoolParameter("rrmSettings", false)) { | ||||
| 			ProvObjects::DeviceRules Rules; | ||||
| 			StorageService()->InventoryDB().EvaluateDeviceSerialNumberRules(SerialNumber, Rules); | ||||
| 			if (Rules.rrm == "no" || Rules.rrm == "inherit") { | ||||
| 				Answer.set("rrm", Rules.rrm); | ||||
| 			} else { | ||||
| 				ProvObjects::RRMDetails D; | ||||
| 				Poco::JSON::Parser P; | ||||
| 				try { | ||||
| 					auto Obj = P.parse(Rules.rrm).extract<Poco::JSON::Object::Ptr>(); | ||||
| 					Answer.set("rrm", Obj); | ||||
| 				} catch (...) { | ||||
| 					Answer.set("rrm", "invalid"); | ||||
| 				} | ||||
| 			} | ||||
| 			return ReturnObject(Answer); | ||||
| 		} else if (GetBoolParameter("applyConfiguration", false)) { | ||||
| 			poco_debug(Logger(), | ||||
| 					   fmt::format("{}: Retrieving configuration.", Existing.serialNumber)); | ||||
| 			auto Device = | ||||
| 				std::make_shared<APConfig>(SerialNumber, Existing.deviceType, Logger(), false); | ||||
| 			auto Configuration = Poco::makeShared<Poco::JSON::Object>(); | ||||
| 			Poco::JSON::Object ErrorsObj, WarningsObj; | ||||
| 			ProvObjects::InventoryConfigApplyResult Results; | ||||
| 			poco_debug(Logger(), | ||||
| 					   fmt::format("{}: Computing configuration.", Existing.serialNumber)); | ||||
| 			if (Device->Get(Configuration)) { | ||||
| 				std::ostringstream OS; | ||||
| 				Configuration->stringify(OS); | ||||
| 				Results.appliedConfiguration = OS.str(); | ||||
| 				auto Response = Poco::makeShared<Poco::JSON::Object>(); | ||||
| 				poco_debug(Logger(), | ||||
| 						   fmt::format("{}: Sending configuration push.", Existing.serialNumber)); | ||||
| 				if (SDK::GW::Device::Configure(this, SerialNumber, Configuration, Response)) { | ||||
| 					poco_debug(Logger(), fmt::format("{}: Sending configuration pushed.", | ||||
| 													 Existing.serialNumber)); | ||||
| 					GetRejectedLines(Response, Results.warnings); | ||||
| 					Results.errorCode = 0; | ||||
| 				} else { | ||||
| 					poco_debug(Logger(), fmt::format("{}: Sending configuration failed.", | ||||
| 													 Existing.serialNumber)); | ||||
| 					Results.errorCode = 1; | ||||
| 				} | ||||
| 			} else { | ||||
| 				poco_debug(Logger(), | ||||
| 						   fmt::format("{}: Configuration is bad.", Existing.serialNumber)); | ||||
| 				Results.errorCode = 1; | ||||
| 			} | ||||
| 			Results.to_json(Answer); | ||||
| 			return ReturnObject(Answer); | ||||
| 		} else if (GetBoolParameter("resolveConfig", false)) { | ||||
| 			poco_debug(Logger(), | ||||
| 					   fmt::format("{}: Retrieving configuration.", Existing.serialNumber)); | ||||
| 			auto Device = | ||||
| 				std::make_shared<APConfig>(SerialNumber, Existing.deviceType, Logger(), false); | ||||
| 			auto Configuration = Poco::makeShared<Poco::JSON::Object>(); | ||||
| 			Poco::JSON::Object ErrorsObj, WarningsObj; | ||||
| 			ProvObjects::InventoryConfigApplyResult Results; | ||||
| 			poco_debug(Logger(), | ||||
| 					   Poco::format("{}: Computing configuration.", Existing.serialNumber)); | ||||
| 			if (Device->Get(Configuration)) { | ||||
| 				Answer.set("configuration", Configuration); | ||||
| 			} else { | ||||
| 				Answer.set("error", 1); | ||||
| 			} | ||||
| 			return ReturnObject(Answer); | ||||
| 		} else if (QB_.AdditionalInfo) { | ||||
| 			AddExtendedInfo(Existing, Answer); | ||||
| 		} | ||||
| 		Existing.to_json(Answer); | ||||
| 		ReturnObject(Answer); | ||||
| 	} | ||||
|  | ||||
|     void RESTAPI_inventory_handler::DoDelete() { | ||||
|         ProvObjects::InventoryTag   Existing; | ||||
|         std::string SerialNumber = GetBinding(RESTAPI::Protocol::SERIALNUMBER,""); | ||||
|         if(SerialNumber.empty() || !DB_.GetRecord(RESTAPI::Protocol::SERIALNUMBER,SerialNumber,Existing)) { | ||||
|             return NotFound(); | ||||
|         } | ||||
| 	void RESTAPI_inventory_handler::DoDelete() { | ||||
| 		ProvObjects::InventoryTag Existing; | ||||
| 		std::string SerialNumber = GetBinding(RESTAPI::Protocol::SERIALNUMBER, ""); | ||||
| 		if (SerialNumber.empty() || | ||||
| 			!DB_.GetRecord(RESTAPI::Protocol::SERIALNUMBER, SerialNumber, Existing)) { | ||||
| 			return NotFound(); | ||||
| 		} | ||||
|  | ||||
|         MoveUsage(StorageService()->PolicyDB(),DB_,Existing.managementPolicy,"",Existing.info.id); | ||||
|         RemoveMembership(StorageService()->VenueDB(),&ProvObjects::Venue::configurations,Existing.venue,Existing.info.id); | ||||
|         RemoveMembership(StorageService()->EntityDB(),&ProvObjects::Entity::configurations,Existing.entity,Existing.info.id); | ||||
|         MoveUsage(StorageService()->LocationDB(),DB_,Existing.location,"",Existing.info.id); | ||||
|         MoveUsage(StorageService()->ContactDB(),DB_,Existing.contact,"",Existing.info.id); | ||||
| 		MoveUsage(StorageService()->PolicyDB(), DB_, Existing.managementPolicy, "", | ||||
| 				  Existing.info.id); | ||||
| 		RemoveMembership(StorageService()->VenueDB(), &ProvObjects::Venue::configurations, | ||||
| 						 Existing.venue, Existing.info.id); | ||||
| 		RemoveMembership(StorageService()->EntityDB(), &ProvObjects::Entity::configurations, | ||||
| 						 Existing.entity, Existing.info.id); | ||||
| 		MoveUsage(StorageService()->LocationDB(), DB_, Existing.location, "", Existing.info.id); | ||||
| 		MoveUsage(StorageService()->ContactDB(), DB_, Existing.contact, "", Existing.info.id); | ||||
|  | ||||
|         if(!Existing.deviceConfiguration.empty()) { | ||||
|             ProvObjects::DeviceConfiguration    DC; | ||||
|             if(StorageService()->ConfigurationDB().GetRecord("id", Existing.deviceConfiguration, DC)) { | ||||
|                 if(DC.subscriberOnly) | ||||
|                     StorageService()->ConfigurationDB().DeleteRecord("id", Existing.deviceConfiguration); | ||||
|                 else | ||||
|                     StorageService()->ConfigurationDB().DeleteInUse("id", Existing.deviceConfiguration, DB_.Prefix(), | ||||
|                                                                     Existing.info.id); | ||||
|             } | ||||
|         } | ||||
| 		if (!Existing.deviceConfiguration.empty()) { | ||||
| 			ProvObjects::DeviceConfiguration DC; | ||||
| 			if (StorageService()->ConfigurationDB().GetRecord("id", Existing.deviceConfiguration, | ||||
| 															  DC)) { | ||||
| 				if (DC.subscriberOnly) | ||||
| 					StorageService()->ConfigurationDB().DeleteRecord("id", | ||||
| 																	 Existing.deviceConfiguration); | ||||
| 				else | ||||
| 					StorageService()->ConfigurationDB().DeleteInUse( | ||||
| 						"id", Existing.deviceConfiguration, DB_.Prefix(), Existing.info.id); | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
|         MoveUsage(StorageService()->PolicyDB(),DB_,Existing.managementPolicy,"",Existing.info.id); | ||||
|         MoveUsage(StorageService()->LocationDB(),DB_,Existing.location,"",Existing.info.id); | ||||
|         MoveUsage(StorageService()->ContactDB(),DB_,Existing.contact,"",Existing.info.id); | ||||
|         MoveUsage(StorageService()->ConfigurationDB(),DB_,Existing.deviceConfiguration,"",Existing.info.id); | ||||
|         ManageMembership(StorageService()->EntityDB(),&ProvObjects::Entity::devices,Existing.entity,"",Existing.info.id); | ||||
|         ManageMembership(StorageService()->VenueDB(),&ProvObjects::Venue::devices,Existing.venue,"",Existing.info.id); | ||||
|         DB_.DeleteRecord("id", Existing.info.id); | ||||
|         SerialNumberCache()->DeleteSerialNumber(SerialNumber); | ||||
|         return OK(); | ||||
|     } | ||||
| 		MoveUsage(StorageService()->PolicyDB(), DB_, Existing.managementPolicy, "", | ||||
| 				  Existing.info.id); | ||||
| 		MoveUsage(StorageService()->LocationDB(), DB_, Existing.location, "", Existing.info.id); | ||||
| 		MoveUsage(StorageService()->ContactDB(), DB_, Existing.contact, "", Existing.info.id); | ||||
| 		MoveUsage(StorageService()->ConfigurationDB(), DB_, Existing.deviceConfiguration, "", | ||||
| 				  Existing.info.id); | ||||
| 		ManageMembership(StorageService()->EntityDB(), &ProvObjects::Entity::devices, | ||||
| 						 Existing.entity, "", Existing.info.id); | ||||
| 		ManageMembership(StorageService()->VenueDB(), &ProvObjects::Venue::devices, Existing.venue, | ||||
| 						 "", Existing.info.id); | ||||
| 		DB_.DeleteRecord("id", Existing.info.id); | ||||
| 		SerialNumberCache()->DeleteSerialNumber(SerialNumber); | ||||
| 		return OK(); | ||||
| 	} | ||||
|  | ||||
| 	void RESTAPI_inventory_handler::DoPost() { | ||||
| 		std::string SerialNumber = GetBinding(RESTAPI::Protocol::SERIALNUMBER, ""); | ||||
| 		Poco::toLowerInPlace(SerialNumber); | ||||
| 		if (SerialNumber.empty()) { | ||||
| 			return BadRequest(RESTAPI::Errors::MissingSerialNumber); | ||||
| 		} | ||||
|  | ||||
|     void RESTAPI_inventory_handler::DoPost() { | ||||
|         std::string SerialNumber = GetBinding(RESTAPI::Protocol::SERIALNUMBER,""); | ||||
|         Poco::toLowerInPlace(SerialNumber); | ||||
|         if(SerialNumber.empty()) { | ||||
|             return BadRequest(RESTAPI::Errors::MissingSerialNumber); | ||||
|         } | ||||
| 		if (!NormalizeMac(SerialNumber)) { | ||||
| 			return BadRequest(RESTAPI::Errors::InvalidSerialNumber); | ||||
| 		} | ||||
|  | ||||
|         if(!NormalizeMac(SerialNumber)) { | ||||
|             return BadRequest(RESTAPI::Errors::InvalidSerialNumber); | ||||
|         } | ||||
| 		if (DB_.Exists(RESTAPI::Protocol::SERIALNUMBER, SerialNumber)) { | ||||
| 			return BadRequest(RESTAPI::Errors::SerialNumberExists); | ||||
| 		} | ||||
|  | ||||
|         if(DB_.Exists(RESTAPI::Protocol::SERIALNUMBER,SerialNumber)) { | ||||
|             return BadRequest(RESTAPI::Errors::SerialNumberExists); | ||||
|         } | ||||
| 		const auto &RawObject = ParsedBody_; | ||||
| 		ProvObjects::InventoryTag NewObject; | ||||
| 		if (!NewObject.from_json(RawObject)) { | ||||
| 			return BadRequest(RESTAPI::Errors::InvalidJSONDocument); | ||||
| 		} | ||||
|  | ||||
|         const auto & RawObject = ParsedBody_; | ||||
|         ProvObjects::InventoryTag NewObject; | ||||
|         if (!NewObject.from_json(RawObject)) { | ||||
|             return BadRequest(RESTAPI::Errors::InvalidJSONDocument); | ||||
|         } | ||||
| 		NormalizeMac(NewObject.serialNumber); | ||||
| 		if (SerialNumber != NewObject.serialNumber) { | ||||
| 			return BadRequest(RESTAPI::Errors::SerialNumberMismatch); | ||||
| 		} | ||||
|  | ||||
|         NormalizeMac(NewObject.serialNumber); | ||||
|         if(SerialNumber!=NewObject.serialNumber) { | ||||
|             return BadRequest(RESTAPI::Errors::SerialNumberMismatch); | ||||
|         } | ||||
| 		if ((RawObject->has("deviceRules") && !ValidDeviceRules(NewObject.deviceRules, *this))) { | ||||
| 			return; | ||||
| 		} | ||||
|  | ||||
|         if((RawObject->has("deviceRules") && !ValidDeviceRules(NewObject.deviceRules,*this))) { | ||||
|             return; | ||||
|         } | ||||
| 		if (!Provisioning::DeviceClass::Validate(NewObject.devClass.c_str())) { | ||||
| 			return BadRequest(RESTAPI::Errors::InvalidDeviceClass); | ||||
| 		} | ||||
|  | ||||
|         if(!Provisioning::DeviceClass::Validate(NewObject.devClass.c_str())) { | ||||
|             return BadRequest(RESTAPI::Errors::InvalidDeviceClass); | ||||
|         } | ||||
| 		if (NewObject.devClass.empty()) { | ||||
| 			NewObject.devClass = Provisioning::DeviceClass::ANY; | ||||
| 		} | ||||
|  | ||||
|         if(NewObject.devClass.empty()) { | ||||
|             NewObject.devClass = Provisioning::DeviceClass::ANY; | ||||
|         } | ||||
| 		if (!ProvObjects::CreateObjectInfo(RawObject, UserInfo_.userinfo, NewObject.info)) { | ||||
| 			return BadRequest(RESTAPI::Errors::NameMustBeSet); | ||||
| 		} | ||||
|  | ||||
|         if(!ProvObjects::CreateObjectInfo(RawObject, UserInfo_.userinfo, NewObject.info)) { | ||||
|             return BadRequest( RESTAPI::Errors::NameMustBeSet); | ||||
|         } | ||||
| 		if (NewObject.deviceType.empty() || | ||||
| 			!DeviceTypeCache()->IsAcceptableDeviceType(NewObject.deviceType)) { | ||||
| 			return BadRequest(RESTAPI::Errors::InvalidDeviceTypes); | ||||
| 		} | ||||
|  | ||||
|         if(NewObject.deviceType.empty() || !DeviceTypeCache()->IsAcceptableDeviceType(NewObject.deviceType)) { | ||||
|             return BadRequest(RESTAPI::Errors::InvalidDeviceTypes); | ||||
|         } | ||||
| 		if (OpenWifi::EntityDB::IsRoot(NewObject.entity) || | ||||
| 			(!NewObject.entity.empty() && | ||||
| 			 !StorageService()->EntityDB().Exists("id", NewObject.entity))) { | ||||
| 			return BadRequest(RESTAPI::Errors::ValidNonRootUUID); | ||||
| 		} | ||||
|  | ||||
|         if(OpenWifi::EntityDB::IsRoot(NewObject.entity) || (!NewObject.entity.empty() && !StorageService()->EntityDB().Exists("id",NewObject.entity))) { | ||||
|             return BadRequest(RESTAPI::Errors::ValidNonRootUUID); | ||||
|         } | ||||
| 		if (!NewObject.venue.empty() && | ||||
| 			!StorageService()->VenueDB().Exists("id", NewObject.venue)) { | ||||
| 			return BadRequest(RESTAPI::Errors::VenueMustExist); | ||||
| 		} | ||||
|  | ||||
|         if(!NewObject.venue.empty() && !StorageService()->VenueDB().Exists("id",NewObject.venue)) { | ||||
|             return BadRequest(RESTAPI::Errors::VenueMustExist); | ||||
|         } | ||||
| 		if (!NewObject.venue.empty() && !NewObject.entity.empty()) { | ||||
| 			return BadRequest(RESTAPI::Errors::NotBoth); | ||||
| 		} | ||||
|  | ||||
|         if(!NewObject.venue.empty() && !NewObject.entity.empty()) { | ||||
|             return BadRequest(RESTAPI::Errors::NotBoth); | ||||
|         } | ||||
| 		if (!NewObject.location.empty() && | ||||
| 			!StorageService()->LocationDB().Exists("id", NewObject.location)) { | ||||
| 			return BadRequest(RESTAPI::Errors::LocationMustExist); | ||||
| 		} | ||||
|  | ||||
|         if(!NewObject.location.empty() && !StorageService()->LocationDB().Exists("id",NewObject.location)) { | ||||
|             return BadRequest(RESTAPI::Errors::LocationMustExist); | ||||
|         } | ||||
| 		if (!NewObject.contact.empty() && | ||||
| 			!StorageService()->ContactDB().Exists("id", NewObject.contact)) { | ||||
| 			return BadRequest(RESTAPI::Errors::ContactMustExist); | ||||
| 		} | ||||
|  | ||||
|         if(!NewObject.contact.empty() && !StorageService()->ContactDB().Exists("id",NewObject.contact)) { | ||||
|             return BadRequest(RESTAPI::Errors::ContactMustExist); | ||||
|         } | ||||
| 		if (!NewObject.deviceConfiguration.empty() && | ||||
| 			!StorageService()->ConfigurationDB().Exists("id", NewObject.deviceConfiguration)) { | ||||
| 			return BadRequest(RESTAPI::Errors::ConfigurationMustExist); | ||||
| 		} | ||||
|  | ||||
|         if(!NewObject.deviceConfiguration.empty() && !StorageService()->ConfigurationDB().Exists("id",NewObject.deviceConfiguration)) { | ||||
|             return BadRequest(RESTAPI::Errors::ConfigurationMustExist); | ||||
|         } | ||||
| 		if (!NewObject.managementPolicy.empty() && | ||||
| 			!StorageService()->PolicyDB().Exists("id", NewObject.managementPolicy)) { | ||||
| 			return BadRequest(RESTAPI::Errors::UnknownManagementPolicyUUID); | ||||
| 		} | ||||
|  | ||||
|         if(!NewObject.managementPolicy.empty() && !StorageService()->PolicyDB().Exists("id",NewObject.managementPolicy)) { | ||||
|             return BadRequest(RESTAPI::Errors::UnknownManagementPolicyUUID); | ||||
|         } | ||||
| 		std::vector<std::string> Errors; | ||||
| 		auto ObjectsCreated = CreateObjects(NewObject, *this, Errors); | ||||
| 		if (!Errors.empty()) { | ||||
| 			return BadRequest(RESTAPI::Errors::ConfigBlockInvalid); | ||||
| 		} | ||||
|  | ||||
|         RESTAPI::Errors::msg Error=RESTAPI::Errors::SUCCESS; | ||||
|         auto ObjectsCreated = CreateObjects(NewObject,*this,Error); | ||||
|         if(Error.err_num != 0) { | ||||
|             return BadRequest(Error); | ||||
|         } | ||||
| 		if (DB_.CreateRecord(NewObject)) { | ||||
| 			SDK::GW::Device::SetOwnerShip(this, SerialNumber, NewObject.entity, NewObject.venue, | ||||
| 										  NewObject.subscriber); | ||||
| 			SerialNumberCache()->AddSerialNumber(SerialNumber, NewObject.deviceType); | ||||
| 			MoveUsage(StorageService()->PolicyDB(), DB_, "", NewObject.managementPolicy, | ||||
| 					  NewObject.info.id); | ||||
| 			MoveUsage(StorageService()->LocationDB(), DB_, "", NewObject.location, | ||||
| 					  NewObject.info.id); | ||||
| 			MoveUsage(StorageService()->ContactDB(), DB_, "", NewObject.contact, NewObject.info.id); | ||||
| 			MoveUsage(StorageService()->ConfigurationDB(), DB_, "", NewObject.deviceConfiguration, | ||||
| 					  NewObject.info.id); | ||||
| 			ManageMembership(StorageService()->EntityDB(), &ProvObjects::Entity::devices, "", | ||||
| 							 NewObject.entity, NewObject.info.id); | ||||
| 			ManageMembership(StorageService()->VenueDB(), &ProvObjects::Venue::devices, "", | ||||
| 							 NewObject.venue, NewObject.info.id); | ||||
|  | ||||
|         if(DB_.CreateRecord(NewObject)) { | ||||
|             SDK::GW::Device::SetOwnerShip(this, SerialNumber, NewObject.entity, NewObject.venue, NewObject.subscriber); | ||||
|             SerialNumberCache()->AddSerialNumber(SerialNumber,NewObject.deviceType); | ||||
|             MoveUsage(StorageService()->PolicyDB(),DB_,"",NewObject.managementPolicy,NewObject.info.id); | ||||
|             MoveUsage(StorageService()->LocationDB(),DB_,"",NewObject.location,NewObject.info.id); | ||||
|             MoveUsage(StorageService()->ContactDB(),DB_,"",NewObject.contact,NewObject.info.id); | ||||
|             MoveUsage(StorageService()->ConfigurationDB(),DB_,"",NewObject.deviceConfiguration,NewObject.info.id); | ||||
|             ManageMembership(StorageService()->EntityDB(),&ProvObjects::Entity::devices,"",NewObject.entity,NewObject.info.id); | ||||
|             ManageMembership(StorageService()->VenueDB(),&ProvObjects::Venue::devices,"",NewObject.venue,NewObject.info.id); | ||||
| 			ProvObjects::InventoryTag NewTag; | ||||
| 			DB_.GetRecord("id", NewObject.info.id, NewTag); | ||||
| 			Poco::JSON::Object Answer; | ||||
| 			NewTag.to_json(Answer); | ||||
| 			return ReturnObject(Answer); | ||||
| 		} | ||||
| 		InternalError(RESTAPI::Errors::RecordNotCreated); | ||||
| 	} | ||||
|  | ||||
|             ProvObjects::InventoryTag   NewTag; | ||||
|             DB_.GetRecord("id",NewObject.info.id,NewTag); | ||||
|             Poco::JSON::Object Answer; | ||||
|             NewTag.to_json(Answer); | ||||
|             return ReturnObject(Answer); | ||||
|         } | ||||
|         InternalError(RESTAPI::Errors::RecordNotCreated); | ||||
|     } | ||||
| 	void RESTAPI_inventory_handler::DoPut() { | ||||
|  | ||||
|     void RESTAPI_inventory_handler::DoPut() { | ||||
| 		std::string SerialNumber = GetBinding(RESTAPI::Protocol::SERIALNUMBER, ""); | ||||
| 		if (SerialNumber.empty() || !Utils::ValidSerialNumber(SerialNumber)) { | ||||
| 			return BadRequest(RESTAPI::Errors::MissingOrInvalidParameters); | ||||
| 		} | ||||
|  | ||||
|         std::string SerialNumber = GetBinding(RESTAPI::Protocol::SERIALNUMBER,""); | ||||
|         if(SerialNumber.empty() || !Utils::ValidSerialNumber(SerialNumber)) { | ||||
|             return BadRequest(RESTAPI::Errors::MissingOrInvalidParameters); | ||||
|         } | ||||
| 		ProvObjects::InventoryTag Existing; | ||||
| 		if (SerialNumber.empty() || | ||||
| 			!DB_.GetRecord(RESTAPI::Protocol::SERIALNUMBER, SerialNumber, Existing)) { | ||||
| 			return NotFound(); | ||||
| 		} | ||||
|  | ||||
|         ProvObjects::InventoryTag   Existing; | ||||
|         if(SerialNumber.empty() || !DB_.GetRecord(RESTAPI::Protocol::SERIALNUMBER,SerialNumber,Existing)) { | ||||
|             return NotFound(); | ||||
|         } | ||||
| 		std::string previous_venue = Existing.venue; | ||||
|  | ||||
|         auto RemoveSubscriber = GetParameter("removeSubscriber"); | ||||
|         if(!RemoveSubscriber.empty()) { | ||||
|             if(Existing.subscriber == RemoveSubscriber) { | ||||
|                 Logger().information(Poco::format("%s: removing subscriber (%s)", SerialNumber, RemoveSubscriber)); | ||||
|                 ProvObjects::DeviceConfiguration    DC; | ||||
|                 if(StorageService()->ConfigurationDB().GetRecord("id",Existing.deviceConfiguration,DC)) { | ||||
|                     Logger().information(Poco::format("%s: removing configuration for subscriber (%s)", SerialNumber, RemoveSubscriber)); | ||||
|                     if(DC.subscriberOnly) { | ||||
|                         if(!StorageService()->ConfigurationDB().DeleteRecord("id", Existing.deviceConfiguration)) { | ||||
|                             Logger().debug("Could not delete the subscriber configuration"); | ||||
|                         } | ||||
|                     } | ||||
|                     else { | ||||
|                         Logger().debug("Configurations is not for a subscriber."); | ||||
|                     } | ||||
|                     Existing.deviceConfiguration = ""; | ||||
|                 } | ||||
|                 Existing.subscriber = ""; | ||||
|                 Poco::JSON::Object state; | ||||
|                 state.set("date",OpenWifi::Now()); | ||||
|                 state.set("method","auto-discovery"); | ||||
|                 state.set("last-operation", "returned to inventory"); | ||||
|                 std::ostringstream OO; | ||||
|                 state.stringify(OO); | ||||
|                 Existing.state = OO.str(); | ||||
|                 StorageService()->InventoryDB().UpdateRecord("id",Existing.info.id,Existing); | ||||
|                 RemoveMembership(StorageService()->EntityDB(),&ProvObjects::Entity::devices,"id",Existing.info.id); | ||||
|                 Poco::JSON::Object  Answer; | ||||
|                 Existing.to_json(Answer); | ||||
|                 SDK::GW::Device::SetSubscriber(nullptr, SerialNumber, ""); | ||||
|                 return ReturnObject(Answer); | ||||
|             } else { | ||||
|                 Logger().information(Poco::format("%s: wrong subscriber (%s)", SerialNumber, RemoveSubscriber)); | ||||
|             } | ||||
|             return BadRequest(RESTAPI::Errors::MissingOrInvalidParameters); | ||||
|         } | ||||
| 		auto RemoveSubscriber = GetParameter("removeSubscriber"); | ||||
| 		if (!RemoveSubscriber.empty()) { | ||||
| 			if (Existing.subscriber == RemoveSubscriber) { | ||||
| 				poco_information(Logger(), fmt::format("{}: removing subscriber ({})", SerialNumber, | ||||
| 													   RemoveSubscriber)); | ||||
| 				ProvObjects::DeviceConfiguration DC; | ||||
| 				if (StorageService()->ConfigurationDB().GetRecord( | ||||
| 						"id", Existing.deviceConfiguration, DC)) { | ||||
| 					poco_information(Logger(), | ||||
| 									 fmt::format("{}: removing configuration for subscriber ({})", | ||||
| 												 SerialNumber, RemoveSubscriber)); | ||||
| 					if (DC.subscriberOnly) { | ||||
| 						if (!StorageService()->ConfigurationDB().DeleteRecord( | ||||
| 								"id", Existing.deviceConfiguration)) { | ||||
| 							poco_debug(Logger(), "Could not delete the subscriber configuration"); | ||||
| 						} | ||||
| 					} else { | ||||
| 						poco_debug(Logger(), "Configurations is not for a subscriber."); | ||||
| 					} | ||||
| 					Existing.deviceConfiguration = ""; | ||||
| 				} | ||||
| 				Existing.subscriber = ""; | ||||
| 				Poco::JSON::Object state; | ||||
| 				state.set("date", Utils::Now()); | ||||
| 				state.set("method", "auto-discovery"); | ||||
| 				state.set("last-operation", "returned to inventory"); | ||||
| 				std::ostringstream OO; | ||||
| 				state.stringify(OO); | ||||
| 				Existing.state = OO.str(); | ||||
| 				StorageService()->InventoryDB().UpdateRecord("id", Existing.info.id, Existing); | ||||
| 				RemoveMembership(StorageService()->EntityDB(), &ProvObjects::Entity::devices, "id", | ||||
| 								 Existing.info.id); | ||||
| 				Poco::JSON::Object Answer; | ||||
| 				Existing.to_json(Answer); | ||||
| 				SDK::GW::Device::SetSubscriber(nullptr, SerialNumber, ""); | ||||
| 				return ReturnObject(Answer); | ||||
| 			} else { | ||||
| 				poco_information(Logger(), fmt::format("{}: wrong subscriber ({})", SerialNumber, | ||||
| 													   RemoveSubscriber)); | ||||
| 			} | ||||
| 			return BadRequest(RESTAPI::Errors::MissingOrInvalidParameters); | ||||
| 		} | ||||
|  | ||||
|         const auto & RawObject = ParsedBody_; | ||||
|         ProvObjects::InventoryTag   NewObject; | ||||
|         if(!NewObject.from_json(RawObject)) { | ||||
|             return BadRequest(RESTAPI::Errors::InvalidJSONDocument); | ||||
|         } | ||||
| 		const auto &RawObject = ParsedBody_; | ||||
| 		ProvObjects::InventoryTag NewObject; | ||||
| 		if (!NewObject.from_json(RawObject)) { | ||||
| 			return BadRequest(RESTAPI::Errors::InvalidJSONDocument); | ||||
| 		} | ||||
|  | ||||
|         if((RawObject->has("deviceRules") && !ValidDeviceRules(NewObject.deviceRules,*this))) { | ||||
|             return; | ||||
|         } | ||||
| 		if ((RawObject->has("deviceRules") && !ValidDeviceRules(NewObject.deviceRules, *this))) { | ||||
| 			return; | ||||
| 		} | ||||
|  | ||||
|         if(!Provisioning::DeviceClass::Validate(NewObject.devClass.c_str())) { | ||||
|             return BadRequest(RESTAPI::Errors::InvalidDeviceClass); | ||||
|         } | ||||
| 		if (!Provisioning::DeviceClass::Validate(NewObject.devClass.c_str())) { | ||||
| 			return BadRequest(RESTAPI::Errors::InvalidDeviceClass); | ||||
| 		} | ||||
|  | ||||
|         if(!NewObject.deviceType.empty()) { | ||||
|             if(!DeviceTypeCache()->IsAcceptableDeviceType(NewObject.deviceType)) { | ||||
|                 return BadRequest(RESTAPI::Errors::InvalidDeviceTypes); | ||||
|             } | ||||
|         } | ||||
| 		if (!NewObject.deviceType.empty()) { | ||||
| 			if (!DeviceTypeCache()->IsAcceptableDeviceType(NewObject.deviceType)) { | ||||
| 				return BadRequest(RESTAPI::Errors::InvalidDeviceTypes); | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
|         if(!UpdateObjectInfo(RawObject, UserInfo_.userinfo, Existing.info)) { | ||||
|             return BadRequest(RESTAPI::Errors::NameMustBeSet); | ||||
|         } | ||||
| 		if (!UpdateObjectInfo(RawObject, UserInfo_.userinfo, Existing.info)) { | ||||
| 			return BadRequest(RESTAPI::Errors::NameMustBeSet); | ||||
| 		} | ||||
|  | ||||
|         if(RawObject->has("deviceRules")) | ||||
|             Existing.deviceRules = NewObject.deviceRules; | ||||
| 		if (RawObject->has("deviceRules")) | ||||
| 			Existing.deviceRules = NewObject.deviceRules; | ||||
|  | ||||
|         std::string FromPolicy, ToPolicy; | ||||
|         if(!CreateMove(RawObject,"managementPolicy",&InventoryDB::RecordName::managementPolicy, Existing, FromPolicy, | ||||
|                        ToPolicy, StorageService()->PolicyDB())) | ||||
|             return BadRequest(RESTAPI::Errors::EntityMustExist); | ||||
| 		std::string FromPolicy, ToPolicy; | ||||
| 		if (!CreateMove(RawObject, "managementPolicy", &InventoryDB::RecordName::managementPolicy, | ||||
| 						Existing, FromPolicy, ToPolicy, StorageService()->PolicyDB())) | ||||
| 			return BadRequest(RESTAPI::Errors::EntityMustExist); | ||||
|  | ||||
|         std::string FromEntity, ToEntity; | ||||
|         if(!CreateMove(RawObject,"entity",&InventoryDB::RecordName::entity, Existing, FromEntity, ToEntity, | ||||
|                        StorageService()->EntityDB())) | ||||
|             return BadRequest(RESTAPI::Errors::EntityMustExist); | ||||
| 		std::string FromEntity, ToEntity; | ||||
| 		if (!CreateMove(RawObject, "entity", &InventoryDB::RecordName::entity, Existing, FromEntity, | ||||
| 						ToEntity, StorageService()->EntityDB())) | ||||
| 			return BadRequest(RESTAPI::Errors::EntityMustExist); | ||||
|  | ||||
|         std::string FromVenue, ToVenue; | ||||
|         if(!CreateMove(RawObject,"venue",&InventoryDB::RecordName::venue, Existing, FromVenue, ToVenue, | ||||
|                        StorageService()->VenueDB())) | ||||
|             return BadRequest(RESTAPI::Errors::VenueMustExist); | ||||
| 		std::string FromVenue, ToVenue; | ||||
| 		if (!CreateMove(RawObject, "venue", &InventoryDB::RecordName::venue, Existing, FromVenue, | ||||
| 						ToVenue, StorageService()->VenueDB())) | ||||
| 			return BadRequest(RESTAPI::Errors::VenueMustExist); | ||||
|  | ||||
|         std::string FromLocation, ToLocation; | ||||
|         if(!CreateMove(RawObject,"location",&InventoryDB::RecordName::location, Existing, FromLocation, ToLocation, | ||||
|                        StorageService()->LocationDB())) | ||||
|             return BadRequest(RESTAPI::Errors::VenueMustExist); | ||||
| 		std::string FromLocation, ToLocation; | ||||
| 		if (!CreateMove(RawObject, "location", &InventoryDB::RecordName::location, Existing, | ||||
| 						FromLocation, ToLocation, StorageService()->LocationDB())) | ||||
| 			return BadRequest(RESTAPI::Errors::VenueMustExist); | ||||
|  | ||||
|         std::string FromContact, ToContact; | ||||
|         if(!CreateMove(RawObject,"contact",&InventoryDB::RecordName::contact, Existing, FromContact, ToContact, | ||||
|                        StorageService()->ContactDB())) | ||||
|             return BadRequest(RESTAPI::Errors::VenueMustExist); | ||||
| 		std::string FromContact, ToContact; | ||||
| 		if (!CreateMove(RawObject, "contact", &InventoryDB::RecordName::contact, Existing, | ||||
| 						FromContact, ToContact, StorageService()->ContactDB())) | ||||
| 			return BadRequest(RESTAPI::Errors::VenueMustExist); | ||||
|  | ||||
|         std::string FromConfiguration, ToConfiguration; | ||||
|         if(!CreateMove(RawObject,"deviceConfiguration",&InventoryDB::RecordName::deviceConfiguration, Existing, | ||||
|                        FromConfiguration, ToConfiguration, StorageService()->ConfigurationDB())) | ||||
|             return BadRequest(RESTAPI::Errors::ConfigurationMustExist); | ||||
| 		std::string FromConfiguration, ToConfiguration; | ||||
| 		if (!CreateMove(RawObject, "deviceConfiguration", | ||||
| 						&InventoryDB::RecordName::deviceConfiguration, Existing, FromConfiguration, | ||||
| 						ToConfiguration, StorageService()->ConfigurationDB())) | ||||
| 			return BadRequest(RESTAPI::Errors::ConfigurationMustExist); | ||||
|  | ||||
|         std::string NewSubScriber; | ||||
|         if(AssignIfPresent(RawObject, "subscriber", NewSubScriber)) { | ||||
|             if(!NewSubScriber.empty()) { | ||||
|                 if(NewSubScriber!=Existing.subscriber) { | ||||
|                     SecurityObjects::UserInfo   U; | ||||
|                     if(SDK::Sec::Subscriber::Get(this, NewSubScriber, U)) { | ||||
|                         Existing.subscriber = NewSubScriber; | ||||
|                     } else { | ||||
|                         return BadRequest(RESTAPI::Errors::SubscriberMustExist); | ||||
|                     } | ||||
|                 } | ||||
|             } else { | ||||
|                 Existing.subscriber = ""; | ||||
|             } | ||||
|         } | ||||
| 		std::string NewSubScriber; | ||||
| 		if (AssignIfPresent(RawObject, "subscriber", NewSubScriber)) { | ||||
| 			if (!NewSubScriber.empty()) { | ||||
| 				if (NewSubScriber != Existing.subscriber) { | ||||
| 					SecurityObjects::UserInfo U; | ||||
| 					if (SDK::Sec::Subscriber::Get(this, NewSubScriber, U)) { | ||||
| 						Existing.subscriber = NewSubScriber; | ||||
| 					} else { | ||||
| 						return BadRequest(RESTAPI::Errors::SubscriberMustExist); | ||||
| 					} | ||||
| 				} | ||||
| 			} else { | ||||
| 				Existing.subscriber = ""; | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
|         if( RawObject->has("devClass") && NewObject.devClass!= Existing.devClass) { | ||||
|             Existing.devClass = NewObject.devClass; | ||||
|         } | ||||
| 		AssignIfPresent(RawObject, "doNotAllowOverrides", Existing.doNotAllowOverrides); | ||||
|  | ||||
|         if( RawObject->has("state") && NewObject.state!= Existing.state) { | ||||
|             Existing.state = NewObject.state; | ||||
|         } | ||||
| 		if (RawObject->has("devClass") && NewObject.devClass != Existing.devClass) { | ||||
| 			Existing.devClass = NewObject.devClass; | ||||
| 		} | ||||
|  | ||||
|         RESTAPI::Errors::msg Error=RESTAPI::Errors::SUCCESS; | ||||
|         auto ObjectsCreated = CreateObjects(NewObject,*this,Error); | ||||
|         if(Error.err_num != 0) { | ||||
|             return BadRequest(Error); | ||||
|         } | ||||
| 		if (RawObject->has("state") && NewObject.state != Existing.state) { | ||||
| 			Existing.state = NewObject.state; | ||||
| 		} | ||||
|  | ||||
|         if(!ObjectsCreated.empty()) { | ||||
|             auto it = ObjectsCreated.find("configuration"); | ||||
|             if(it!=ObjectsCreated.end()) { | ||||
|                 FromConfiguration=""; | ||||
|                 ToConfiguration=it->second; | ||||
|                 Existing.deviceConfiguration=ToConfiguration; | ||||
|             } | ||||
|         } | ||||
| 		std::vector<std::string> Errors; | ||||
| 		auto ObjectsCreated = CreateObjects(NewObject, *this, Errors); | ||||
| 		if (!Errors.empty()) { | ||||
| 			return BadRequest(RESTAPI::Errors::ConfigBlockInvalid); | ||||
| 		} | ||||
|  | ||||
|         if(StorageService()->InventoryDB().UpdateRecord("id", Existing.info.id, Existing)) { | ||||
|             MoveUsage(StorageService()->PolicyDB(),DB_,FromPolicy,ToPolicy,Existing.info.id); | ||||
|             MoveUsage(StorageService()->LocationDB(),DB_,FromLocation,ToLocation,Existing.info.id); | ||||
|             MoveUsage(StorageService()->ContactDB(),DB_,FromContact,ToContact,Existing.info.id); | ||||
|             MoveUsage(StorageService()->ConfigurationDB(),DB_,FromConfiguration,ToConfiguration,Existing.info.id); | ||||
|             ManageMembership(StorageService()->EntityDB(),&ProvObjects::Entity::devices,FromEntity,ToEntity,Existing.info.id); | ||||
|             ManageMembership(StorageService()->VenueDB(),&ProvObjects::Venue::devices,FromVenue,ToVenue,Existing.info.id); | ||||
| 		if (!ObjectsCreated.empty()) { | ||||
| 			auto it = ObjectsCreated.find("configuration"); | ||||
| 			if (it != ObjectsCreated.end()) { | ||||
| 				FromConfiguration = ""; | ||||
| 				ToConfiguration = it->second; | ||||
| 				Existing.deviceConfiguration = ToConfiguration; | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
|             SDK::GW::Device::SetOwnerShip(this, SerialNumber, Existing.entity, Existing.venue, Existing.subscriber); | ||||
| 		if (StorageService()->InventoryDB().UpdateRecord("id", Existing.info.id, Existing)) { | ||||
| 			MoveUsage(StorageService()->PolicyDB(), DB_, FromPolicy, ToPolicy, Existing.info.id); | ||||
| 			MoveUsage(StorageService()->LocationDB(), DB_, FromLocation, ToLocation, | ||||
| 					  Existing.info.id); | ||||
| 			MoveUsage(StorageService()->ContactDB(), DB_, FromContact, ToContact, Existing.info.id); | ||||
| 			MoveUsage(StorageService()->ConfigurationDB(), DB_, FromConfiguration, ToConfiguration, | ||||
| 					  Existing.info.id); | ||||
| 			ManageMembership(StorageService()->EntityDB(), &ProvObjects::Entity::devices, | ||||
| 							 FromEntity, ToEntity, Existing.info.id); | ||||
| 			ManageMembership(StorageService()->VenueDB(), &ProvObjects::Venue::devices, FromVenue, | ||||
| 							 ToVenue, Existing.info.id); | ||||
|  | ||||
|             ProvObjects::InventoryTag   NewObjectCreated; | ||||
|             DB_.GetRecord("id", Existing.info.id, NewObjectCreated); | ||||
|             Poco::JSON::Object  Answer; | ||||
|             NewObject.to_json(Answer); | ||||
|             return ReturnObject(Answer); | ||||
|         } | ||||
|         InternalError(RESTAPI::Errors::RecordNotUpdated); | ||||
|     } | ||||
| } | ||||
| 			SDK::GW::Device::SetOwnerShip(this, SerialNumber, Existing.entity, Existing.venue, | ||||
| 										  Existing.subscriber); | ||||
|  | ||||
| 			// Attempt an automatic config push when the venue is set and different than what is | ||||
| 			// in DB. | ||||
| 			poco_information(Logger(), fmt::format("New Venue {} Old Venue {}", NewObject.venue, previous_venue)); | ||||
| 			if (!NewObject.venue.empty() && NewObject.venue != previous_venue) { | ||||
| 				ComputeAndPushConfig(SerialNumber, NewObject.deviceType, Logger()); | ||||
| 			} | ||||
|  | ||||
| 			ProvObjects::InventoryTag NewObjectCreated; | ||||
| 			DB_.GetRecord("id", Existing.info.id, NewObjectCreated); | ||||
| 			Poco::JSON::Object Answer; | ||||
| 			NewObject.to_json(Answer); | ||||
| 			return ReturnObject(Answer); | ||||
| 		} | ||||
| 		InternalError(RESTAPI::Errors::RecordNotUpdated); | ||||
| 	} | ||||
| } // namespace OpenWifi | ||||
| @@ -7,31 +7,33 @@ | ||||
| // | ||||
|  | ||||
| #pragma once | ||||
|  | ||||
| #include "framework/MicroService.h" | ||||
| #include "StorageService.h" | ||||
| #include "framework/RESTAPI_Handler.h" | ||||
|  | ||||
| namespace OpenWifi { | ||||
|     class RESTAPI_inventory_handler : public RESTAPIHandler { | ||||
|     public: | ||||
|         RESTAPI_inventory_handler(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L, RESTAPI_GenericServer & Server, uint64_t TransactionId, bool Internal) | ||||
|         : RESTAPIHandler(bindings, L, | ||||
|                          std::vector<std::string>{ | ||||
|             Poco::Net::HTTPRequest::HTTP_GET, Poco::Net::HTTPRequest::HTTP_POST, | ||||
|             Poco::Net::HTTPRequest::HTTP_PUT, Poco::Net::HTTPRequest::HTTP_DELETE, | ||||
|             Poco::Net::HTTPRequest::HTTP_OPTIONS}, | ||||
|             Server, | ||||
|             TransactionId, | ||||
|             Internal){} | ||||
|         static auto PathName() { return std::list<std::string>{"/api/v1/inventory/{serialNumber}"}; }; | ||||
| 	class RESTAPI_inventory_handler : public RESTAPIHandler { | ||||
| 	  public: | ||||
| 		RESTAPI_inventory_handler(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L, | ||||
| 								  RESTAPI_GenericServerAccounting &Server, uint64_t TransactionId, | ||||
| 								  bool Internal) | ||||
| 			: RESTAPIHandler(bindings, L, | ||||
| 							 std::vector<std::string>{Poco::Net::HTTPRequest::HTTP_GET, | ||||
| 													  Poco::Net::HTTPRequest::HTTP_POST, | ||||
| 													  Poco::Net::HTTPRequest::HTTP_PUT, | ||||
| 													  Poco::Net::HTTPRequest::HTTP_DELETE, | ||||
| 													  Poco::Net::HTTPRequest::HTTP_OPTIONS}, | ||||
| 							 Server, TransactionId, Internal) {} | ||||
| 		static auto PathName() { | ||||
| 			return std::list<std::string>{"/api/v1/inventory/{serialNumber}"}; | ||||
| 		}; | ||||
|  | ||||
|     private: | ||||
|         InventoryDB     &DB_=StorageService()->InventoryDB(); | ||||
|         void DoGet() final; | ||||
|         void DoPost() final; | ||||
|         void DoPut() final; | ||||
|         void DoDelete() final; | ||||
|         void PerformClaim(const std::string &SerialNumber, const std::string & Claimer , | ||||
|                           std::string & ClaimId, uint64_t &ErrorCode, Poco::JSON::Object &Answer); | ||||
|     }; | ||||
| } | ||||
| 	  private: | ||||
| 		InventoryDB &DB_ = StorageService()->InventoryDB(); | ||||
| 		void DoGet() final; | ||||
| 		void DoPost() final; | ||||
| 		void DoPut() final; | ||||
| 		void DoDelete() final; | ||||
| 		void PerformClaim(const std::string &SerialNumber, const std::string &Claimer, | ||||
| 						  std::string &ClaimId, uint64_t &ErrorCode, Poco::JSON::Object &Answer); | ||||
| 	}; | ||||
| } // namespace OpenWifi | ||||
|   | ||||
| @@ -6,127 +6,134 @@ | ||||
| //	Arilia Wireless Inc. | ||||
| // | ||||
|  | ||||
|  | ||||
| #include "RESTAPI_inventory_list_handler.h" | ||||
| #include "StorageService.h" | ||||
| #include "RESTAPI/RESTAPI_db_helpers.h" | ||||
| #include "StorageService.h" | ||||
|  | ||||
| namespace OpenWifi{ | ||||
|     void RESTAPI_inventory_list_handler::SendList( const ProvObjects::InventoryTagVec & Tags, bool SerialOnly) { | ||||
|         Poco::JSON::Array   Array; | ||||
|         for(const auto &i:Tags) { | ||||
|             if(SerialOnly) { | ||||
|                 Array.add(i.serialNumber); | ||||
|             } else { | ||||
|                 Poco::JSON::Object  O; | ||||
|                 i.to_json(O); | ||||
|                 if(QB_.AdditionalInfo) | ||||
|                     AddExtendedInfo(i,O); | ||||
|                 Array.add(O); | ||||
|             } | ||||
|         } | ||||
|         Poco::JSON::Object  Answer; | ||||
|         if(SerialOnly) | ||||
|             Answer.set("serialNumbers", Array); | ||||
|         else | ||||
|             Answer.set("taglist", Array); | ||||
|         ReturnObject(Answer); | ||||
|     } | ||||
| namespace OpenWifi { | ||||
| 	void RESTAPI_inventory_list_handler::SendList(const ProvObjects::InventoryTagVec &Tags, | ||||
| 												  bool SerialOnly) { | ||||
| 		Poco::JSON::Array Array; | ||||
| 		for (const auto &i : Tags) { | ||||
| 			if (SerialOnly) { | ||||
| 				Array.add(i.serialNumber); | ||||
| 			} else { | ||||
| 				Poco::JSON::Object O; | ||||
| 				i.to_json(O); | ||||
| 				if (QB_.AdditionalInfo) | ||||
| 					AddExtendedInfo(i, O); | ||||
| 				Array.add(O); | ||||
| 			} | ||||
| 		} | ||||
| 		Poco::JSON::Object Answer; | ||||
| 		if (SerialOnly) | ||||
| 			Answer.set("serialNumbers", Array); | ||||
| 		else | ||||
| 			Answer.set("taglist", Array); | ||||
| 		ReturnObject(Answer); | ||||
| 	} | ||||
|  | ||||
|     void RESTAPI_inventory_list_handler::DoGet() { | ||||
| 	void RESTAPI_inventory_list_handler::DoGet() { | ||||
|  | ||||
|         if(GetBoolParameter("orderSpec")) { | ||||
|             return ReturnFieldList(DB_,*this); | ||||
|         } | ||||
| 		if (GetBoolParameter("orderSpec")) { | ||||
| 			return ReturnFieldList(DB_, *this); | ||||
| 		} | ||||
|  | ||||
|         bool SerialOnly=GetBoolParameter("serialOnly"); | ||||
| 		bool SerialOnly = GetBoolParameter("serialOnly"); | ||||
|  | ||||
|         std::string UUID; | ||||
|         std::string Arg,Arg2; | ||||
| 		std::string UUID; | ||||
| 		std::string Arg, Arg2; | ||||
|  | ||||
|         std::string OrderBy{" ORDER BY serialNumber ASC "}; | ||||
|         if(HasParameter("orderBy",Arg)) { | ||||
|             if(!DB_.PrepareOrderBy(Arg,OrderBy)) { | ||||
|                 return BadRequest(RESTAPI::Errors::InvalidLOrderBy); | ||||
|             } | ||||
|         } | ||||
| 		std::string OrderBy{" ORDER BY serialNumber ASC "}; | ||||
| 		if (HasParameter("orderBy", Arg)) { | ||||
| 			if (!DB_.PrepareOrderBy(Arg, OrderBy)) { | ||||
| 				return BadRequest(RESTAPI::Errors::InvalidLOrderBy); | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
|         if(!QB_.Select.empty()) { | ||||
|             return ReturnRecordList<decltype(DB_)>("taglist",DB_,*this ); | ||||
|         } else if(HasParameter("entity",UUID)) { | ||||
|             if(QB_.CountOnly) { | ||||
|                 auto C = DB_.Count( StorageService()->InventoryDB().OP("entity",ORM::EQ,UUID)); | ||||
|                 return ReturnCountOnly( C); | ||||
|             } | ||||
|             ProvObjects::InventoryTagVec Tags; | ||||
|             DB_.GetRecords(QB_.Offset, QB_.Limit, Tags, DB_.OP("entity",ORM::EQ,UUID), OrderBy); | ||||
| 		if (!QB_.Select.empty()) { | ||||
| 			return ReturnRecordList<decltype(DB_)>("taglist", DB_, *this); | ||||
| 		} else if (HasParameter("entity", UUID)) { | ||||
| 			if (QB_.CountOnly) { | ||||
| 				auto C = DB_.Count(StorageService()->InventoryDB().OP("entity", ORM::EQ, UUID)); | ||||
| 				return ReturnCountOnly(C); | ||||
| 			} | ||||
| 			ProvObjects::InventoryTagVec Tags; | ||||
| 			DB_.GetRecords(QB_.Offset, QB_.Limit, Tags, DB_.OP("entity", ORM::EQ, UUID), OrderBy); | ||||
| 			return SendList(Tags, SerialOnly); | ||||
| 		} else if (HasParameter("venue", UUID)) { | ||||
| 			if (QB_.CountOnly) { | ||||
| 				auto C = DB_.Count(DB_.OP("venue", ORM::EQ, UUID)); | ||||
| 				return ReturnCountOnly(C); | ||||
| 			} | ||||
| 			ProvObjects::InventoryTagVec Tags; | ||||
| 			DB_.GetRecords(QB_.Offset, QB_.Limit, Tags, DB_.OP("venue", ORM::EQ, UUID), OrderBy); | ||||
| 			return SendList(Tags, SerialOnly); | ||||
| 		} else if (GetBoolParameter("subscribersOnly") && GetBoolParameter("unassigned")) { | ||||
| 			if (QB_.CountOnly) { | ||||
| 				auto C = DB_.Count(" devClass='subscriber' and subscriber='' "); | ||||
| 				return ReturnCountOnly(C); | ||||
| 			} | ||||
| 			ProvObjects::InventoryTagVec Tags; | ||||
| 			DB_.GetRecords(QB_.Offset, QB_.Limit, Tags, " devClass='subscriber' and subscriber='' ", | ||||
| 						   OrderBy); | ||||
| 			if (QB_.CountOnly) { | ||||
| 				auto C = DB_.Count(DB_.OP("venue", ORM::EQ, UUID)); | ||||
| 				return ReturnCountOnly(C); | ||||
| 			} | ||||
| 			return SendList(Tags, SerialOnly); | ||||
| 		} else if (GetBoolParameter("subscribersOnly")) { | ||||
| 			if (QB_.CountOnly) { | ||||
| 				auto C = DB_.Count(" devClass='subscriber' and subscriber!='' "); | ||||
| 				return ReturnCountOnly(C); | ||||
| 			} | ||||
| 			ProvObjects::InventoryTagVec Tags; | ||||
| 			DB_.GetRecords(QB_.Offset, QB_.Limit, Tags, | ||||
| 						   " devClass='subscriber' and subscriber!='' ", OrderBy); | ||||
| 			return SendList(Tags, SerialOnly); | ||||
| 		} else if (GetBoolParameter("unassigned")) { | ||||
| 			if (QB_.CountOnly) { | ||||
| 				std::string Empty; | ||||
| 				auto C = DB_.Count(InventoryDB::OP(DB_.OP("venue", ORM::EQ, Empty), ORM::AND, | ||||
| 												   DB_.OP("entity", ORM::EQ, Empty))); | ||||
| 				return ReturnCountOnly(C); | ||||
| 			} | ||||
| 			ProvObjects::InventoryTagVec Tags; | ||||
| 			std::string Empty; | ||||
| 			DB_.GetRecords(QB_.Offset, QB_.Limit, Tags, | ||||
| 						   InventoryDB::OP(DB_.OP("venue", ORM::EQ, Empty), ORM::AND, | ||||
| 										   DB_.OP("entity", ORM::EQ, Empty)), | ||||
| 						   OrderBy); | ||||
| 			return SendList(Tags, SerialOnly); | ||||
| 		} else if (HasParameter("subscriber", Arg) && !Arg.empty()) { | ||||
| 			// looking for device(s) for a specific subscriber... | ||||
| 			ProvObjects::InventoryTagVec Tags; | ||||
| 			DB_.GetRecords(0, 100, Tags, " subscriber='" + ORM::Escape(Arg) + "'"); | ||||
| 			if (SerialOnly) { | ||||
| 				std::vector<std::string> SerialNumbers; | ||||
| 				std::transform(cbegin(Tags), cend(Tags), std::back_inserter(SerialNumbers), | ||||
| 							   [](const auto &T) { return T.serialNumber; }); | ||||
| 				return ReturnObject("serialNumbers", SerialNumbers); | ||||
| 			} else { | ||||
| 				return MakeJSONObjectArray("taglist", Tags, *this); | ||||
| 			} | ||||
| 		} else if (QB_.CountOnly) { | ||||
| 			auto C = DB_.Count(); | ||||
| 			return ReturnCountOnly(C); | ||||
| 		} else if (GetBoolParameter("rrmOnly")) { | ||||
| 			Types::UUIDvec_t DeviceList; | ||||
| 			DB_.GetRRMDeviceList(DeviceList); | ||||
| 			if (QB_.CountOnly) | ||||
| 				return ReturnCountOnly(DeviceList.size()); | ||||
| 			else { | ||||
| 				return ReturnObject("serialNumbers", DeviceList); | ||||
| 			} | ||||
| 		} else { | ||||
| 			ProvObjects::InventoryTagVec Tags; | ||||
| 			DB_.GetRecords(QB_.Offset, QB_.Limit, Tags, "", OrderBy); | ||||
|             return SendList(Tags, SerialOnly); | ||||
|         } else if(HasParameter("venue",UUID)) { | ||||
|             if(QB_.CountOnly) { | ||||
|                 auto C = DB_.Count(DB_.OP("venue",ORM::EQ,UUID)); | ||||
|                 return ReturnCountOnly( C); | ||||
|             } | ||||
|             ProvObjects::InventoryTagVec Tags; | ||||
|             DB_.GetRecords(QB_.Offset, QB_.Limit, Tags, DB_.OP("venue",ORM::EQ,UUID), OrderBy); | ||||
|             return SendList( Tags, SerialOnly); | ||||
|         } else if(GetBoolParameter("subscribersOnly") && GetBoolParameter("unassigned")) { | ||||
|             if(QB_.CountOnly) { | ||||
|                 auto C = DB_.Count(" devClass='subscriber' and subscriber='' "); | ||||
|                 return ReturnCountOnly( C); | ||||
|             } | ||||
|             ProvObjects::InventoryTagVec Tags; | ||||
|             DB_.GetRecords(QB_.Offset, QB_.Limit, Tags, " devClass='subscriber' and subscriber='' ", OrderBy); | ||||
|             if(QB_.CountOnly) { | ||||
|                 auto C = DB_.Count(DB_.OP("venue",ORM::EQ,UUID)); | ||||
|                 return ReturnCountOnly( C); | ||||
|             } | ||||
|             return SendList(Tags, SerialOnly); | ||||
|         } else if(GetBoolParameter("subscribersOnly")) { | ||||
|             if(QB_.CountOnly) { | ||||
|                 auto C = DB_.Count(" devClass='subscriber' and subscriber!='' "); | ||||
|                 return ReturnCountOnly( C); | ||||
|             } | ||||
|             ProvObjects::InventoryTagVec Tags; | ||||
|             DB_.GetRecords(QB_.Offset, QB_.Limit, Tags," devClass='subscriber' and subscriber!='' ", OrderBy); | ||||
|             return SendList(Tags, SerialOnly); | ||||
|         } else if(GetBoolParameter("unassigned")) { | ||||
|             if(QB_.CountOnly) { | ||||
|                 std::string Empty; | ||||
|                 auto C = DB_.Count( InventoryDB::OP( DB_.OP("venue",ORM::EQ,Empty), | ||||
|                                                                           ORM::AND, DB_.OP("entity",ORM::EQ,Empty) )); | ||||
|                 return ReturnCountOnly(C); | ||||
|             } | ||||
|             ProvObjects::InventoryTagVec Tags; | ||||
|             std::string Empty; | ||||
|             DB_.GetRecords(QB_.Offset, QB_.Limit, Tags, InventoryDB::OP( DB_.OP("venue",ORM::EQ,Empty), | ||||
|                                                                          ORM::AND, DB_.OP("entity",ORM::EQ,Empty) ) , OrderBy ); | ||||
|             return SendList(Tags, SerialOnly); | ||||
|         } else if (HasParameter("subscriber",Arg) && !Arg.empty()) { | ||||
|             // looking for device(s) for a specific subscriber... | ||||
|             ProvObjects::InventoryTagVec Tags; | ||||
|             DB_.GetRecords(0,100,Tags," subscriber='" + Arg + "'"); | ||||
|             if(SerialOnly) { | ||||
|                 std::vector<std::string>    SerialNumbers; | ||||
|                 std::transform(cbegin(Tags), cend(Tags), std::back_inserter(SerialNumbers), [](const auto &T) { return T.serialNumber; }); | ||||
|                 return ReturnObject("serialNumbers",SerialNumbers); | ||||
|             } else { | ||||
|                 return MakeJSONObjectArray("taglist", Tags, *this); | ||||
|             } | ||||
|         } else if (QB_.CountOnly) { | ||||
|             auto C = DB_.Count(); | ||||
|             return ReturnCountOnly(C); | ||||
|         } else if (GetBoolParameter("rrmOnly")) { | ||||
|             Types::UUIDvec_t   DeviceList; | ||||
|             DB_.GetRRMDeviceList(DeviceList); | ||||
|             if(QB_.CountOnly) | ||||
|                 return ReturnCountOnly(DeviceList.size()); | ||||
|             else { | ||||
|                 return ReturnObject("serialNumbers",DeviceList); | ||||
|             } | ||||
|         } else { | ||||
|             ProvObjects::InventoryTagVec Tags; | ||||
|             DB_.GetRecords(QB_.Offset,QB_.Limit,Tags,"",OrderBy); | ||||
|             return MakeJSONObjectArray("taglist", Tags, *this); | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| //			return MakeJSONObjectArray("taglist", Tags, *this); | ||||
| 		} | ||||
| 	} | ||||
| } // namespace OpenWifi | ||||
| @@ -7,30 +7,29 @@ | ||||
| // | ||||
|  | ||||
| #pragma once | ||||
|  | ||||
| #include "StorageService.h" | ||||
| #include "framework/MicroService.h" | ||||
| #include "framework/RESTAPI_Handler.h" | ||||
|  | ||||
| namespace OpenWifi { | ||||
|  | ||||
|     class RESTAPI_inventory_list_handler : public RESTAPIHandler { | ||||
|     public: | ||||
|         RESTAPI_inventory_list_handler(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L, RESTAPI_GenericServer & Server, uint64_t TransactionId, bool Internal) | ||||
|         : RESTAPIHandler(bindings, L, | ||||
|                          std::vector<std::string>{ | ||||
|             Poco::Net::HTTPRequest::HTTP_GET, | ||||
|             Poco::Net::HTTPRequest::HTTP_OPTIONS}, | ||||
|             Server, | ||||
|             TransactionId, | ||||
|             Internal){} | ||||
|         static auto PathName() { return std::list<std::string>{"/api/v1/inventory"}; }; | ||||
|     private: | ||||
|         InventoryDB     &DB_=StorageService()->InventoryDB(); | ||||
|         void DoGet() final; | ||||
|         void DoPost() final {}; | ||||
|         void DoPut() final {}; | ||||
|         void DoDelete() final {}; | ||||
| 	class RESTAPI_inventory_list_handler : public RESTAPIHandler { | ||||
| 	  public: | ||||
| 		RESTAPI_inventory_list_handler(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L, | ||||
| 									   RESTAPI_GenericServerAccounting &Server, | ||||
| 									   uint64_t TransactionId, bool Internal) | ||||
| 			: RESTAPIHandler(bindings, L, | ||||
| 							 std::vector<std::string>{Poco::Net::HTTPRequest::HTTP_GET, | ||||
| 													  Poco::Net::HTTPRequest::HTTP_OPTIONS}, | ||||
| 							 Server, TransactionId, Internal) {} | ||||
| 		static auto PathName() { return std::list<std::string>{"/api/v1/inventory"}; }; | ||||
|  | ||||
|         void SendList(const ProvObjects::InventoryTagVec & Tags, bool SerialOnly); | ||||
|     }; | ||||
| } | ||||
| 	  private: | ||||
| 		InventoryDB &DB_ = StorageService()->InventoryDB(); | ||||
| 		void DoGet() final; | ||||
| 		void DoPost() final{}; | ||||
| 		void DoPut() final{}; | ||||
| 		void DoDelete() final{}; | ||||
|  | ||||
| 		void SendList(const ProvObjects::InventoryTagVec &Tags, bool SerialOnly); | ||||
| 	}; | ||||
| } // namespace OpenWifi | ||||
| @@ -8,19 +8,19 @@ | ||||
| namespace OpenWifi { | ||||
|  | ||||
| 	void RESTAPI_iptocountry_handler::DoGet() { | ||||
| 		auto IPList = GetParameter("iplist",""); | ||||
| 		auto IPList = GetParameter("iplist", ""); | ||||
|  | ||||
| 		if(IPList.empty()) { | ||||
| 		if (IPList.empty()) { | ||||
| 			return BadRequest(RESTAPI::Errors::MissingOrInvalidParameters); | ||||
| 		} | ||||
|  | ||||
| 		auto IPAddresses = Poco::StringTokenizer(IPList,","); | ||||
| 		Poco::JSON::Object	Answer; | ||||
| 		auto IPAddresses = Poco::StringTokenizer(IPList, ","); | ||||
| 		Poco::JSON::Object Answer; | ||||
|  | ||||
| 		Answer.set("enabled", FindCountryFromIP()->Enabled()); | ||||
| 		Poco::JSON::Array	Countries; | ||||
| 		Poco::JSON::Array Countries; | ||||
|  | ||||
| 		for(const auto &i:IPAddresses) { | ||||
| 		for (const auto &i : IPAddresses) { | ||||
| 			Countries.add(FindCountryFromIP()->Get(i)); | ||||
| 		} | ||||
| 		Answer.set("countryCodes", Countries); | ||||
| @@ -28,4 +28,4 @@ namespace OpenWifi { | ||||
| 		return ReturnObject(Answer); | ||||
| 	} | ||||
|  | ||||
| } | ||||
| } // namespace OpenWifi | ||||
| @@ -3,23 +3,23 @@ | ||||
| // | ||||
|  | ||||
| #pragma once | ||||
|  | ||||
| #include "framework/MicroService.h" | ||||
| #include "StorageService.h" | ||||
| #include "framework/RESTAPI_Handler.h" | ||||
|  | ||||
| namespace OpenWifi { | ||||
| class RESTAPI_iptocountry_handler : public RESTAPIHandler { | ||||
|   public: | ||||
| 	RESTAPI_iptocountry_handler(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L, RESTAPI_GenericServer & Server, uint64_t TransactionId, bool Internal) | ||||
| 		: RESTAPIHandler(bindings, L, | ||||
| 						 std::vector<std::string>{Poco::Net::HTTPRequest::HTTP_GET, | ||||
| 												  Poco::Net::HTTPRequest::HTTP_OPTIONS}, | ||||
| 						 Server, | ||||
| 						 TransactionId, | ||||
| 						 Internal){}; | ||||
|     static auto PathName() { return std::list<std::string>{"/api/v1/iptocountry"}; }; | ||||
| 	void DoGet() final; | ||||
| 	void DoDelete() final {}; | ||||
| 	void DoPost() final {}; | ||||
| 	void DoPut() final {}; | ||||
| }; | ||||
| } | ||||
| 	class RESTAPI_iptocountry_handler : public RESTAPIHandler { | ||||
| 	  public: | ||||
| 		RESTAPI_iptocountry_handler(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L, | ||||
| 									RESTAPI_GenericServerAccounting &Server, uint64_t TransactionId, | ||||
| 									bool Internal) | ||||
| 			: RESTAPIHandler(bindings, L, | ||||
| 							 std::vector<std::string>{Poco::Net::HTTPRequest::HTTP_GET, | ||||
| 													  Poco::Net::HTTPRequest::HTTP_OPTIONS}, | ||||
| 							 Server, TransactionId, Internal){}; | ||||
| 		static auto PathName() { return std::list<std::string>{"/api/v1/iptocountry"}; }; | ||||
| 		void DoGet() final; | ||||
| 		void DoDelete() final{}; | ||||
| 		void DoPost() final{}; | ||||
| 		void DoPut() final{}; | ||||
| 	}; | ||||
| } // namespace OpenWifi | ||||
|   | ||||
| @@ -6,161 +6,169 @@ | ||||
| //	Arilia Wireless Inc. | ||||
| // | ||||
|  | ||||
|  | ||||
| #include "RESTAPI_location_handler.h" | ||||
| #include "RESTObjects/RESTAPI_ProvObjects.h" | ||||
| #include "StorageService.h" | ||||
| #include "Daemon.h" | ||||
| #include "RESTAPI/RESTAPI_db_helpers.h" | ||||
| #include "RESTObjects/RESTAPI_ProvObjects.h" | ||||
| #include "StorageService.h" | ||||
| #include "framework/utils.h" | ||||
|  | ||||
| namespace OpenWifi{ | ||||
| namespace OpenWifi { | ||||
|  | ||||
|     void RESTAPI_location_handler::DoGet() { | ||||
|         std::string UUID = GetBinding("uuid",""); | ||||
|         ProvObjects::Location   Existing; | ||||
|         if(UUID.empty() || !DB_.GetRecord("id", UUID, Existing)) { | ||||
|             return BadRequest(RESTAPI::Errors::MissingUUID); | ||||
|         } | ||||
| 	void RESTAPI_location_handler::DoGet() { | ||||
| 		std::string UUID = GetBinding("uuid", ""); | ||||
| 		ProvObjects::Location Existing; | ||||
| 		if (UUID.empty() || !DB_.GetRecord("id", UUID, Existing)) { | ||||
| 			return BadRequest(RESTAPI::Errors::MissingUUID); | ||||
| 		} | ||||
|  | ||||
|         std::string Arg; | ||||
|         Poco::JSON::Object  Answer; | ||||
|         if(HasParameter("expandInUse",Arg) && Arg=="true") { | ||||
|             Storage::ExpandedListMap    M; | ||||
|             std::vector<std::string>    Errors; | ||||
|             Poco::JSON::Object  Inner; | ||||
|             if(StorageService()->ExpandInUse(Existing.inUse,M,Errors)) { | ||||
|                 for(const auto &[type,list]:M) { | ||||
|                     Poco::JSON::Array   ObjList; | ||||
|                     for(const auto &i:list.entries) { | ||||
|                         Poco::JSON::Object  O; | ||||
|                         i.to_json(O); | ||||
|                         ObjList.add(O); | ||||
|                     } | ||||
|                     Inner.set(type,ObjList); | ||||
|                 } | ||||
|             } | ||||
|             Answer.set("entries", Inner); | ||||
|             return ReturnObject(Answer); | ||||
|         } else if(QB_.AdditionalInfo) { | ||||
|             AddExtendedInfo(Existing, Answer); | ||||
|         } | ||||
|         Existing.to_json(Answer); | ||||
|         ReturnObject(Answer); | ||||
|     } | ||||
| 		std::string Arg; | ||||
| 		Poco::JSON::Object Answer; | ||||
| 		if (HasParameter("expandInUse", Arg) && Arg == "true") { | ||||
| 			Storage::ExpandedListMap M; | ||||
| 			std::vector<std::string> Errors; | ||||
| 			Poco::JSON::Object Inner; | ||||
| 			if (StorageService()->ExpandInUse(Existing.inUse, M, Errors)) { | ||||
| 				for (const auto &[type, list] : M) { | ||||
| 					Poco::JSON::Array ObjList; | ||||
| 					for (const auto &i : list.entries) { | ||||
| 						Poco::JSON::Object O; | ||||
| 						i.to_json(O); | ||||
| 						ObjList.add(O); | ||||
| 					} | ||||
| 					Inner.set(type, ObjList); | ||||
| 				} | ||||
| 			} | ||||
| 			Answer.set("entries", Inner); | ||||
| 			return ReturnObject(Answer); | ||||
| 		} else if (QB_.AdditionalInfo) { | ||||
| 			AddExtendedInfo(Existing, Answer); | ||||
| 		} | ||||
| 		Existing.to_json(Answer); | ||||
| 		ReturnObject(Answer); | ||||
| 	} | ||||
|  | ||||
|     void RESTAPI_location_handler::DoDelete() { | ||||
|         std::string UUID = GetBinding("uuid",""); | ||||
|         ProvObjects::Location   Existing; | ||||
|         if(UUID.empty() || !DB_.GetRecord("id", UUID, Existing)) { | ||||
|             return NotFound(); | ||||
|         } | ||||
| 	void RESTAPI_location_handler::DoDelete() { | ||||
| 		std::string UUID = GetBinding("uuid", ""); | ||||
| 		ProvObjects::Location Existing; | ||||
| 		if (UUID.empty() || !DB_.GetRecord("id", UUID, Existing)) { | ||||
| 			return NotFound(); | ||||
| 		} | ||||
|  | ||||
|         bool Force=false; | ||||
|         std::string Arg; | ||||
|         if(HasParameter("force",Arg) && Arg=="true") | ||||
|             Force=true; | ||||
| 		bool Force = false; | ||||
| 		std::string Arg; | ||||
| 		if (HasParameter("force", Arg) && Arg == "true") | ||||
| 			Force = true; | ||||
|  | ||||
|         if(!Force && !Existing.inUse.empty()) { | ||||
|             return BadRequest(RESTAPI::Errors::StillInUse); | ||||
|         } | ||||
| 		if (!Force && !Existing.inUse.empty()) { | ||||
| 			return BadRequest(RESTAPI::Errors::StillInUse); | ||||
| 		} | ||||
|  | ||||
|         DB_.DeleteRecord("id",UUID); | ||||
|         RemoveMembership(StorageService()->EntityDB(),&ProvObjects::Entity::locations,Existing.entity,Existing.info.id); | ||||
|         MoveUsage(StorageService()->PolicyDB(),DB_,Existing.info.id,"",Existing.info.id); | ||||
|         return OK(); | ||||
|     } | ||||
| 		DB_.DeleteRecord("id", UUID); | ||||
| 		RemoveMembership(StorageService()->EntityDB(), &ProvObjects::Entity::locations, | ||||
| 						 Existing.entity, Existing.info.id); | ||||
| 		MoveUsage(StorageService()->PolicyDB(), DB_, Existing.info.id, "", Existing.info.id); | ||||
| 		return OK(); | ||||
| 	} | ||||
|  | ||||
|     void RESTAPI_location_handler::DoPost() { | ||||
|         std::string UUID = GetBinding(RESTAPI::Protocol::UUID,""); | ||||
|         if(UUID.empty()) { | ||||
|             return BadRequest(RESTAPI::Errors::MissingUUID); | ||||
|         } | ||||
| 	void RESTAPI_location_handler::DoPost() { | ||||
| 		std::string UUID = GetBinding(RESTAPI::Protocol::UUID, ""); | ||||
| 		if (UUID.empty()) { | ||||
| 			return BadRequest(RESTAPI::Errors::MissingUUID); | ||||
| 		} | ||||
|  | ||||
|         const auto & Obj = ParsedBody_; | ||||
|         ProvObjects::Location NewObject; | ||||
|         if (!NewObject.from_json(Obj)) { | ||||
|             return BadRequest(RESTAPI::Errors::InvalidJSONDocument); | ||||
|         } | ||||
| 		const auto &Obj = ParsedBody_; | ||||
| 		ProvObjects::Location NewObject; | ||||
| 		if (!NewObject.from_json(Obj)) { | ||||
| 			return BadRequest(RESTAPI::Errors::InvalidJSONDocument); | ||||
| 		} | ||||
|  | ||||
|         if(!ProvObjects::CreateObjectInfo(Obj, UserInfo_.userinfo, NewObject.info)) { | ||||
|             return BadRequest( RESTAPI::Errors::NameMustBeSet); | ||||
|         } | ||||
| 		if (!ProvObjects::CreateObjectInfo(Obj, UserInfo_.userinfo, NewObject.info)) { | ||||
| 			return BadRequest(RESTAPI::Errors::NameMustBeSet); | ||||
| 		} | ||||
|  | ||||
|         if(NewObject.entity.empty() || !StorageService()->EntityDB().Exists("id",NewObject.entity)) { | ||||
|             return BadRequest(RESTAPI::Errors::EntityMustExist); | ||||
|         } | ||||
| 		if (NewObject.entity.empty() || | ||||
| 			!StorageService()->EntityDB().Exists("id", NewObject.entity)) { | ||||
| 			return BadRequest(RESTAPI::Errors::EntityMustExist); | ||||
| 		} | ||||
|  | ||||
|         if(!NewObject.managementPolicy.empty() && !StorageService()->PolicyDB().Exists("id",NewObject.managementPolicy)) { | ||||
|             return BadRequest(RESTAPI::Errors::UnknownManagementPolicyUUID); | ||||
|         } | ||||
| 		if (!NewObject.managementPolicy.empty() && | ||||
| 			!StorageService()->PolicyDB().Exists("id", NewObject.managementPolicy)) { | ||||
| 			return BadRequest(RESTAPI::Errors::UnknownManagementPolicyUUID); | ||||
| 		} | ||||
|  | ||||
|         NewObject.inUse.clear(); | ||||
| 		NewObject.inUse.clear(); | ||||
|  | ||||
|         if(DB_.CreateRecord(NewObject)) { | ||||
|             MoveUsage(StorageService()->PolicyDB(),DB_,"",NewObject.managementPolicy,NewObject.info.id); | ||||
|             AddMembership(StorageService()->EntityDB(),&ProvObjects::Entity::locations,NewObject.entity,NewObject.info.id); | ||||
| 		if (DB_.CreateRecord(NewObject)) { | ||||
| 			MoveUsage(StorageService()->PolicyDB(), DB_, "", NewObject.managementPolicy, | ||||
| 					  NewObject.info.id); | ||||
| 			AddMembership(StorageService()->EntityDB(), &ProvObjects::Entity::locations, | ||||
| 						  NewObject.entity, NewObject.info.id); | ||||
|  | ||||
|             LocationDB::RecordName AddedRecord; | ||||
|             DB_.GetRecord("id", NewObject.info.id,AddedRecord); | ||||
|             Poco::JSON::Object Answer; | ||||
|             NewObject.to_json(Answer); | ||||
|             return ReturnObject(Answer); | ||||
|         } | ||||
|         BadRequest(RESTAPI::Errors::RecordNotCreated); | ||||
|     } | ||||
| 			LocationDB::RecordName AddedRecord; | ||||
| 			DB_.GetRecord("id", NewObject.info.id, AddedRecord); | ||||
| 			Poco::JSON::Object Answer; | ||||
| 			NewObject.to_json(Answer); | ||||
| 			return ReturnObject(Answer); | ||||
| 		} | ||||
| 		BadRequest(RESTAPI::Errors::RecordNotCreated); | ||||
| 	} | ||||
|  | ||||
|     void RESTAPI_location_handler::DoPut() { | ||||
| 	void RESTAPI_location_handler::DoPut() { | ||||
|  | ||||
|         std::string UUID = GetBinding(RESTAPI::Protocol::UUID); | ||||
|         ProvObjects::Location   Existing; | ||||
|         if(UUID.empty() || !DB_.GetRecord("id", UUID, Existing)) { | ||||
|             return NotFound(); | ||||
|         } | ||||
| 		std::string UUID = GetBinding(RESTAPI::Protocol::UUID); | ||||
| 		ProvObjects::Location Existing; | ||||
| 		if (UUID.empty() || !DB_.GetRecord("id", UUID, Existing)) { | ||||
| 			return NotFound(); | ||||
| 		} | ||||
|  | ||||
|         const auto & RawObject = ParsedBody_; | ||||
|         ProvObjects::Location NewObject; | ||||
|         if (!NewObject.from_json(RawObject)) { | ||||
|             return BadRequest(RESTAPI::Errors::InvalidJSONDocument); | ||||
|         } | ||||
| 		const auto &RawObject = ParsedBody_; | ||||
| 		ProvObjects::Location NewObject; | ||||
| 		if (!NewObject.from_json(RawObject)) { | ||||
| 			return BadRequest(RESTAPI::Errors::InvalidJSONDocument); | ||||
| 		} | ||||
|  | ||||
|         if(!UpdateObjectInfo(RawObject, UserInfo_.userinfo, Existing.info)) { | ||||
|             return BadRequest( RESTAPI::Errors::NameMustBeSet); | ||||
|         } | ||||
| 		if (!UpdateObjectInfo(RawObject, UserInfo_.userinfo, Existing.info)) { | ||||
| 			return BadRequest(RESTAPI::Errors::NameMustBeSet); | ||||
| 		} | ||||
|  | ||||
|         std::string FromPolicy, ToPolicy; | ||||
|         if(!CreateMove(RawObject,"managementPolicy",&LocationDB::RecordName::managementPolicy, Existing, FromPolicy, ToPolicy, StorageService()->PolicyDB())) | ||||
|             return BadRequest(RESTAPI::Errors::EntityMustExist); | ||||
| 		std::string FromPolicy, ToPolicy; | ||||
| 		if (!CreateMove(RawObject, "managementPolicy", &LocationDB::RecordName::managementPolicy, | ||||
| 						Existing, FromPolicy, ToPolicy, StorageService()->PolicyDB())) | ||||
| 			return BadRequest(RESTAPI::Errors::EntityMustExist); | ||||
|  | ||||
|         std::string FromEntity, ToEntity; | ||||
|         if(!CreateMove(RawObject,"entity",&LocationDB::RecordName::entity, Existing, FromEntity, ToEntity, StorageService()->EntityDB())) | ||||
|             return BadRequest(RESTAPI::Errors::EntityMustExist); | ||||
| 		std::string FromEntity, ToEntity; | ||||
| 		if (!CreateMove(RawObject, "entity", &LocationDB::RecordName::entity, Existing, FromEntity, | ||||
| 						ToEntity, StorageService()->EntityDB())) | ||||
| 			return BadRequest(RESTAPI::Errors::EntityMustExist); | ||||
|  | ||||
|         AssignIfPresent(RawObject, "buildingName", Existing.buildingName); | ||||
|         AssignIfPresent(RawObject, "city", Existing.city); | ||||
|         AssignIfPresent(RawObject, "state", Existing.state); | ||||
|         AssignIfPresent(RawObject, "postal", Existing.postal); | ||||
|         AssignIfPresent(RawObject, "country", Existing.country); | ||||
|         AssignIfPresent(RawObject, "geoCode", Existing.geoCode); | ||||
|         if(RawObject->has("addressLines")) | ||||
|             Existing.addressLines = NewObject.addressLines; | ||||
|         if(RawObject->has("phones")) | ||||
|             Existing.phones = NewObject.phones; | ||||
|         if(RawObject->has("mobiles")) | ||||
|             Existing.mobiles = NewObject.mobiles; | ||||
|         Existing.info.modified = OpenWifi::Now(); | ||||
|         if(RawObject->has("type")) | ||||
|             Existing.type = NewObject.type; | ||||
| 		AssignIfPresent(RawObject, "buildingName", Existing.buildingName); | ||||
| 		AssignIfPresent(RawObject, "city", Existing.city); | ||||
| 		AssignIfPresent(RawObject, "state", Existing.state); | ||||
| 		AssignIfPresent(RawObject, "postal", Existing.postal); | ||||
| 		AssignIfPresent(RawObject, "country", Existing.country); | ||||
| 		AssignIfPresent(RawObject, "geoCode", Existing.geoCode); | ||||
| 		if (RawObject->has("addressLines")) | ||||
| 			Existing.addressLines = NewObject.addressLines; | ||||
| 		if (RawObject->has("phones")) | ||||
| 			Existing.phones = NewObject.phones; | ||||
| 		if (RawObject->has("mobiles")) | ||||
| 			Existing.mobiles = NewObject.mobiles; | ||||
| 		Existing.info.modified = Utils::Now(); | ||||
| 		if (RawObject->has("type")) | ||||
| 			Existing.type = NewObject.type; | ||||
|  | ||||
|         if(DB_.UpdateRecord("id", UUID, Existing)) { | ||||
|             MoveUsage(StorageService()->PolicyDB(), DB_, FromPolicy, ToPolicy, Existing.info.id); | ||||
|             ManageMembership(StorageService()->EntityDB(),&ProvObjects::Entity::locations,FromEntity, ToEntity, Existing.info.id); | ||||
| 		if (DB_.UpdateRecord("id", UUID, Existing)) { | ||||
| 			MoveUsage(StorageService()->PolicyDB(), DB_, FromPolicy, ToPolicy, Existing.info.id); | ||||
| 			ManageMembership(StorageService()->EntityDB(), &ProvObjects::Entity::locations, | ||||
| 							 FromEntity, ToEntity, Existing.info.id); | ||||
|  | ||||
|             ProvObjects::Location    NewObjectAdded; | ||||
|             DB_.GetRecord("id", UUID, NewObjectAdded); | ||||
|             Poco::JSON::Object  Answer; | ||||
|             NewObjectAdded.to_json(Answer); | ||||
|             return ReturnObject(Answer); | ||||
|         } | ||||
|         InternalError(RESTAPI::Errors::RecordNotUpdated); | ||||
|     } | ||||
| } | ||||
| 			ProvObjects::Location NewObjectAdded; | ||||
| 			DB_.GetRecord("id", UUID, NewObjectAdded); | ||||
| 			Poco::JSON::Object Answer; | ||||
| 			NewObjectAdded.to_json(Answer); | ||||
| 			return ReturnObject(Answer); | ||||
| 		} | ||||
| 		InternalError(RESTAPI::Errors::RecordNotUpdated); | ||||
| 	} | ||||
| } // namespace OpenWifi | ||||
| @@ -7,29 +7,29 @@ | ||||
| // | ||||
|  | ||||
| #pragma once | ||||
|  | ||||
| #include "framework/MicroService.h" | ||||
| #include "StorageService.h" | ||||
| #include "framework/RESTAPI_Handler.h" | ||||
|  | ||||
| namespace OpenWifi { | ||||
|     class RESTAPI_location_handler : public RESTAPIHandler { | ||||
|     public: | ||||
|         RESTAPI_location_handler(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L, RESTAPI_GenericServer & Server, uint64_t TransactionId, bool Internal) | ||||
|         : RESTAPIHandler(bindings, L, | ||||
|                          std::vector<std::string>{ | ||||
|             Poco::Net::HTTPRequest::HTTP_GET, Poco::Net::HTTPRequest::HTTP_POST, | ||||
|             Poco::Net::HTTPRequest::HTTP_PUT, Poco::Net::HTTPRequest::HTTP_DELETE, | ||||
|             Poco::Net::HTTPRequest::HTTP_OPTIONS}, | ||||
|             Server, | ||||
|             TransactionId, | ||||
|             Internal){} | ||||
|         static auto PathName() { return std::list<std::string>{"/api/v1/location/{uuid}"}; }; | ||||
| 	class RESTAPI_location_handler : public RESTAPIHandler { | ||||
| 	  public: | ||||
| 		RESTAPI_location_handler(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L, | ||||
| 								 RESTAPI_GenericServerAccounting &Server, uint64_t TransactionId, | ||||
| 								 bool Internal) | ||||
| 			: RESTAPIHandler(bindings, L, | ||||
| 							 std::vector<std::string>{Poco::Net::HTTPRequest::HTTP_GET, | ||||
| 													  Poco::Net::HTTPRequest::HTTP_POST, | ||||
| 													  Poco::Net::HTTPRequest::HTTP_PUT, | ||||
| 													  Poco::Net::HTTPRequest::HTTP_DELETE, | ||||
| 													  Poco::Net::HTTPRequest::HTTP_OPTIONS}, | ||||
| 							 Server, TransactionId, Internal) {} | ||||
| 		static auto PathName() { return std::list<std::string>{"/api/v1/location/{uuid}"}; }; | ||||
|  | ||||
|     private: | ||||
|         LocationDB      & DB_ = StorageService()->LocationDB(); | ||||
|         void DoGet() final ; | ||||
|         void DoPost() final ; | ||||
|         void DoPut() final ; | ||||
|         void DoDelete() final ; | ||||
|     }; | ||||
| } | ||||
| 	  private: | ||||
| 		LocationDB &DB_ = StorageService()->LocationDB(); | ||||
| 		void DoGet() final; | ||||
| 		void DoPost() final; | ||||
| 		void DoPut() final; | ||||
| 		void DoDelete() final; | ||||
| 	}; | ||||
| } // namespace OpenWifi | ||||
|   | ||||
| @@ -4,13 +4,13 @@ | ||||
|  | ||||
| #include "RESTAPI_location_list_handler.h" | ||||
|  | ||||
| #include "RESTAPI/RESTAPI_db_helpers.h" | ||||
| #include "RESTObjects/RESTAPI_ProvObjects.h" | ||||
| #include "StorageService.h" | ||||
| #include "RESTAPI/RESTAPI_db_helpers.h" | ||||
|  | ||||
| namespace OpenWifi{ | ||||
| namespace OpenWifi { | ||||
|  | ||||
|     void RESTAPI_location_list_handler::DoGet() { | ||||
|         return ListHandler<LocationDB>("locations", DB_, *this); | ||||
|     } | ||||
| } | ||||
| 	void RESTAPI_location_list_handler::DoGet() { | ||||
| 		return ListHandler<LocationDB>("locations", DB_, *this); | ||||
| 	} | ||||
| } // namespace OpenWifi | ||||
| @@ -3,28 +3,27 @@ | ||||
| // | ||||
|  | ||||
| #pragma once | ||||
|  | ||||
| #include "framework/MicroService.h" | ||||
| #include "StorageService.h" | ||||
| #include "framework/RESTAPI_Handler.h" | ||||
|  | ||||
| namespace OpenWifi { | ||||
|  | ||||
|     class RESTAPI_location_list_handler : public RESTAPIHandler { | ||||
|     public: | ||||
|         RESTAPI_location_list_handler(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L, RESTAPI_GenericServer & Server, uint64_t TransactionId, bool Internal) | ||||
|         : RESTAPIHandler(bindings, L, | ||||
|                          std::vector<std::string>{ | ||||
|             Poco::Net::HTTPRequest::HTTP_GET, | ||||
|             Poco::Net::HTTPRequest::HTTP_OPTIONS}, | ||||
|             Server, | ||||
|             TransactionId, | ||||
|             Internal){} | ||||
|         static auto PathName() { return std::list<std::string>{"/api/v1/location"}; }; | ||||
|     private: | ||||
|         LocationDB  & DB_=StorageService()->LocationDB(); | ||||
|         void DoGet() final; | ||||
|         void DoPost() final {}; | ||||
|         void DoPut() final {}; | ||||
|         void DoDelete() final {}; | ||||
|     }; | ||||
| } | ||||
| 	class RESTAPI_location_list_handler : public RESTAPIHandler { | ||||
| 	  public: | ||||
| 		RESTAPI_location_list_handler(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L, | ||||
| 									  RESTAPI_GenericServerAccounting &Server, | ||||
| 									  uint64_t TransactionId, bool Internal) | ||||
| 			: RESTAPIHandler(bindings, L, | ||||
| 							 std::vector<std::string>{Poco::Net::HTTPRequest::HTTP_GET, | ||||
| 													  Poco::Net::HTTPRequest::HTTP_OPTIONS}, | ||||
| 							 Server, TransactionId, Internal) {} | ||||
| 		static auto PathName() { return std::list<std::string>{"/api/v1/location"}; }; | ||||
|  | ||||
| 	  private: | ||||
| 		LocationDB &DB_ = StorageService()->LocationDB(); | ||||
| 		void DoGet() final; | ||||
| 		void DoPost() final{}; | ||||
| 		void DoPut() final{}; | ||||
| 		void DoDelete() final{}; | ||||
| 	}; | ||||
| } // namespace OpenWifi | ||||
|   | ||||