diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..f0cfb71 --- /dev/null +++ b/.gitignore @@ -0,0 +1,77 @@ +env.dart +.vscode + +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.buildlog/ +.history +.svn/ + +# IntelliJ related +*.iml +*.ipr +*.iws +.idea/ + +# The .vscode folder contains launch configuration and tasks you configure in +# VS Code which you may wish to be included in version control, so this line +# is commented out by default. +#.vscode/ + +# Flutter/Dart/Pub related +**/doc/api/ +.dart_tool/ +.flutter-plugins +.flutter-plugins-dependencies +.packages +.pub-cache/ +.pub/ +build/ + +# Android related +**/android/**/gradle-wrapper.jar +**/android/.gradle +**/android/captures/ +**/android/gradlew +**/android/gradlew.bat +**/android/local.properties +**/android/**/GeneratedPluginRegistrant.java + +# iOS/XCode related +**/ios/**/*.mode1v3 +**/ios/**/*.mode2v3 +**/ios/**/*.moved-aside +**/ios/**/*.pbxuser +**/ios/**/*.perspectivev3 +**/ios/**/*sync/ +**/ios/**/.sconsign.dblite +**/ios/**/.tags* +**/ios/**/.vagrant/ +**/ios/**/DerivedData/ +**/ios/**/Icon? +**/ios/**/Pods/ +**/ios/**/.symlinks/ +**/ios/**/profile +**/ios/**/xcuserdata +**/ios/.generated/ +**/ios/Flutter/App.framework +**/ios/Flutter/Flutter.framework +**/ios/Flutter/Flutter.podspec +**/ios/Flutter/Generated.xcconfig +**/ios/Flutter/app.flx +**/ios/Flutter/app.zip +**/ios/Flutter/flutter_assets/ +**/ios/Flutter/flutter_export_environment.sh +**/ios/ServiceDefinitions.json +**/ios/Runner/GeneratedPluginRegistrant.* + +# Exceptions to above rules. +!**/ios/**/default.mode1v3 +!**/ios/**/default.mode2v3 +!**/ios/**/default.pbxuser +!**/ios/**/default.perspectivev3 diff --git a/.metadata b/.metadata new file mode 100644 index 0000000..89d95f1 --- /dev/null +++ b/.metadata @@ -0,0 +1,10 @@ +# This file tracks properties of this Flutter project. +# Used by Flutter tool to assess capabilities and perform upgrades etc. +# +# This file should be version controlled and should not be manually edited. + +version: + revision: adc687823a831bbebe28bdccfac1a628ca621513 + channel: stable + +project_type: package diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..246aaca --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,11 @@ +# Changelog +## v0.0.1-prealpha1 +> Release date: 20/May/2021 + +* First version +* Add `page` requests parameters models +* Add notion api endpoints: `pages` + * Retrieve a page + * Create a page + * Note: Accept only basic content: `title` & `parent`. +* Add `database` tests \ No newline at end of file diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..ba75c69 --- /dev/null +++ b/LICENSE @@ -0,0 +1 @@ +TODO: Add your license here. diff --git a/README.md b/README.md new file mode 100644 index 0000000..a6b1593 --- /dev/null +++ b/README.md @@ -0,0 +1,26 @@ +Notion API client for dart. + +## Using +You only have to create a new instance of the NotionClient class and all the API requests will be available as class methods. +> Note: Maybe they will be separated onto separated classes, idk yet. +```dart +NotionClient notion = NotionClient(token: 'YOUR SECRET TOKEN FROM INTEGRATIONS PAGE'); +``` + +### Methods +`20/May/2021`: The methods return a `http.Response`. You can find how to use it in its [documentation][1]. + +#### Creating pages +```dart +Page page = Page(databaseId: 'YOUR DATABASE ID'); +page.title = Text(content: 'The title of the new page'); + +notion.createPage(page); +``` + +#### Retrieving pages +```dart +notion.retrievePage(test_page_id); +``` + +[1]:https://pub.dev/documentation/http/latest/http/Response-class.html \ No newline at end of file diff --git a/ROADMAP.md b/ROADMAP.md new file mode 100644 index 0000000..e37d5fe --- /dev/null +++ b/ROADMAP.md @@ -0,0 +1,39 @@ +# Roadmap +## v0.0.1-prealpha1: ✅ +> Release date: 20/May/2021 + +* First version +* Add `page` requests parameters models +* Add notion api endpoints: `pages` + * Retrieve a page + * Create a page + * Note: Accept only basic content: `title` & `parent`. +* Add `database` tests + +## v0.0.1-prealpha2: +> Release date: 24/May/2021 +* Return data response directly instead of `http.Response` +* Manage http calls errors + +## v0.0.1-prealpha3: +> Release date: 26/May/2021 +* Add `database` request parameters models +* Add notion api endpoints: `databases` + * Retrieve a database + * Query a database + * List databases +* Add `database` tests + +## v0.0.1-prealpha4: +> Release date: 28/May/2021 +* Add `block children` request parameters models +* Add notion api endpoints: `block children` + * Retrieve block children + * Append block children +* Add `block children` tests + +## v0.0.1-beta1: +> Release date: 28/May/2021 +* Improve testing + +### More coming soon. \ No newline at end of file diff --git a/lib/client.dart b/lib/client.dart new file mode 100644 index 0000000..db355ba --- /dev/null +++ b/lib/client.dart @@ -0,0 +1,34 @@ +library notion_api; + +import 'dart:convert'; + +import 'package:flutter/material.dart' show required; +import 'package:http/http.dart' as http; +import 'package:notion_api/models/pages.dart'; + +/// A Notion API. +class NotionClient { + String _token; + String _url = 'https://api.notion.com/v1'; + + NotionClient({@required token}) : this._token = token; + + Future retrievePage(String id) async { + return await http.get(Uri.parse('$_url/pages/$id'), headers: { + 'Authorization': 'Bearer $_token', + }); + } + + /// Create a new page + Future createPage(Page page) async { + return await http.post(Uri.parse('$_url/pages'), + body: jsonEncode(page.toJson()), + headers: { + 'Authorization': 'Bearer $_token', + 'Content-Type': 'application/json; charset=UTF-8', + }); + } + + /// Returns [value] plus 1. + int addOne(int value) => value + 1; +} diff --git a/lib/models/objects.dart b/lib/models/objects.dart new file mode 100644 index 0000000..77217ae --- /dev/null +++ b/lib/models/objects.dart @@ -0,0 +1,4 @@ +enum NotionObjects { + user, + database, +} diff --git a/lib/models/pages.dart b/lib/models/pages.dart new file mode 100644 index 0000000..709ded6 --- /dev/null +++ b/lib/models/pages.dart @@ -0,0 +1,41 @@ +import 'dart:convert'; + +import 'package:flutter/material.dart' show required; +import 'package:notion_api/models/rich_text.dart'; + +class Page { + final PageParent parent = PageParent(); + final PageProperties properties = PageProperties(); + final PageChildren children = PageChildren(); + + Page({@required databaseId}) { + this.parent.databaseId = databaseId; + } + + set title(RichText value) => properties.title.add(value ?? Text(content: '')); + + Map toJson() => { + 'parent': this.parent.toJson(), + 'properties': this.properties.toJson(), + }; +} + +class PageParent { + String databaseId; + + toJson() => { + 'database_id': databaseId, + }; +} + +class PageProperties { + List title = []; + + toJson() => { + 'title': { + 'title': title.map((e) => e.toJson()).toList(), + }, + }; +} + +class PageChildren {} diff --git a/lib/models/rich_text.dart b/lib/models/rich_text.dart new file mode 100644 index 0000000..fd2c96a --- /dev/null +++ b/lib/models/rich_text.dart @@ -0,0 +1,70 @@ +import 'package:notion_api/models/users.dart'; + +enum RichTextType { + mention, + text, + equation, + url, +} + +enum RichTextColors { + gray, + brown, + orange, + yellow, +} + +class RichTextAnnotations { + bool bold; + bool italic; + bool strikethrough; + bool underline; + bool code; + RichTextColors color; +} + +class RichText { + String plainText; + String href; + RichTextAnnotations annotations; + RichTextType type; + + toJson() => { + 'plain_text': plainText, + 'href': href, + 'annotations': annotations, + 'type': type, + }; +} + +class Text extends RichText { + String content; + + Text({content}) : this.content = content; + + toJson() { + Map json = super.toJson(); + json['text'] = { + 'content': content, + }; + json.removeWhere((key, value) => value == null); + return json; + } +} + +class Link extends Text { + RichTextType type = RichTextType.url; + String url; +} + +class Mention extends RichText { + RichTextType type = RichTextType.mention; +} + +class UserMention extends Mention { + PeopleUser user; +} + +class Equation extends RichText { + String expression; +} diff --git a/lib/models/users.dart b/lib/models/users.dart new file mode 100644 index 0000000..fdf3db4 --- /dev/null +++ b/lib/models/users.dart @@ -0,0 +1,24 @@ +import 'package:notion_api/models/objects.dart'; + +enum UserType { + person, + bot, +} + +class User { + NotionObjects object = NotionObjects.user; + String id; + UserType type; + String name; + String avatar_url; +} + +class _People { + String email; +} + +class PeopleUser extends User { + _People people; +} + +class BotUser extends User {} diff --git a/pubspec.lock b/pubspec.lock new file mode 100644 index 0000000..34b2850 --- /dev/null +++ b/pubspec.lock @@ -0,0 +1,168 @@ +# Generated by pub +# See https://dart.dev/tools/pub/glossary#lockfile +packages: + async: + dependency: transitive + description: + name: async + url: "https://pub.dartlang.org" + source: hosted + version: "2.5.0" + boolean_selector: + dependency: transitive + description: + name: boolean_selector + url: "https://pub.dartlang.org" + source: hosted + version: "2.1.0" + characters: + dependency: transitive + description: + name: characters + url: "https://pub.dartlang.org" + source: hosted + version: "1.1.0" + charcode: + dependency: transitive + description: + name: charcode + url: "https://pub.dartlang.org" + source: hosted + version: "1.2.0" + clock: + dependency: transitive + description: + name: clock + url: "https://pub.dartlang.org" + source: hosted + version: "1.1.0" + collection: + dependency: transitive + description: + name: collection + url: "https://pub.dartlang.org" + source: hosted + version: "1.15.0" + fake_async: + dependency: transitive + description: + name: fake_async + url: "https://pub.dartlang.org" + source: hosted + version: "1.2.0" + flutter: + dependency: "direct main" + description: flutter + source: sdk + version: "0.0.0" + flutter_test: + dependency: "direct dev" + description: flutter + source: sdk + version: "0.0.0" + http: + dependency: "direct main" + description: + name: http + url: "https://pub.dartlang.org" + source: hosted + version: "0.13.3" + http_parser: + dependency: transitive + description: + name: http_parser + url: "https://pub.dartlang.org" + source: hosted + version: "4.0.0" + matcher: + dependency: transitive + description: + name: matcher + url: "https://pub.dartlang.org" + source: hosted + version: "0.12.10" + meta: + dependency: transitive + description: + name: meta + url: "https://pub.dartlang.org" + source: hosted + version: "1.3.0" + path: + dependency: transitive + description: + name: path + url: "https://pub.dartlang.org" + source: hosted + version: "1.8.0" + pedantic: + dependency: transitive + description: + name: pedantic + url: "https://pub.dartlang.org" + source: hosted + version: "1.11.0" + sky_engine: + dependency: transitive + description: flutter + source: sdk + version: "0.0.99" + source_span: + dependency: transitive + description: + name: source_span + url: "https://pub.dartlang.org" + source: hosted + version: "1.8.0" + stack_trace: + dependency: transitive + description: + name: stack_trace + url: "https://pub.dartlang.org" + source: hosted + version: "1.10.0" + stream_channel: + dependency: transitive + description: + name: stream_channel + url: "https://pub.dartlang.org" + source: hosted + version: "2.1.0" + string_scanner: + dependency: transitive + description: + name: string_scanner + url: "https://pub.dartlang.org" + source: hosted + version: "1.1.0" + term_glyph: + dependency: transitive + description: + name: term_glyph + url: "https://pub.dartlang.org" + source: hosted + version: "1.2.0" + test_api: + dependency: transitive + description: + name: test_api + url: "https://pub.dartlang.org" + source: hosted + version: "0.2.19" + typed_data: + dependency: transitive + description: + name: typed_data + url: "https://pub.dartlang.org" + source: hosted + version: "1.3.0" + vector_math: + dependency: transitive + description: + name: vector_math + url: "https://pub.dartlang.org" + source: hosted + version: "2.1.0" +sdks: + dart: ">=2.12.0 <3.0.0" + flutter: ">=1.17.0" diff --git a/pubspec.yaml b/pubspec.yaml new file mode 100644 index 0000000..b045748 --- /dev/null +++ b/pubspec.yaml @@ -0,0 +1,54 @@ +name: notion_api +description: Notion API client for dart. +version: 0.0.1-prealpha1 +author: Jonathan Gómez + +environment: + sdk: ">=2.7.0 <3.0.0" + flutter: ">=1.17.0" + +dependencies: + flutter: + sdk: flutter + http: ^0.13.3 + +dev_dependencies: + flutter_test: + sdk: flutter + +# For information on the generic Dart part of this file, see the +# following page: https://dart.dev/tools/pub/pubspec + +# The following section is specific to Flutter. +flutter: + + # To add assets to your package, add an assets section, like this: + # assets: + # - images/a_dot_burr.jpeg + # - images/a_dot_ham.jpeg + # + # For details regarding assets in packages, see + # https://flutter.dev/assets-and-images/#from-packages + # + # An image asset can refer to one or more resolution-specific "variants", see + # https://flutter.dev/assets-and-images/#resolution-aware. + + # To add custom fonts to your package, add a fonts section here, + # in this "flutter" section. Each entry in this list should have a + # "family" key with the font family name, and a "fonts" key with a + # list giving the asset and other descriptors for the font. For + # example: + # fonts: + # - family: Schyler + # fonts: + # - asset: fonts/Schyler-Regular.ttf + # - asset: fonts/Schyler-Italic.ttf + # style: italic + # - family: Trajan Pro + # fonts: + # - asset: fonts/TrajanPro.ttf + # - asset: fonts/TrajanPro_Bold.ttf + # weight: 700 + # + # For details regarding fonts in packages, see + # https://flutter.dev/custom-fonts/#from-packages diff --git a/test/notion_api_test.dart b/test/notion_api_test.dart new file mode 100644 index 0000000..b5d58cf --- /dev/null +++ b/test/notion_api_test.dart @@ -0,0 +1,27 @@ +import 'package:flutter_test/flutter_test.dart'; +import 'package:notion_api/models/pages.dart'; +import 'package:notion_api/models/rich_text.dart'; +import 'package:notion_api/client.dart'; + +import '../env.dart'; + +void main() { + group('Pages', () { + test('Create a page', () async { + final NotionClient notion = NotionClient(token: token); + + final Page page = Page(databaseId: test_database_id); + page.title = Text(content: 'Page from Test'); + + var res = await notion.createPage(page); + + expect(res.statusCode, 200); + }); + + test('Retrieve a page', () async { + final NotionClient notion = NotionClient(token: token); + var res = await notion.retrievePage(test_page_id); + expect(res.statusCode, 200); + }); + }); +}