Переглянути джерело

Added swagger files and tokens plus fixed some data issues

main
rpm-mcarman 2 роки тому
джерело
коміт
e2bec5e7d8
27 змінених файлів з 371 додано та 19 видалено
  1. +27
    -0
      Package.resolved
  2. +2
    -0
      Package.swift
  3. BIN
      Public/Swagger/favicon-16x16.png
  4. BIN
      Public/Swagger/favicon-32x32.png
  5. +16
    -0
      Public/Swagger/index.css
  6. +19
    -0
      Public/Swagger/index.html
  7. +79
    -0
      Public/Swagger/oauth2-redirect.html
  8. +20
    -0
      Public/Swagger/swagger-initializer.js
  9. +3
    -0
      Public/Swagger/swagger-ui-bundle.js
  10. +1
    -0
      Public/Swagger/swagger-ui-bundle.js.map
  11. +3
    -0
      Public/Swagger/swagger-ui-es-bundle-core.js
  12. +1
    -0
      Public/Swagger/swagger-ui-es-bundle-core.js.map
  13. +3
    -0
      Public/Swagger/swagger-ui-es-bundle.js
  14. +1
    -0
      Public/Swagger/swagger-ui-es-bundle.js.map
  15. +3
    -0
      Public/Swagger/swagger-ui-standalone-preset.js
  16. +1
    -0
      Public/Swagger/swagger-ui-standalone-preset.js.map
  17. +3
    -0
      Public/Swagger/swagger-ui.css
  18. +1
    -0
      Public/Swagger/swagger-ui.css.map
  19. +2
    -0
      Public/Swagger/swagger-ui.js
  20. +1
    -0
      Public/Swagger/swagger-ui.js.map
  21. +15
    -0
      Sources/App/Controllers/AuthControllers/cntrlUser.swift
  22. +55
    -0
      Sources/App/Models/Token.swift
  23. +39
    -0
      Sources/App/Models/mdlLicense.swift
  24. +2
    -0
      Sources/App/configure.swift
  25. +1
    -4
      Sources/App/routes.swift
  26. +65
    -7
      Tests/AppTests/RoleTest.swift
  27. +8
    -8
      Tests/AppTests/UserTests.swift

+ 27
- 0
Package.resolved Переглянути файл

