WIP: implement CLI
This commit is contained in:
parent
481927c3fd
commit
b9c6226b00
4 changed files with 357 additions and 0 deletions
|
@ -54,6 +54,10 @@
|
|||
80820145275FFD380040996E /* SidebarBudgetView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 80820144275FFD380040996E /* SidebarBudgetView.swift */; };
|
||||
8094A9C327567CAC006C6C62 /* Collections in Frameworks */ = {isa = PBXBuildFile; productRef = 8094A9C227567CAC006C6C62 /* Collections */; };
|
||||
809B942327221EC800B1DAE2 /* CategoryFormSheet.swift in Sources */ = {isa = PBXBuildFile; fileRef = 809B942227221EC800B1DAE2 /* CategoryFormSheet.swift */; };
|
||||
80A419ED2787C0A00090C515 /* TwigsCli.swift in Sources */ = {isa = PBXBuildFile; fileRef = 80A419EC2787C0A00090C515 /* TwigsCli.swift */; };
|
||||
80A419F32787C13E0090C515 /* ArgumentParser in Frameworks */ = {isa = PBXBuildFile; productRef = 80A419F22787C13E0090C515 /* ArgumentParser */; };
|
||||
80A419F52787C1520090C515 /* ArgumentParser in Frameworks */ = {isa = PBXBuildFile; productRef = 80A419F42787C1520090C515 /* ArgumentParser */; };
|
||||
80A419F72788A3880090C515 /* TwigsCore in Frameworks */ = {isa = PBXBuildFile; productRef = 80A419F62788A3880090C515 /* TwigsCore */; };
|
||||
80D1FC14277C1EF9007F17FB /* InlineLoadingView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 80D1FC13277C1EF9007F17FB /* InlineLoadingView.swift */; };
|
||||
/* End PBXBuildFile section */
|
||||
|
||||
|
@ -74,6 +78,18 @@
|
|||
};
|
||||
/* End PBXContainerItemProxy section */
|
||||
|
||||
/* Begin PBXCopyFilesBuildPhase section */
|
||||
80A419E82787C0A00090C515 /* CopyFiles */ = {
|
||||
isa = PBXCopyFilesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
dstPath = /usr/share/man/man1/;
|
||||
dstSubfolderSpec = 0;
|
||||
files = (
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 1;
|
||||
};
|
||||
/* End PBXCopyFilesBuildPhase section */
|
||||
|
||||
/* Begin PBXFileReference section */
|
||||
2821265F23555FD300072D52 /* TransactionFormSheet.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TransactionFormSheet.swift; sourceTree = "<group>"; };
|
||||
282126A0235929B800072D52 /* ProfileView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProfileView.swift; sourceTree = "<group>"; };
|
||||
|
@ -129,6 +145,8 @@
|
|||
808582CD277E5E9E00006859 /* TwigsCore */ = {isa = PBXFileReference; lastKnownFileType = wrapper; name = TwigsCore; path = ../TwigsCore; sourceTree = "<group>"; };
|
||||
809B942227221EC800B1DAE2 /* CategoryFormSheet.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CategoryFormSheet.swift; sourceTree = "<group>"; };
|
||||
809B94242722597800B1DAE2 /* es */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = es; path = es.lproj/Localizable.strings; sourceTree = "<group>"; };
|
||||
80A419EA2787C0A00090C515 /* twigs-cli */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = "twigs-cli"; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
80A419EC2787C0A00090C515 /* TwigsCli.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TwigsCli.swift; sourceTree = "<group>"; };
|
||||
80D1FC13277C1EF9007F17FB /* InlineLoadingView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InlineLoadingView.swift; sourceTree = "<group>"; };
|
||||
/* End PBXFileReference section */
|
||||
|
||||
|
@ -137,6 +155,7 @@
|
|||
isa = PBXFrameworksBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
80A419F32787C13E0090C515 /* ArgumentParser in Frameworks */,
|
||||
8005FD5B277E623900E48B23 /* TwigsCore in Frameworks */,
|
||||
8094A9C327567CAC006C6C62 /* Collections in Frameworks */,
|
||||
);
|
||||
|
@ -156,6 +175,15 @@
|
|||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
80A419E72787C0A00090C515 /* Frameworks */ = {
|
||||
isa = PBXFrameworksBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
80A419F72788A3880090C515 /* TwigsCore in Frameworks */,
|
||||
80A419F52787C1520090C515 /* ArgumentParser in Frameworks */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXFrameworksBuildPhase section */
|
||||
|
||||
/* Begin PBXGroup section */
|
||||
|
@ -207,6 +235,7 @@
|
|||
isa = PBXGroup;
|
||||
children = (
|
||||
80DBED432774AE4F00CB0A88 /* Packages */,
|
||||
80A419EB2787C0A00090C515 /* twigs-cli */,
|
||||
28AC94EB233C373900BFB70A /* Products */,
|
||||
28AC94EC233C373900BFB70A /* Twigs */,
|
||||
28AC9503233C373A00BFB70A /* TwigsTests */,
|
||||
|
@ -221,6 +250,7 @@
|
|||
28AC94EA233C373900BFB70A /* Twigs.app */,
|
||||
28AC9500233C373A00BFB70A /* TwigsTests.xctest */,
|
||||
28AC950B233C373A00BFB70A /* TwigsUITests.xctest */,
|
||||
80A419EA2787C0A00090C515 /* twigs-cli */,
|
||||
);
|
||||
name = Products;
|
||||
sourceTree = "<group>";
|
||||
|
@ -320,6 +350,14 @@
|
|||
name = Frameworks;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
80A419EB2787C0A00090C515 /* twigs-cli */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
80A419EC2787C0A00090C515 /* TwigsCli.swift */,
|
||||
);
|
||||
path = "twigs-cli";
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
80D6B1EF275B11C10075D0EC /* Recurring Transactions */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
|
@ -358,6 +396,7 @@
|
|||
packageProductDependencies = (
|
||||
8094A9C227567CAC006C6C62 /* Collections */,
|
||||
8005FD5A277E623900E48B23 /* TwigsCore */,
|
||||
80A419F22787C13E0090C515 /* ArgumentParser */,
|
||||
);
|
||||
productName = Budget;
|
||||
productReference = 28AC94EA233C373900BFB70A /* Twigs.app */;
|
||||
|
@ -399,6 +438,27 @@
|
|||
productReference = 28AC950B233C373A00BFB70A /* TwigsUITests.xctest */;
|
||||
productType = "com.apple.product-type.bundle.ui-testing";
|
||||
};
|
||||
80A419E92787C0A00090C515 /* twigs-cli */ = {
|
||||
isa = PBXNativeTarget;
|
||||
buildConfigurationList = 80A419F02787C0A00090C515 /* Build configuration list for PBXNativeTarget "twigs-cli" */;
|
||||
buildPhases = (
|
||||
80A419E62787C0A00090C515 /* Sources */,
|
||||
80A419E72787C0A00090C515 /* Frameworks */,
|
||||
80A419E82787C0A00090C515 /* CopyFiles */,
|
||||
);
|
||||
buildRules = (
|
||||
);
|
||||
dependencies = (
|
||||
);
|
||||
name = "twigs-cli";
|
||||
packageProductDependencies = (
|
||||
80A419F42787C1520090C515 /* ArgumentParser */,
|
||||
80A419F62788A3880090C515 /* TwigsCore */,
|
||||
);
|
||||
productName = "twigs-cli";
|
||||
productReference = 80A419EA2787C0A00090C515 /* twigs-cli */;
|
||||
productType = "com.apple.product-type.tool";
|
||||
};
|
||||
/* End PBXNativeTarget section */
|
||||
|
||||
/* Begin PBXProject section */
|
||||
|
@ -420,6 +480,9 @@
|
|||
CreatedOnToolsVersion = 11.0;
|
||||
TestTargetID = 28AC94E9233C373900BFB70A;
|
||||
};
|
||||
80A419E92787C0A00090C515 = {
|
||||
CreatedOnToolsVersion = 13.2.1;
|
||||
};
|
||||
};
|
||||
};
|
||||
buildConfigurationList = 28AC94E5233C373900BFB70A /* Build configuration list for PBXProject "Twigs" */;
|
||||
|
@ -434,6 +497,7 @@
|
|||
mainGroup = 28AC94E1233C373900BFB70A;
|
||||
packageReferences = (
|
||||
8094A9C127567CAC006C6C62 /* XCRemoteSwiftPackageReference "swift-collections" */,
|
||||
80A419F12787C13E0090C515 /* XCRemoteSwiftPackageReference "swift-argument-parser" */,
|
||||
);
|
||||
productRefGroup = 28AC94EB233C373900BFB70A /* Products */;
|
||||
projectDirPath = "";
|
||||
|
@ -442,6 +506,7 @@
|
|||
28AC94E9233C373900BFB70A /* Twigs */,
|
||||
28AC94FF233C373A00BFB70A /* TwigsTests */,
|
||||
28AC950A233C373A00BFB70A /* TwigsUITests */,
|
||||
80A419E92787C0A00090C515 /* twigs-cli */,
|
||||
);
|
||||
};
|
||||
/* End PBXProject section */
|
||||
|
@ -538,6 +603,14 @@
|
|||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
80A419E62787C0A00090C515 /* Sources */ = {
|
||||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
80A419ED2787C0A00090C515 /* TwigsCli.swift in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXSourcesBuildPhase section */
|
||||
|
||||
/* Begin PBXTargetDependency section */
|
||||
|
@ -834,6 +907,34 @@
|
|||
};
|
||||
name = Release;
|
||||
};
|
||||
80A419EE2787C0A00090C515 /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++17";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
DEVELOPMENT_TEAM = VJ33S6H7W7;
|
||||
ENABLE_HARDENED_RUNTIME = YES;
|
||||
MACOSX_DEPLOYMENT_TARGET = 12.1;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SDKROOT = macosx;
|
||||
SWIFT_VERSION = 5.0;
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
80A419EF2787C0A00090C515 /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++17";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
DEVELOPMENT_TEAM = VJ33S6H7W7;
|
||||
ENABLE_HARDENED_RUNTIME = YES;
|
||||
MACOSX_DEPLOYMENT_TARGET = 12.1;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SDKROOT = macosx;
|
||||
SWIFT_VERSION = 5.0;
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
/* End XCBuildConfiguration section */
|
||||
|
||||
/* Begin XCConfigurationList section */
|
||||
|
@ -873,6 +974,15 @@
|
|||
defaultConfigurationIsVisible = 0;
|
||||
defaultConfigurationName = Release;
|
||||
};
|
||||
80A419F02787C0A00090C515 /* Build configuration list for PBXNativeTarget "twigs-cli" */ = {
|
||||
isa = XCConfigurationList;
|
||||
buildConfigurations = (
|
||||
80A419EE2787C0A00090C515 /* Debug */,
|
||||
80A419EF2787C0A00090C515 /* Release */,
|
||||
);
|
||||
defaultConfigurationIsVisible = 0;
|
||||
defaultConfigurationName = Release;
|
||||
};
|
||||
/* End XCConfigurationList section */
|
||||
|
||||
/* Begin XCRemoteSwiftPackageReference section */
|
||||
|
@ -884,6 +994,14 @@
|
|||
minimumVersion = 1.0.0;
|
||||
};
|
||||
};
|
||||
80A419F12787C13E0090C515 /* XCRemoteSwiftPackageReference "swift-argument-parser" */ = {
|
||||
isa = XCRemoteSwiftPackageReference;
|
||||
repositoryURL = "https://github.com/apple/swift-argument-parser.git";
|
||||
requirement = {
|
||||
kind = upToNextMajorVersion;
|
||||
minimumVersion = 1.0.0;
|
||||
};
|
||||
};
|
||||
/* End XCRemoteSwiftPackageReference section */
|
||||
|
||||
/* Begin XCSwiftPackageProductDependency section */
|
||||
|
@ -896,6 +1014,20 @@
|
|||
package = 8094A9C127567CAC006C6C62 /* XCRemoteSwiftPackageReference "swift-collections" */;
|
||||
productName = Collections;
|
||||
};
|
||||
80A419F22787C13E0090C515 /* ArgumentParser */ = {
|
||||
isa = XCSwiftPackageProductDependency;
|
||||
package = 80A419F12787C13E0090C515 /* XCRemoteSwiftPackageReference "swift-argument-parser" */;
|
||||
productName = ArgumentParser;
|
||||
};
|
||||
80A419F42787C1520090C515 /* ArgumentParser */ = {
|
||||
isa = XCSwiftPackageProductDependency;
|
||||
package = 80A419F12787C13E0090C515 /* XCRemoteSwiftPackageReference "swift-argument-parser" */;
|
||||
productName = ArgumentParser;
|
||||
};
|
||||
80A419F62788A3880090C515 /* TwigsCore */ = {
|
||||
isa = XCSwiftPackageProductDependency;
|
||||
productName = TwigsCore;
|
||||
};
|
||||
/* End XCSwiftPackageProductDependency section */
|
||||
};
|
||||
rootObject = 28AC94E2233C373900BFB70A /* Project object */;
|
||||
|
|
|
@ -1,6 +1,15 @@
|
|||
{
|
||||
"object": {
|
||||
"pins": [
|
||||
{
|
||||
"package": "swift-argument-parser",
|
||||
"repositoryURL": "https://github.com/apple/swift-argument-parser.git",
|
||||
"state": {
|
||||
"branch": null,
|
||||
"revision": "e1465042f195f374b94f915ba8ca49de24300a0d",
|
||||
"version": "1.0.2"
|
||||
}
|
||||
},
|
||||
{
|
||||
"package": "swift-collections",
|
||||
"repositoryURL": "https://github.com/apple/swift-collections.git",
|
||||
|
|
92
Twigs.xcodeproj/xcshareddata/xcschemes/twigs-cli.xcscheme
Normal file
92
Twigs.xcodeproj/xcshareddata/xcschemes/twigs-cli.xcscheme
Normal file
|
@ -0,0 +1,92 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Scheme
|
||||
LastUpgradeVersion = "1320"
|
||||
version = "1.3">
|
||||
<BuildAction
|
||||
parallelizeBuildables = "YES"
|
||||
buildImplicitDependencies = "YES">
|
||||
<BuildActionEntries>
|
||||
<BuildActionEntry
|
||||
buildForTesting = "YES"
|
||||
buildForRunning = "YES"
|
||||
buildForProfiling = "YES"
|
||||
buildForArchiving = "YES"
|
||||
buildForAnalyzing = "YES">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "80A419E92787C0A00090C515"
|
||||
BuildableName = "twigs-cli"
|
||||
BlueprintName = "twigs-cli"
|
||||
ReferencedContainer = "container:Twigs.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildActionEntry>
|
||||
</BuildActionEntries>
|
||||
</BuildAction>
|
||||
<TestAction
|
||||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
shouldUseLaunchSchemeArgsEnv = "YES">
|
||||
<Testables>
|
||||
</Testables>
|
||||
</TestAction>
|
||||
<LaunchAction
|
||||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
launchStyle = "0"
|
||||
useCustomWorkingDirectory = "NO"
|
||||
ignoresPersistentStateOnLaunch = "NO"
|
||||
debugDocumentVersioning = "YES"
|
||||
debugServiceExtension = "internal"
|
||||
allowLocationSimulation = "YES">
|
||||
<BuildableProductRunnable
|
||||
runnableDebuggingMode = "0">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "80A419E92787C0A00090C515"
|
||||
BuildableName = "twigs-cli"
|
||||
BlueprintName = "twigs-cli"
|
||||
ReferencedContainer = "container:Twigs.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildableProductRunnable>
|
||||
<CommandLineArguments>
|
||||
<CommandLineArgument
|
||||
argument = "auth"
|
||||
isEnabled = "YES">
|
||||
</CommandLineArgument>
|
||||
<CommandLineArgument
|
||||
argument = "login"
|
||||
isEnabled = "YES">
|
||||
</CommandLineArgument>
|
||||
<CommandLineArgument
|
||||
argument = "-u https://twigs.api.wbrawner.com"
|
||||
isEnabled = "YES">
|
||||
</CommandLineArgument>
|
||||
</CommandLineArguments>
|
||||
</LaunchAction>
|
||||
<ProfileAction
|
||||
buildConfiguration = "Release"
|
||||
shouldUseLaunchSchemeArgsEnv = "YES"
|
||||
savedToolIdentifier = ""
|
||||
useCustomWorkingDirectory = "NO"
|
||||
debugDocumentVersioning = "YES">
|
||||
<BuildableProductRunnable
|
||||
runnableDebuggingMode = "0">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "80A419E92787C0A00090C515"
|
||||
BuildableName = "twigs-cli"
|
||||
BlueprintName = "twigs-cli"
|
||||
ReferencedContainer = "container:Twigs.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildableProductRunnable>
|
||||
</ProfileAction>
|
||||
<AnalyzeAction
|
||||
buildConfiguration = "Debug">
|
||||
</AnalyzeAction>
|
||||
<ArchiveAction
|
||||
buildConfiguration = "Release"
|
||||
revealArchiveInOrganizer = "YES">
|
||||
</ArchiveAction>
|
||||
</Scheme>
|
124
twigs-cli/TwigsCli.swift
Normal file
124
twigs-cli/TwigsCli.swift
Normal file
|
@ -0,0 +1,124 @@
|
|||
//
|
||||
// main.swift
|
||||
// twigs-cli
|
||||
//
|
||||
// Created by William Brawner on 1/6/22.
|
||||
// Copyright © 2022 William Brawner. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import ArgumentParser
|
||||
import TwigsCore
|
||||
|
||||
@main
|
||||
enum TwigsCli {
|
||||
static func main() async throws {
|
||||
await Twigs.main()
|
||||
}
|
||||
}
|
||||
|
||||
protocol AsyncParsableCommand: ParsableCommand {
|
||||
mutating func runAsync() async throws
|
||||
}
|
||||
|
||||
extension ParsableCommand {
|
||||
static func main() async {
|
||||
do {
|
||||
var command = try parseAsRoot(nil)
|
||||
if var asyncCommand = command as? AsyncParsableCommand {
|
||||
try await asyncCommand.runAsync()
|
||||
} else {
|
||||
try command.run()
|
||||
}
|
||||
} catch {
|
||||
exit(withError: error)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct Twigs: ParsableCommand {
|
||||
static var configuration = CommandConfiguration(
|
||||
commandName: "twigs-cli",
|
||||
abstract: "A CLI for Twigs, a personal finance application focused on individual and family budgeting",
|
||||
version: "1.0.0",
|
||||
subcommands: [Twigs.Auth.self]
|
||||
)
|
||||
}
|
||||
|
||||
extension Twigs {
|
||||
struct Auth: ParsableCommand {
|
||||
static var configuration = CommandConfiguration(
|
||||
abstract: "commands for authentication with a Twigs server",
|
||||
subcommands: [Twigs.Auth.Login.self]
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
extension Twigs.Auth {
|
||||
struct Login: AsyncParsableCommand {
|
||||
static var configuration = CommandConfiguration(
|
||||
abstract: "login with an existing account"
|
||||
)
|
||||
|
||||
@Option(name: [.short, .long], help: "")
|
||||
var token: String = ""
|
||||
|
||||
@Option(name: [.short, .long], parsing: SingleValueParsingStrategy.next, help: "the URL to the twigs server")
|
||||
var url: String = ""
|
||||
|
||||
mutating func runAsync() async throws {
|
||||
let config = Config(url: url, token: token)
|
||||
// TODO: Check if token was provided, if not check config file
|
||||
if let token = await config.token, !token.isEmpty {
|
||||
print("using token for login")
|
||||
// TODO: Save token to disk
|
||||
return
|
||||
}
|
||||
print("Username:", terminator: " ")
|
||||
if let input = readLine(), !input.isEmpty {
|
||||
await config.setUsername(input)
|
||||
} else {
|
||||
throw TwigsErrors.input("ERROR: Username cannot be empty")
|
||||
}
|
||||
guard let passChars = getpass("Password: ") else {
|
||||
throw TwigsErrors.input("ERROR: Unable to read password")
|
||||
}
|
||||
let password = String(cString: passChars)
|
||||
if password.isEmpty {
|
||||
throw TwigsErrors.input("ERROR: Password cannot be empty")
|
||||
}
|
||||
await config.setPassword(password)
|
||||
if let username = await config.username, let password = await config.password {
|
||||
print("Logging in as \(username) with password \(password)")
|
||||
let apiService = TwigsApiService()
|
||||
apiService.baseUrl = await config.url
|
||||
try await apiService.login(username: username, password: password)
|
||||
// TODO: Persist url and token in config file
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
actor Config {
|
||||
var url: String? = nil
|
||||
var username: String? = nil
|
||||
var password: String? = nil
|
||||
var token: String? = nil
|
||||
|
||||
init(url: String? = nil, token: String? = nil) {
|
||||
self.url = url
|
||||
self.token = token
|
||||
}
|
||||
|
||||
func setUsername(_ username: String) {
|
||||
self.username = username
|
||||
}
|
||||
|
||||
func setPassword(_ password: String) {
|
||||
self.password = password
|
||||
}
|
||||
}
|
||||
|
||||
enum TwigsErrors: Error {
|
||||
case input(String)
|
||||
}
|
Loading…
Reference in a new issue