Skip to content

Commit 2f8fea6

Browse files
committed
Added property list impl.
1 parent cc878b3 commit 2f8fea6

File tree

7 files changed

+271
-62
lines changed

7 files changed

+271
-62
lines changed

Sources/MultiUser/Model/User.swift

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
//
2+
// User.swift
3+
//
4+
//
5+
// Created by Sascha Müllner on 29.02.20.
6+
//
7+
8+
import Foundation
9+
10+
struct User : Codable {
11+
private var uuid:UUID
12+
13+
var username: String?
14+
var firstname: String?
15+
var lastname: String?
16+
var birthday: Date?
17+
var emails: [String]?
18+
var attributes: [String: String]?
19+
var icon: Data?
20+
var data: [Data]?
21+
22+
init() {
23+
self.uuid = UUID()
24+
}
25+
26+
init(from decoder: Decoder) throws {
27+
let values = try decoder.container(keyedBy: CodingKeys.self)
28+
self.uuid = try values.decode(UUID.self, forKey: .uuid)
29+
self.username = try values.decode(String.self, forKey: .username)
30+
self.firstname = try values.decode(String.self, forKey: .firstname)
31+
self.lastname = try values.decode(String.self, forKey: .lastname)
32+
self.birthday = try values.decode(Date.self, forKey: .birthday)
33+
self.emails = try values.decode([String].self, forKey: .emails)
34+
self.attributes = try values.decode([String: String].self, forKey: .attributes)
35+
self.icon = try values.decode(Data.self, forKey: .icon)
36+
self.data = try values.decode([Data].self, forKey: .data)
37+
}
38+
39+
func encode(to encoder: Encoder) throws {
40+
var container = encoder.container(keyedBy: CodingKeys.self)
41+
try container.encode(self.uuid, forKey: .uuid)
42+
try container.encode(self.username, forKey: .username)
43+
try container.encode(self.firstname, forKey: .firstname)
44+
try container.encode(self.lastname, forKey: .lastname)
45+
try container.encode(self.birthday, forKey: .birthday)
46+
try container.encode(self.emails, forKey: .emails)
47+
try container.encode(self.attributes, forKey: .attributes)
48+
try container.encode(self.icon, forKey: .icon)
49+
try container.encode(self.data, forKey: .data)
50+
}
51+
52+
var id: UUID {
53+
get {
54+
return self.uuid
55+
}
56+
}
57+
58+
private enum CodingKeys: String, CodingKey {
59+
case uuid, username, firstname, lastname, birthday, emails, attributes, icon, data
60+
}
61+
}
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
//
2+
// UserIndex.swift
3+
//
4+
//
5+
// Created by Sascha Müllner on 02.03.20.
6+
//
7+
8+
import Foundation
9+
10+
struct UserIndex : Codable {
11+
var currentUserUUID: UUID?
12+
13+
init() {
14+
}
15+
16+
init(from decoder: Decoder) throws {
17+
let values = try decoder.container(keyedBy: CodingKeys.self)
18+
self.currentUserUUID = try values.decode(UUID.self, forKey: .currentUserUUID)
19+
}
20+
21+
func encode(to encoder: Encoder) throws {
22+
var container = encoder.container(keyedBy: CodingKeys.self)
23+
try container.encode(self.currentUserUUID, forKey: .currentUserUUID)
24+
}
25+
26+
private enum CodingKeys: String, CodingKey {
27+
case currentUserUUID
28+
}
29+
}
Lines changed: 147 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,147 @@
1+
//
2+
// PropertyListUserRepository.swift
3+
//
4+
//
5+
// Created by Sascha Müllner on 02.03.20.
6+
//
7+
8+
import Foundation
9+
10+
class PropertyListUserRepository : UserRepositoryProtocol {
11+
12+
init() {
13+
do
14+
{
15+
try FileManager.default.createDirectory(atPath: usersDirectory.path, withIntermediateDirectories: true, attributes: nil)
16+
}
17+
catch let error as NSError
18+
{
19+
print("Unable to create directory \(error.debugDescription)")
20+
}
21+
}
22+
23+
func save(user: User) {
24+
let encoder = PropertyListEncoder()
25+
encoder.outputFormat = .xml
26+
do {
27+
guard let url = self.getURL(user: user) else {
28+
return
29+
}
30+
let data = try encoder.encode(user)
31+
try data.write(to: url)
32+
} catch {
33+
print(error)
34+
}
35+
}
36+
37+
func delete(user: User) {
38+
do
39+
{
40+
guard let url = self.getURL(user: user) else {
41+
return
42+
}
43+
try FileManager.default.removeItem(at: url)
44+
}
45+
catch let error as NSError
46+
{
47+
print("Unable to delete file \(error.debugDescription)")
48+
}
49+
}
50+
51+
var all: [User] {
52+
var users = [User]()
53+
for userURL in self.userURLs {
54+
guard let user = self.read(url: userURL) else {
55+
continue
56+
}
57+
users.append(user)
58+
}
59+
return users
60+
}
61+
62+
var current: User? {
63+
get {
64+
guard let currentUserUUID = self.userIndex?.currentUserUUID else {
65+
return nil
66+
}
67+
return self.read(userUUID: currentUserUUID)
68+
}
69+
set(user) {
70+
guard let userId = user?.id else {
71+
return
72+
}
73+
var userIndex = self.userIndex ?? UserIndex()
74+
userIndex.currentUserUUID = userId
75+
self.userIndex = userIndex
76+
}
77+
}
78+
79+
private func read(userUUID: UUID) -> User? {
80+
let userId = userUUID.uuidString
81+
let url = self.usersDirectory.appendingPathComponent(userId, isDirectory: false)
82+
return self.read(url: url)
83+
}
84+
85+
private func read(url: URL) -> User? {
86+
let path = url.path
87+
if FileManager.default.isReadableFile(atPath: path),
88+
let xml = FileManager.default.contents(atPath: path),
89+
let user = try? PropertyListDecoder().decode(User.self, from: xml)
90+
{
91+
return user
92+
}
93+
return nil
94+
}
95+
96+
private var usersDirectory :URL {
97+
get {
98+
let paths = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)
99+
let usersDirectory = paths[0].appendingPathComponent("users", isDirectory: true)
100+
return usersDirectory
101+
}
102+
}
103+
104+
private var userURLs :[URL] {
105+
get {
106+
do {
107+
return try FileManager.default.contentsOfDirectory(at: self.usersDirectory, includingPropertiesForKeys: nil, options: .skipsHiddenFiles)
108+
} catch {
109+
print("Error while enumerating files \(self.usersDirectory.path): \(error.localizedDescription)")
110+
}
111+
return []
112+
}
113+
}
114+
115+
private func getURL(user: User) -> URL? {
116+
let userId = user.id
117+
return self.usersDirectory.appendingPathComponent(userId.uuidString, isDirectory: false)
118+
}
119+
120+
private var usersIndexURL :URL {
121+
return self.usersDirectory.appendingPathComponent("users.idx", isDirectory: false)
122+
}
123+
124+
private var userIndex: UserIndex? {
125+
get {
126+
let path = self.usersIndexURL.path
127+
if FileManager.default.isReadableFile(atPath: path),
128+
let xml = FileManager.default.contents(atPath: path),
129+
let userIndex = try? PropertyListDecoder().decode(UserIndex.self, from: xml)
130+
{
131+
return userIndex
132+
}
133+
return nil
134+
}
135+
set(userIndex) {
136+
let encoder = PropertyListEncoder()
137+
encoder.outputFormat = .xml
138+
do {
139+
let url = self.usersIndexURL
140+
let data = try encoder.encode(userIndex)
141+
try data.write(to: url)
142+
} catch {
143+
print(error)
144+
}
145+
}
146+
}
147+
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
//
2+
// UserRepositoryProtocol.swift
3+
//
4+
//
5+
// Created by Sascha Müllner on 02.03.20.
6+
//
7+
8+
import Foundation
9+
10+
protocol UserRepositoryProtocol {
11+
func save(user: User)
12+
func delete(user: User)
13+
var all: [User] { get }
14+
var current: User? { get set }
15+
}
File renamed without changes.

