From 1613c951d49e6d85aff52f312d57fa087b35c079 Mon Sep 17 00:00:00 2001 From: Ruben Beltran del Rio Date: Wed, 10 Sep 2025 22:48:37 +0200 Subject: Move things URL calls to a helper --- QSThingsPlugin/Helpers/KeychainHelper.h | 7 ---- QSThingsPlugin/Helpers/KeychainHelper.m | 7 ---- QSThingsPlugin/Helpers/ThingsHelper.h | 34 ++++++++++++++++ QSThingsPlugin/Helpers/ThingsHelper.m | 70 +++++++++++++++++++++++++++++++++ 4 files changed, 104 insertions(+), 14 deletions(-) create mode 100644 QSThingsPlugin/Helpers/ThingsHelper.h create mode 100644 QSThingsPlugin/Helpers/ThingsHelper.m (limited to 'QSThingsPlugin/Helpers') diff --git a/QSThingsPlugin/Helpers/KeychainHelper.h b/QSThingsPlugin/Helpers/KeychainHelper.h index d935bec..3665377 100644 --- a/QSThingsPlugin/Helpers/KeychainHelper.h +++ b/QSThingsPlugin/Helpers/KeychainHelper.h @@ -1,10 +1,3 @@ -// -// KeychainHelper.h -// Things Plugin -// -// Created by Ruben Beltran del Rio on 2025-09-10. -// - #import "Constants.h" #import #import diff --git a/QSThingsPlugin/Helpers/KeychainHelper.m b/QSThingsPlugin/Helpers/KeychainHelper.m index 9ce90f7..fcf8291 100644 --- a/QSThingsPlugin/Helpers/KeychainHelper.m +++ b/QSThingsPlugin/Helpers/KeychainHelper.m @@ -1,10 +1,3 @@ -// -// KeychainHelper.m -// Things Plugin -// -// Created by Ruben Beltran del Rio on 2025-09-10. -// - #import "KeychainHelper.h" NS_ASSUME_NONNULL_BEGIN diff --git a/QSThingsPlugin/Helpers/ThingsHelper.h b/QSThingsPlugin/Helpers/ThingsHelper.h new file mode 100644 index 0000000..29d3092 --- /dev/null +++ b/QSThingsPlugin/Helpers/ThingsHelper.h @@ -0,0 +1,34 @@ +#import "KeychainHelper.h" +#import "Constants.h" +#import + +NS_ASSUME_NONNULL_BEGIN + +/** + Enum of valid Things URL routes. + */ +typedef NSString* ThingsURLRoute NS_STRING_ENUM; + +extern ThingsURLRoute const ThingsURLRouteSearch; +extern ThingsURLRoute const ThingsURLRouteShow; +extern ThingsURLRoute const ThingsURLRouteUpdate; +extern ThingsURLRoute const ThingsURLRouteUpdateProject; +extern ThingsURLRoute const ThingsURLRouteAdd; +extern ThingsURLRoute const ThingsURLRouteAddProject; + +/** + Helper class to communicate with things using the URL API + */ +@interface ThingsHelper : NSObject + +/** + Calls a Things URL route with the specified parameters + @param route the Things URL route to call. Use ThingsURLRoute enum. + @param parameters NSDictionary of query parameters to include in the URL. Can be nil or empty. + @returns YES if the URL was successfully opened, NO if something went wrong. + */ ++ (BOOL)callRoute:(ThingsURLRoute)route withParameters:(NSDictionary *)parameters; + +@end + +NS_ASSUME_NONNULL_END diff --git a/QSThingsPlugin/Helpers/ThingsHelper.m b/QSThingsPlugin/Helpers/ThingsHelper.m new file mode 100644 index 0000000..cc7267b --- /dev/null +++ b/QSThingsPlugin/Helpers/ThingsHelper.m @@ -0,0 +1,70 @@ +#import "ThingsHelper.h" + +NS_ASSUME_NONNULL_BEGIN + +ThingsURLRoute const ThingsURLRouteSearch = @"search"; +ThingsURLRoute const ThingsURLRouteShow = @"show"; +ThingsURLRoute const ThingsURLRouteUpdate = @"update"; +ThingsURLRoute const ThingsURLRouteUpdateProject = @"update-project"; +ThingsURLRoute const ThingsURLRouteAdd = @"add"; +ThingsURLRoute const ThingsURLRouteAddProject = @"add-project"; + +@implementation ThingsHelper + ++ (instancetype)sharedInstance { + static ThingsHelper *sharedInstance = nil; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + sharedInstance = [[self alloc] init]; + }); + return sharedInstance; +} + ++ (BOOL)requiresAuthentication:(ThingsURLRoute)route { + if ([route isEqualToString:ThingsURLRouteSearch] || [route isEqualToString:ThingsURLRouteShow]) { + return NO; + } + return YES; +} + ++ (BOOL)callRoute:(ThingsURLRoute)route withParameters:(NSDictionary *)parameters { + NSString *authenticationKey = [KeychainHelper authenticationKey]; + if ([self requiresAuthentication:route] && !authenticationKey) { + NSLog(@"Attempted to call an authenticated things URL without an authentication key."); + return NO; + } + + NSString *baseURL = [NSString stringWithFormat:@"things:///%@", route]; + NSMutableArray *queryComponents = [NSMutableArray array]; + + if ([self requiresAuthentication:route]) { + [queryComponents addObject:[NSString stringWithFormat:@"auth-token=%@", authenticationKey]]; + } + + for (NSString *key in parameters) { + id value = parameters[key]; + NSString *encodedKey = [self urlEncodeString:key]; + NSString *encodedValue = [self urlEncodeString:[NSString stringWithFormat:@"%@", value]]; + [queryComponents addObject:[NSString stringWithFormat:@"%@=%@", encodedKey, encodedValue]]; + } + + NSString *urlString = baseURL; + if ([queryComponents count] > 0) { + urlString = [NSString stringWithFormat:@"%@?%@", baseURL, [queryComponents componentsJoinedByString:@"&"]]; + } + + NSURL *url = [NSURL URLWithString:urlString]; + + [[NSWorkspace sharedWorkspace] openURL:url]; + + return YES; +} + ++ (NSString *)urlEncodeString:(NSString *)string { + NSCharacterSet *allowedCharacters = [NSCharacterSet URLQueryAllowedCharacterSet]; + return [string stringByAddingPercentEncodingWithAllowedCharacters:allowedCharacters]; +} + +@end + +NS_ASSUME_NONNULL_END -- cgit