Skip to content

Commit a3b4de6

Browse files
authored
Merge pull request #27 from codeccoop/feat/airtable
Airtable add-on
2 parents 8c01c42 + 81cfebb commit a3b4de6

File tree

18 files changed

+1587
-10
lines changed

18 files changed

+1587
-10
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ Forms Bridge has the following add-ons:
5858

5959
**🗓️ Productivity**
6060

61+
- [Airtable](https://formsbridge.codeccoop.org/documentation/airtable)
6162
- [Google Calendar](https://formsbridge.codeccoop.org/documentation/google-calendar/)
6263
- [Google Sheets](https://formsbridge.codeccoop.org/documentation/google-sheets/)
6364
- [Nextcloud](https://formsbridge.codeccoop.org/documentation/nextcloud/)
7.25 KB
Loading
Lines changed: 229 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,229 @@
1+
<?php
2+
/**
3+
* Class Airtable_Addon
4+
*
5+
* @package formsbridge
6+
*/
7+
8+
namespace FORMS_BRIDGE;
9+
10+
use FBAPI;
11+
use WP_Error;
12+
13+
if ( ! defined( 'ABSPATH' ) ) {
14+
exit();
15+
}
16+
17+
require_once 'class-airtable-form-bridge.php';
18+
require_once 'hooks.php';
19+
20+
/**
21+
* Airtable addon class.
22+
*/
23+
class Airtable_Addon extends Addon {
24+
25+
/**
26+
* Handles the addon's title.
27+
*
28+
* @var string
29+
*/
30+
const TITLE = 'Airtable';
31+
32+
/**
33+
* Handles the addon's name.
34+
*
35+
* @var string
36+
*/
37+
const NAME = 'airtable';
38+
39+
/**
40+
* Handles the addon's custom bridge class.
41+
*
42+
* @var string
43+
*/
44+
const BRIDGE = '\FORMS_BRIDGE\Airtable_Form_Bridge';
45+
46+
/**
47+
* Performs a request against the backend to check the connection status.
48+
*
49+
* @param string $backend Backend name.
50+
*
51+
* @return boolean
52+
*/
53+
public function ping( $backend ) {
54+
$bridge = new Airtable_Form_Bridge(
55+
array(
56+
'name' => '__airtable-' . time(),
57+
'backend' => $backend,
58+
'endpoint' => '/v0/meta/bases',
59+
'method' => 'GET',
60+
)
61+
);
62+
63+
$response = $bridge->submit();
64+
if ( is_wp_error( $response ) ) {
65+
Logger::log( 'Airtable backend ping error: Unable to recover the credential access token', Logger::ERROR );
66+
return false;
67+
}
68+
69+
return true;
70+
}
71+
72+
/**
73+
* Performs a GET request against the backend endpoint and retrive the response data.
74+
*
75+
* @param string $endpoint Airtable endpoint.
76+
* @param string $backend Backend name.
77+
*
78+
* @return array|WP_Error
79+
*/
80+
public function fetch( $endpoint, $backend ) {
81+
$bridge = new Airtable_Form_Bridge(
82+
array(
83+
'name' => '__airtable-meta-bases',
84+
'backend' => $backend,
85+
'endpoint' => '/v0/meta/bases',
86+
'method' => 'GET',
87+
),
88+
);
89+
90+
$response = $bridge->submit();
91+
92+
if ( is_wp_error( $response ) ) {
93+
return $response;
94+
}
95+
96+
$tables = array();
97+
foreach ( $response['data']['bases'] as $base ) {
98+
$schema_response = $bridge->patch( array( 'endpoint' => "/v0/meta/bases/{$base['id']}/tables" ) )
99+
->submit();
100+
101+
if ( is_wp_error( $schema_response ) ) {
102+
return $schema_response;
103+
}
104+
105+
foreach ( $schema_response['data']['tables'] as $table ) {
106+
$tables[] = array(
107+
'base_id' => $base['id'],
108+
'base_name' => $base['name'],
109+
'label' => "{$base['name']}/{$table['name']}",
110+
'name' => $table['name'],
111+
'id' => $table['id'],
112+
'endpoint' => "/v0/{$base['id']}/{$table['name']}",
113+
);
114+
}
115+
}
116+
117+
return array( 'data' => array( 'tables' => $tables ) );
118+
}
119+
120+
/**
121+
* Performs an introspection of the backend API and returns a list of available endpoints.
122+
*
123+
* @param string $backend Target backend name.
124+
* @param string|null $method HTTP method.
125+
*
126+
* @return array|WP_Error
127+
*/
128+
public function get_endpoints( $backend, $method = null ) {
129+
$response = $this->fetch( null, $backend );
130+
131+
if ( is_wp_error( $response ) ) {
132+
return array();
133+
}
134+
135+
$endpoints = array();
136+
foreach ( $response['data']['tables'] as $table ) {
137+
$endpoints[] = $table['endpoint'];
138+
}
139+
140+
return $endpoints;
141+
}
142+
143+
/**
144+
* Performs an introspection of the backend endpoint and returns API fields
145+
* and accepted content type.
146+
*
147+
* @param string $endpoint Airtable endpoint.
148+
* @param string $backend Backend name.
149+
* @param string|null $method HTTP method.
150+
*
151+
* @return array List of fields and content type of the endpoint.
152+
*/
153+
public function get_endpoint_schema( $endpoint, $backend, $method = null ) {
154+
if ( 'POST' !== $method ) {
155+
return array();
156+
}
157+
158+
$bridge = new Airtable_Form_Bridge(
159+
array(
160+
'name' => '__airtable-endpoint-schema',
161+
'method' => 'GET',
162+
'backend' => $backend,
163+
'endpoint' => $endpoint,
164+
)
165+
);
166+
167+
$fields = $bridge->get_fields();
168+
169+
if ( is_wp_error( $fields ) ) {
170+
return array();
171+
}
172+
173+
$schema = array();
174+
foreach ( $fields as $field ) {
175+
if (
176+
in_array(
177+
$field['type'],
178+
array(
179+
'aiText',
180+
'formula',
181+
'autoNumber',
182+
'button',
183+
'count',
184+
'createdBy',
185+
'createdTime',
186+
'lastModifiedBy',
187+
'lastModifiedTime',
188+
'rollup',
189+
'externalSyncSource',
190+
'multipleCollaborators',
191+
'multipleLookupValues',
192+
'multipleRecordLinks',
193+
),
194+
true,
195+
)
196+
) {
197+
continue;
198+
}
199+
200+
switch ( $field['type'] ) {
201+
case 'rating':
202+
case 'number':
203+
$type = 'number';
204+
break;
205+
case 'checkbox':
206+
$type = 'boolean';
207+
break;
208+
case 'multipleSelects':
209+
$type = 'array';
210+
break;
211+
case 'multipleAttachments':
212+
$type = 'file';
213+
break;
214+
default:
215+
$type = 'string';
216+
break;
217+
}
218+
219+
$schema[] = array(
220+
'name' => $field['name'],
221+
'schema' => array( 'type' => $type ),
222+
);
223+
}
224+
225+
return $schema;
226+
}
227+
}
228+
229+
Airtable_Addon::setup();

0 commit comments

Comments
 (0)