Sources/MultiUser/User.swift

Lines changed: 0 additions & 51 deletions
This file was deleted.

Sources/MultiUser/UserService.swift

Lines changed: 19 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -9,39 +9,47 @@ import Foundation
99

1010
class UserService : UserServiceProtocol {
1111

12-
private var _currentUser :User?
12+
private var userRepository :UserRepositoryProtocol
13+
14+
public init(userRepository :UserRepositoryProtocol) {
15+
self.userRepository = userRepository
16+
}
17+
18+
public init() {
19+
self.userRepository = PropertyListUserRepository()
20+
}
1321

1422
func create() -> User {
1523
let user = User()
24+
self.userRepository.save(user: user)
1625
return user
1726
}
1827

1928
func save(user: User) {
20-
29+
self.userRepository.save(user: user)
2130
}
2231

2332
func delete(user: User) {
24-
33+
if(current?.id == user.id) {
34+
current = nil
35+
}
36+
self.userRepository.delete(user: user)
2537
}
2638

2739
var all: [User] {
28-
get {
29-
return []
30-
}
40+
return self.userRepository.all
3141
}
3242

3343
var hasUsers: Bool {
34-
get {
35-
return self.all.count > 0
36-
}
44+
return self.all.count > 0
3745
}
3846

3947
var current: User? {
4048
get {
41-
return _currentUser
49+
return self.userRepository.current
4250
}
4351
set(user) {
44-
_currentUser = user
52+
self.userRepository.current = user
4553
}
4654
}
4755
}

0 commit comments

Comments
 (0)