@@ -216,6 +216,15 @@
"version" : "1.0.2"
}
},
{
"identity" : "swift-syntax",
"kind" : "remoteSourceControl",
"location" : "https://github.com/apple/swift-syntax.git",
"state" : {
"revision" : "64889f0c732f210a935a0ad7cda38f77f876262d",
"version" : "509.1.1"
}
},
{
"identity" : "swift-system",
"kind" : "remoteSourceControl",
@@ -225,6 +234,15 @@
"version" : "1.2.1"
}
},
{
"identity" : "swiftopenapi",
"kind" : "remoteSourceControl",
"location" : "https://github.com/dankinsoid/SwiftOpenAPI.git",
"state" : {
"revision" : "d4ac9379e1f7071844deda554c247c8cb13823ce",
"version" : "2.20.0"
}
},
{
"identity" : "vapor",
"kind" : "remoteSourceControl",
@@ -234,6 +252,15 @@
"version" : "4.92.1"
}
},
{
"identity" : "vaportoopenapi",
"kind" : "remoteSourceControl",
"location" : "https://github.com/dankinsoid/VaporToOpenAPI.git",
"state" : {
"revision" : "5bf8c3fc73a42f0dd8c1ae2928fb5817026fa69e",
"version" : "4.5.0"
}
},
{
"identity" : "websocket-kit",
"kind" : "remoteSourceControl",


+ 2
- 0
Package.swift Переглянути файл

@@ -13,6 +13,7 @@ let package = Package(
.package(url: "https://github.com/vapor/fluent.git", from: "4.8.0"),
// 🐘 Fluent driver for Postgres.
.package(url: "https://github.com/vapor/fluent-postgres-driver.git", from: "2.7.2"),
.package(url: "https://github.com/dankinsoid/VaporToOpenAPI.git", from: "4.5.0"),
],
targets: [
.executableTarget(
@@ -21,6 +22,7 @@ let package = Package(
.product(name: "Fluent", package: "fluent"),
.product(name: "FluentPostgresDriver", package: "fluent-postgres-driver"),
.product(name: "Vapor", package: "vapor"),
.product(name: "VaporToOpenAPI", package: "vaportoopenapi"),
]
),
.testTarget(name: "AppTests", dependencies: [


BIN
Public/Swagger/favicon-16x16.png Переглянути файл

Перед Після
Ширина: 16  |  Висота: 16  |  Розмір: 665 B

BIN
Public/Swagger/favicon-32x32.png Переглянути файл

Перед Після
Ширина: 32  |  Висота: 32  |  Розмір: 628 B

+ 16
- 0
Public/Swagger/index.css Переглянути файл

@@ -0,0 +1,16 @@
html {
box-sizing: border-box;
overflow: -moz-scrollbars-vertical;
overflow-y: scroll;
}

*,
*:before,
*:after {
box-sizing: inherit;
}

body {
margin: 0;
background: #fafafa;
}

+ 19
- 0
Public/Swagger/index.html Переглянути файл

@@ -0,0 +1,19 @@
<!-- HTML for static distribution bundle build -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Swagger UI</title>
<link rel="stylesheet" type="text/css" href="./swagger-ui.css" />
<link rel="stylesheet" type="text/css" href="index.css" />
<link rel="icon" type="image/png" href="./favicon-32x32.png" sizes="32x32" />
<link rel="icon" type="image/png" href="./favicon-16x16.png" sizes="16x16" />
</head>

<body>
<div id="swagger-ui"></div>
<script src="./swagger-ui-bundle.js" charset="UTF-8"> </script>
<script src="./swagger-ui-standalone-preset.js" charset="UTF-8"> </script>
<script src="./swagger-initializer.js" charset="UTF-8"> </script>
</body>
</html>

+ 79
- 0
Public/Swagger/oauth2-redirect.html Переглянути файл

@@ -0,0 +1,79 @@
<!doctype html>
<html lang="en-US">
<head>
<title>Swagger UI: OAuth2 Redirect</title>
</head>
<body>
<script>
'use strict';
function run () {
var oauth2 = window.opener.swaggerUIRedirectOauth2;
var sentState = oauth2.state;
var redirectUrl = oauth2.redirectUrl;
var isValid, qp, arr;

if (/code|token|error/.test(window.location.hash)) {
qp = window.location.hash.substring(1).replace('?', '&');
} else {
qp = location.search.substring(1);
}

arr = qp.split("&");
arr.forEach(function (v,i,_arr) { _arr[i] = '"' + v.replace('=', '":"') + '"';});
qp = qp ? JSON.parse('{' + arr.join() + '}',
function (key, value) {
return key === "" ? value : decodeURIComponent(value);
}
) : {};

isValid = qp.state === sentState;

if ((
oauth2.auth.schema.get("flow") === "accessCode" ||
oauth2.auth.schema.get("flow") === "authorizationCode" ||
oauth2.auth.schema.get("flow") === "authorization_code"
) && !oauth2.auth.code) {
if (!isValid) {
oauth2.errCb({
authId: oauth2.auth.name,
source: "auth",
level: "warning",
message: "Authorization may be unsafe, passed state was changed in server. The passed state wasn't returned from auth server."
});
}

if (qp.code) {
delete oauth2.state;
oauth2.auth.code = qp.code;
oauth2.callback({auth: oauth2.auth, redirectUrl: redirectUrl});
} else {
let oauthErrorMsg;
if (qp.error) {
oauthErrorMsg = "["+qp.error+"]: " +
(qp.error_description ? qp.error_description+ ". " : "no accessCode received from the server. ") +
(qp.error_uri ? "More info: "+qp.error_uri : "");
}

oauth2.errCb({
authId: oauth2.auth.name,
source: "auth",
level: "error",
message: oauthErrorMsg || "[Authorization failed]: no accessCode received from the server."
});
}
} else {
oauth2.callback({auth: oauth2.auth, token: qp, isValid: isValid, redirectUrl: redirectUrl});
}
window.close();
}

if (document.readyState !== 'loading') {
run();
} else {
document.addEventListener('DOMContentLoaded', function () {
run();
});
}
</script>
</body>
</html>

+ 20
- 0
Public/Swagger/swagger-initializer.js Переглянути файл

@@ -0,0 +1,20 @@
window.onload = function() {
//<editor-fold desc="Changeable Configuration Block">

// the following lines will be replaced by docker/configurator, when it runs in a docker-container
window.ui = SwaggerUIBundle({
url: "https://petstore.swagger.io/v2/swagger.json",
dom_id: '#swagger-ui',
deepLinking: true,
presets: [
SwaggerUIBundle.presets.apis,
SwaggerUIStandalonePreset
],
plugins: [
SwaggerUIBundle.plugins.DownloadUrl
],
layout: "StandaloneLayout"
});

//</editor-fold>
};

+ 3
- 0
Public/Swagger/swagger-ui-bundle.js
Різницю між файлами не показано, бо вона завелика
Переглянути файл


+ 1
- 0
Public/Swagger/swagger-ui-bundle.js.map
Різницю між файлами не показано, бо вона завелика
Переглянути файл


+ 3
- 0
Public/Swagger/swagger-ui-es-bundle-core.js
Різницю між файлами не показано, бо вона завелика
Переглянути файл


+ 1
- 0
Public/Swagger/swagger-ui-es-bundle-core.js.map
Різницю між файлами не показано, бо вона завелика
Переглянути файл


+ 3
- 0
Public/Swagger/swagger-ui-es-bundle.js
Різницю між файлами не показано, бо вона завелика
Переглянути файл


+ 1
- 0
Public/Swagger/swagger-ui-es-bundle.js.map
Різницю між файлами не показано, бо вона завелика
Переглянути файл


+ 3
- 0
Public/Swagger/swagger-ui-standalone-preset.js
Різницю між файлами не показано, бо вона завелика
Переглянути файл


+ 1
- 0
Public/Swagger/swagger-ui-standalone-preset.js.map
Різницю між файлами не показано, бо вона завелика
Переглянути файл


+ 3
- 0
Public/Swagger/swagger-ui.css
Різницю між файлами не показано, бо вона завелика
Переглянути файл


+ 1
- 0
Public/Swagger/swagger-ui.css.map
Різницю між файлами не показано, бо вона завелика
Переглянути файл


+ 2
- 0
Public/Swagger/swagger-ui.js
Різницю між файлами не показано, бо вона завелика
Переглянути файл


+ 1
- 0
Public/Swagger/swagger-ui.js.map
Різницю між файлами не показано, бо вона завелика
Переглянути файл


+ 15
- 0
Sources/App/Controllers/AuthControllers/cntrlUser.swift Переглянути файл

@@ -84,4 +84,19 @@ struct cntrlUser: RouteCollection {
}
return response
}
func createToken(req: Request) async throws -> Response{
guard let obj = try? await mdlUser.ObjQuery(req: req).field(\.$id).field(\.$username).first() else{
throw Abort(.notFound, reason: "User was not found.")
}
guard let exp = try? await mdlLicense.query(on: req.db).first() else {
throw Abort(.notFound)
}
let token = Token(userid: obj.id!, token: [UInt8].random(count: 16).base64, source: .signup, expiresat: exp.expires)
try await token.save(on: req.db)
guard let response = try? await token.encodeResponse(status: .ok, for: req) else{
throw Abort(.noContent, reason: "Something went wrong decoding data. Token has been deleted.")
}
return response
}
}

+ 55
- 0
Sources/App/Models/Token.swift Переглянути файл

@@ -0,0 +1,55 @@
//
// Token.swift
//
//
// Created by Michiel Carman on 4/5/24.
//

import Vapor
import Fluent

enum SessionSource: Int, Content {
case signup
case login
}

final class Token: Model, Content{
static let schema = "token"
@ID(custom: "id", generatedBy: .database) var id: Int?
@Parent(key: "userId") var user: mdlUser
@Field(key: "value") var value: String
@Field(key: "source") var source: SessionSource
@Field(key: "expiresAt") var expiresat: Date?
@Timestamp(key: "createdAt", on: .create) var createdat: Date?
init(){}
init(id: Int? = nil, userid: mdlUser.IDValue, token: String,
source: SessionSource, expiresat: Date?) {
self.id = id
self.$user.id = userid
self.value = token
self.source = source
self.expiresat = expiresat
}
}
extension Token{
struct Create: AsyncMigration {
func prepare(on database: Database) async throws {
try await database.schema(Token.schema)
.field("id", .int, .identifier(auto: true))
.field("userId", .int, .references("user", "id"))
.field("value", .string, .required).unique(on: "value")
.field("source", .int, .required)
.field("createdAt", .datetime, .required)
.field("expiresAt", .datetime)
.create()
}

// 5
func revert(on database: Database) async throws {
try await database.schema(Token.schema).delete()
}
}
}

+ 39
- 0
Sources/App/Models/mdlLicense.swift Переглянути файл

@@ -0,0 +1,39 @@
//
// mdlLicense.swift
//
//
// Created by Michiel Carman on 4/5/24.
//

import Vapor
import Fluent
final class mdlLicense: Model{
static let schema = "license"
@ID(custom: "id", generatedBy: .database) var id: Int?
@Field(key: "expires") var expires: Date
init(){}
init(id: Int?, expires: Date){
self.id = id!
self.expires = expires
}
}
extension mdlLicense{
struct Create: AsyncMigration{
func prepare(on database: FluentKit.Database) async throws {
try await database.schema(mdlLicense.schema)
.field("id", .int, .identifier(auto: true))
.field("expires", .datetime)
.create()
}
func revert(on database: FluentKit.Database) async throws {
try await database.schema(mdlLicense.schema)
.delete()
}
}
}

+ 2
- 0
Sources/App/configure.swift Переглянути файл

@@ -138,6 +138,8 @@ public func configure(_ app: Application) async throws {
app.migrations.add(mdlTemplate.Mod1())
app.migrations.add(mdlTemplateCategory.Create())
app.migrations.add(mdlTemplateItemSpec.Create())
app.migrations.add(Token.Create())
app.migrations.add(mdlLicense.Create())
app.logger.logLevel = .debug


+ 1
- 4
Sources/App/routes.swift Переглянути файл

@@ -4,10 +4,7 @@ import Crypto


let
encryptionKey =
SymmetricKey(data:
Environment.get("ENCRYPTION_KEY")!.data(using:
.utf8)!)
encryptionKey = SymmetricKey(data: Environment.get("ENCRYPTION_KEY")!.data(using: .utf8)!)

func routes(_ app: Application) throws {
app.routes.caseInsensitive = true


+ 65
- 7
Tests/AppTests/RoleTest.swift Переглянути файл

@@ -1,8 +1,66 @@
//
// File.swift
//
//
// Created by Michiel Carman on 4/5/24.
//
@testable import App
import Fluent
import XCTVapor

import Foundation
final class RoleTests: XCTestCase {
func test1() async throws{
let app = Application(.testing)
defer{app.shutdown()}
try await configure(app)
let basepath = "/api/v2.0/roles/"
let name = "testRole"
let description = "Testing Role methods"
let cuserid = -1
let uuserid = -1
//Insert object
try app.test(.POST, basepath, beforeRequest: {
req in
let input = mdlRole(id: nil, name: name, description: description, createuserid: cuserid, updateuserid: uuserid)
try req.content.encode(input)
}, afterResponse: {
res in
XCTAssertEqual(res.status, .created)
let obj = try res.content.decode(mdlRole.self)
XCTAssertEqual(obj.name, name)
let id = obj.id
//Update object just created
try app.test(.POST, basepath, beforeRequest:{
req in
let input = mdlRole(id: nil, name: name, description: "Test Update", createuserid: cuserid, updateuserid: uuserid)
}, afterResponse: {
res in
XCTAssertEqual(res.status, .accepted)
let obj = try res.content.decode(mdlRole.self)
XCTAssertEqual(obj.name, name)
})
//Read all objects in the table
try app.test(.GET, basepath, afterResponse: { res in
XCTAssertEqual(res.status, .ok)
XCTAssertEqual(res.headers.contentType, .json)
_ = try res.content.decode([mdlRole].self)
})
//Read the object just inserted
var parameter = try CustomCrypto.EncryptString(input: String(id!))
var path = "\(basepath)\(parameter)"
try app.test(.GET, path, afterResponse: { res in
XCTAssertEqual(res.status, .ok)
XCTAssertEqual(res.headers.contentType, .json)
_ = try res.content.decode(mdlRole.self)
})
//Delete object just inserted
let encryptedid = try CustomCrypto.EncryptString(input: String(id!))
path = "api/v2.0/role/"
let url = "\(path)\(encryptedid)"
try app.test(.DELETE, url, afterResponse: {
res in
XCTAssertEqual(res.status, .ok)
_ = try res.content.decode(mdlRole.self)
})
})
}
}

+ 8
- 8
Tests/AppTests/UserTests.swift Переглянути файл

@@ -101,14 +101,14 @@ final class UserTests: XCTestCase {
})
//delete user
// let encryptedid = try CustomCrypto.EncryptString(input: String(id!))
// path = "api/v2.0/users/"
// let url = "\(path)\(encryptedid)"
// try app.test(.DELETE, url, afterResponse: {
// res in
// XCTAssertEqual(res.status, .ok)
// _ = try res.content.decode(mdlUser.self)
// })
let encryptedid = try CustomCrypto.EncryptString(input: String(id!))
path = "api/v2.0/users/"
let url = "\(path)\(encryptedid)"
try app.test(.DELETE, url, afterResponse: {
res in
XCTAssertEqual(res.status, .ok)
_ = try res.content.decode(mdlUser.self)
})
})
}


Завантаження…
Відмінити
Зберегти