-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* fixes and new warnings (#7) * adding logo and starting documentation * renaming types and simplifying API * correct WordPressSite * fixing review issues * adding BaseURLSite --------- Co-authored-by: Ahmed Shendy <[email protected]>
- Loading branch information
1 parent
bff9c9c
commit 36ffc69
Showing
48 changed files
with
1,091 additions
and
631 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,3 @@ | ||
retain_public: true | ||
targets: | ||
- ContributeWordpress | ||
- ContributeWordPress |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1,136 @@ | ||
# ContributeWordPress | ||
Import your WordPress site into Publish | ||
<p align="center"> | ||
<img alt="ContributeWordPress" title="ContributeWordPress" src="Sources/ContributeWordPress/Documentation.docc/Resources/ContributeWordPressLogo.png" height="125"> | ||
</p> | ||
<h1 align="center">ContributeWordPress</h1> | ||
|
||
Import your WordPress site into Publish. | ||
|
||
[![SwiftPM](https://img.shields.io/badge/SPM-Linux%20%7C%20iOS%20%7C%20macOS%20%7C%20watchOS%20%7C%20tvOS-success?logo=swift)](https://swift.org) | ||
[![Twitter](https://img.shields.io/badge/[email protected]?style=flat)](http://twitter.com/brightdigit) | ||
![GitHub](https://img.shields.io/github/license/brightdigit/ContributeWordPress) | ||
![GitHub issues](https://img.shields.io/github/issues/brightdigit/ContributeWordPress) | ||
![GitHub Workflow Status](https://img.shields.io/github/actions/workflow/status/brightdigit/ContributeWordPress/ContributeWordPress.yml?label=actions&logo=github&?branch=main) | ||
|
||
[![](https://img.shields.io/endpoint?url=https%3A%2F%2Fswiftpackageindex.com%2Fapi%2Fpackages%2Fbrightdigit%2FContributeWordPress%2Fbadge%3Ftype%3Dswift-versions)](https://swiftpackageindex.com/brightdigit/ContributeWordPress) | ||
[![](https://img.shields.io/endpoint?url=https%3A%2F%2Fswiftpackageindex.com%2Fapi%2Fpackages%2Fbrightdigit%2FContributeWordPress%2Fbadge%3Ftype%3Dplatforms)](https://swiftpackageindex.com/brightdigit/ContributeWordPress) | ||
|
||
|
||
[![Codecov](https://img.shields.io/codecov/c/github/brightdigit/ContributeWordPress)](https://codecov.io/gh/brightdigit/ContributeWordPress) | ||
[![CodeFactor Grade](https://img.shields.io/codefactor/grade/github/brightdigit/ContributeWordPress)](https://www.codefactor.io/repository/github/brightdigit/ContributeWordPress) | ||
[![codebeat badge](https://codebeat.co/badges/54695d4b-98c8-4f0f-855e-215500163094)](https://codebeat.co/projects/github-com-brightdigit-ContributeWordPress-main) | ||
[![Code Climate maintainability](https://img.shields.io/codeclimate/maintainability/brightdigit/ContributeWordPress)](https://codeclimate.com/github/brightdigit/ContributeWordPress) | ||
[![Code Climate technical debt](https://img.shields.io/codeclimate/tech-debt/brightdigit/ContributeWordPress?label=debt)](https://codeclimate.com/github/brightdigit/ContributeWordPress) | ||
[![Code Climate issues](https://img.shields.io/codeclimate/issues/brightdigit/ContributeWordPress)](https://codeclimate.com/github/brightdigit/ContributeWordPress) | ||
[![Reviewed by Hound](https://img.shields.io/badge/Reviewed_by-Hound-8E64B0.svg)](https://houndci.com) | ||
|
||
# Table of Contents | ||
|
||
* [Introduction](#introduction) | ||
* [Requirements](#requirements) | ||
* [Installation](#installation) | ||
* [Usage](#usage) | ||
* [Further Documentation](#further-documentation) | ||
* [References](#references) | ||
* [License](#license) | ||
|
||
# Introduction | ||
|
||
**ContributeWordPress** provides an pluggable easy abstract layer for accessing Keychain data as well as an API for encoding and decoding complex data in the Keychain. | ||
|
||
## Requirements | ||
|
||
**Apple Platforms** | ||
|
||
- Xcode 14.3.1 or later | ||
- Swift 5.8 or later | ||
- iOS 14 / watchOS 7 / tvOS 14 / macOS 12 or later deployment targets | ||
|
||
**Linux** | ||
|
||
- Ubuntu 18.04 or later | ||
- Swift 5.8 or later | ||
|
||
## Installation | ||
|
||
Use the Swift Package Manager to install this library via the repository url: | ||
|
||
``` | ||
https://github.com/brightdigit/ContributeWordPress.git | ||
``` | ||
|
||
Use version up to `1.0`. | ||
|
||
# Usage | ||
|
||
## Accessing the Keychain like a Database | ||
|
||
**ContributeWordPress** supports the adding, updating, and querying for both generic and internet passwords. To do this you need to create a ``KeychainRepository`` to access the database to. | ||
|
||
``` | ||
let repository = KeychainRepository( | ||
defaultServiceName: "com.brightdigit.KeychainSyncDemo", | ||
defaultServerName: "com.brightdigit.KeychainSyncDemo", | ||
defaultAccessGroup: "MLT7M394S7.com.brightdigit.KeychainSyncDemo" | ||
) | ||
``` | ||
|
||
To call ``KeychainRepository.init(defaultServiceName:defaultServerName:defaultAccessGroup:defaultSynchronizable:logger:)`` you need to supply a the default ``InternetPasswordItem/server`` and ``GenericPasswordItem/service`` which is required by both types to query and create. | ||
|
||
> You can also supply a `logger` to use for logging as well as an ``InternetPasswordItem.accessGroup`` for your ``InternetPasswordItem`` and ``GenericPasswordItem.accessGroup`` for your ``GenericPasswordItem`` | ||
To query, update, or add a new password, check out the documentation under ``StealthyRepository``. | ||
|
||
## Using `StealthyModel` for Composite Objects | ||
|
||
In many cases, you may want to use multiple items to store a single object such as the user's password with ``InternetPasswordItem`` as well as their token via ``GenericPasswordItem``. In this case, you'll want to use a ``StealthyModel``: | ||
|
||
```swift | ||
struct CompositeCredentials: StealthyModel { | ||
typealias QueryBuilder = CompositeCredentialsQueryBuilder | ||
|
||
internal init(userName: String, password: String?, token: String?) { | ||
self.userName = userName | ||
self.password = password | ||
self.token = token | ||
} | ||
|
||
let userName: String | ||
|
||
let password: String? | ||
|
||
let token: String? | ||
} | ||
``` | ||
|
||
This is the perfect use case for ``StealthyModel`` and it only requires the implementation of a ``ModelQueryBuilder`` which defines how to build the queries for creating, updating, and deleting ``StealthyModel`` objects from the keychain: | ||
|
||
* ``ModelQueryBuilder.updates(from:to:)`` require you to build an array of ``StealthyPropertyUpdate`` object which define the previous and new properties for the Keychain. Both the previous and new are optional in case you are only adding a new item as part of the update or only removing an old item. | ||
|
||
* ``ModelQueryBuilder.properties(from:for:)`` is for creating a new model and requires the individual ``AnyStealthyProperty`` for each item to add to the keychain. | ||
|
||
* ``ModelQueryBuilder.model(from:)`` builds the ``StealthyModel`` based on the ``AnyStealthyProperty`` items | ||
|
||
* ``ModelQueryBuilder.queries(from:)`` builds a query dictionary depending the ``ModelQueryBuilder.QueryType`` passed. The keys to the query dictionary will be used by ``ModelQueryBuilder.model(from:)`` to define the keys of their resulting ``AnyStealthyProperty``. If there's only one object in your app, you can define ``ModelQueryBuilder.QueryType`` as `Void`: | ||
|
||
``` | ||
static func queries(from _: Void) -> [String: Query] { | ||
[ | ||
"password": TypeQuery(type: .internet), | ||
"token": TypeQuery(type: .generic) | ||
] | ||
} | ||
``` | ||
|
||
For more help, take a look at the [`Sample` projects located in the Swift Package.](https://github.com/brightdigit/ContributeWordPress/tree/main/Samples) | ||
|
||
## Further Documentation | ||
|
||
Further documentation is available at [the Swift Package Index.](https://swiftpackageindex.com/brightdigit/ContributeWordPress/1.0.0/documentation/ContributeWordPress) | ||
|
||
# References | ||
|
||
* [Using the Keychain to Manage User Secret](https://developer.apple.com/documentation/security/keychain_services/keychain_items/using_the_keychain_to_manage_user_secrets) | ||
|
||
# License | ||
|
||
This code is distributed under the MIT license. See the [LICENSE](https://github.com/brightdigit/ContributeWordPress/LICENSE) file for more info. |
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
import Foundation | ||
import SyndiKit | ||
|
||
/// A protocol representing a site with a base URL. | ||
internal protocol BaseURLSite { | ||
/// The main URL of the site. | ||
var link: URL { get } | ||
|
||
/// The base URL of the blog, if available. | ||
var baseBlogURL: URL? { get } | ||
} | ||
|
||
extension BaseURLSite { | ||
/// The base URL of the site. | ||
public var baseURL: URL { | ||
baseBlogURL ?? link | ||
} | ||
} |
20 changes: 20 additions & 0 deletions
20
Sources/ContributeWordPress/Decoder/SitesExportDecoder.swift
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
import Foundation | ||
import SyndiKit | ||
|
||
#if canImport(FoundationNetworking) | ||
import FoundationNetworking | ||
#endif | ||
|
||
/// A typealias that represents the section name for the blog | ||
public typealias SectionName = String | ||
|
||
/// A protocol for decoding WordPress sites from exports. | ||
public protocol SitesExportDecoder { | ||
/// Returns a dictionary of WordPress sites keyed by the filename of | ||
/// the export file as section name. | ||
/// | ||
/// - Parameter directoryURL: The URL of the directory containing the exports. | ||
/// - Returns: A dictionary of WordPress sites keyed by section name. | ||
/// - Throws: An error if sites couldn't be extracted from any of the export files. | ||
func sites(fromExportsAt directoryURL: URL) throws -> [SectionName: WordPressSite] | ||
} |
81 changes: 81 additions & 0 deletions
81
Sources/ContributeWordPress/Decoder/SitesExportSynDecoder.swift
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,81 @@ | ||
import Contribute | ||
import Foundation | ||
import SyndiKit | ||
|
||
#if canImport(FoundationNetworking) | ||
import FoundationNetworking | ||
#endif | ||
|
||
/// A type that decodes WordPress export files using the `SynDecoder`. | ||
public struct SitesExportSynDecoder: SitesExportDecoder { | ||
/// The decoder used to decode the WordPress export file. | ||
private let decoder: WordPressDecoder = SynDecoder() | ||
|
||
/// Returns an array of URLs for all of the files in the given directory. | ||
private let fileURLsFromDirectory: (URL) throws -> [URL] | ||
|
||
/// Returns the last path component of the given URL without its extension. | ||
/// This will be the section id for all posts found in the export file at given URL. | ||
private let keyFromURL: (URL) -> String | ||
|
||
public init( | ||
fileURLsFromDirectory: @escaping (URL) throws -> [URL] = | ||
Self.defaultFileURLs(atDirectory:), | ||
keyFromURL: @escaping (URL) -> String = { $0.lastPathComponentWithoutExtension() } | ||
) { | ||
self.fileURLsFromDirectory = fileURLsFromDirectory | ||
self.keyFromURL = keyFromURL | ||
} | ||
|
||
/// The method decodes `WordPressSite` from the given file URL. | ||
/// | ||
/// - Parameters: | ||
/// - url: The URL of export file containing the WordPress site with its posts. | ||
/// - decoder: The WordPress decoder. | ||
/// - Returns: The decoded WordPress site, or nil if decoding failed. | ||
/// - Throws: An error of site couldn't be decoded from the given file.. | ||
private static func siteFromURL( | ||
_ url: URL, | ||
using decoder: WordPressDecoder | ||
) throws -> WordPressSite? { | ||
let data = try Data(contentsOf: url) | ||
return try decoder.decodeSites(fromData: data, allowInvalidCharacters: true) | ||
} | ||
|
||
/// Returns a dictionary of WordPress sites keyed by filename. | ||
/// | ||
/// - Parameter directoryURL: The URL of the directory containing the exports. | ||
/// - Returns: A dictionary of WordPress sites keyed by section name. | ||
/// - Throws: An error if sites couldn't be extracted from any of the export files. | ||
public func sites( | ||
fromExportsAt directoryURL: URL | ||
) throws -> [SectionName: WordPressSite] { | ||
let files = try fileURLsFromDirectory(directoryURL) | ||
|
||
let feedPairs = try files.map { url -> (String, WordPressSite?) in | ||
try (self.keyFromURL(url), Self.siteFromURL(url, using: decoder)) | ||
} | ||
|
||
return Dictionary(uniqueKeysWithValues: feedPairs).compactMapValues { $0 } | ||
} | ||
} | ||
|
||
extension SitesExportSynDecoder { | ||
/// A default logic for finding all files found at given directory. | ||
/// | ||
/// - Parameter directoryURL: The directory URL. | ||
/// - Returns: An array of URLs for export files found in the given directory. | ||
public static func defaultFileURLs(atDirectory directoryURL: URL) -> [URL] { | ||
let enumerator = FileManager.default.enumerator( | ||
at: directoryURL, | ||
includingPropertiesForKeys: nil | ||
) | ||
|
||
guard let enumerator = enumerator else { | ||
assertionFailure("\(directoryURL) returned empty enumerator.") | ||
return [] | ||
} | ||
|
||
return enumerator.compactMap { $0 as? URL } | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.