Skip to content

Commit

Permalink
Event Importer (Meetup + Eventbrite) along with Events Api + Org Api (#…
Browse files Browse the repository at this point in the history
…186)

* Events + Org Api

* Support for tags and event date filtering

* style

* tests

* Update CancelEventCommandTest.php

* event_id's no longer needed

* Update ImportEventForOrganization.php

* Fix cast of service_id and add .env.example for EventBrite API token

* Use event sales status instead of looking at json ld

* Update EventBriteHandler.php

* Update EventBriteHandler.php

* Tag support, resolve PR comments

* Add support for tag filtering

* Update EventApiV0Controller.php

* Change Schedule

* composer.json tweaks

* Remove stripe

* Ensure longitude is passed correctly

* Use date_format

* Add modules to tests

* Org tag filter

* Update EventApiV0Controller.php

* Update EventApiV0Controller.php

* Add api middleware

* Add support for data import thresholds

* style

* Update .env.example

Co-authored-by: Matthew Thornton <[email protected]>

* Default days

* Update EventApiV0Controller.php

* Change attr name for Eventbrite cancellation check

* Adjust EventFactory

* Fix MeetupRestTest

---------

Co-authored-by: Matthew Thornton <[email protected]>
  • Loading branch information
bogdankharchenko and ThorntonMatthewD authored Dec 10, 2023
1 parent bada332 commit 8442dc5
Show file tree
Hide file tree
Showing 66 changed files with 3,204 additions and 413 deletions.
7 changes: 7 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -50,3 +50,10 @@ GOOGLE_TAG_MANAGER=
HCAPTCHA_SITEKEY=
HCAPTCHA_SECRET=
SLACK_CONTACT_WEBHOOK=

EVENTBRITE_PRIVATE_TOKEN=

EVENT_IMPORTER_MAX_DAYS_IN_PAST=30
EVENT_IMPORTER_MAX_DAYS_IN_FUTURE=180

EVENTS_API_DEFAULT_DAYS=1
26 changes: 26 additions & 0 deletions app-modules/api/composer.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
{
"name": "hack-greenville/api",
"description": "",
"type": "library",
"version": "1.0",
"license": "proprietary",
"require": {},
"autoload": {
"psr-4": {
"HackGreenville\\Api\\": "src/"
}
},
"autoload-dev": {
"psr-4": {
"HackGreenville\\Api\\Tests\\": "tests/"
}
},
"minimum-stability": "stable",
"extra": {
"laravel": {
"providers": [
"HackGreenville\\Api\\Providers\\ApiServiceProvider"
]
}
}
}
11 changes: 11 additions & 0 deletions app-modules/api/routes/api-routes.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<?php

use HackGreenville\Api\Http\Controllers\EventApiV0Controller;
use HackGreenville\Api\Http\Controllers\OrgsApiV0Controller;

Route::middleware('api')
->prefix('api/')
->group(function () {
Route::get('v0/events', EventApiV0Controller::class)->name('api.v0.events.index');
Route::get('v0/orgs', OrgsApiV0Controller::class)->name('api.v0.orgs.index');
});
34 changes: 34 additions & 0 deletions app-modules/api/src/Http/Controllers/EventApiV0Controller.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
<?php

namespace HackGreenville\Api\Http\Controllers;

use App\Models\Event;
use HackGreenville\Api\Http\Requests\EventApiV0Request;
use HackGreenville\Api\Resources\Events\V0\EventCollection;
use Illuminate\Database\Eloquent\Builder;

class EventApiV0Controller
{
public function __invoke(EventApiV0Request $request)
{
return new EventCollection(
resource: Event::query()
->when($request->filled('start_date'), function (Builder $query) use ($request) {
$query->where('active_at', '>=', $request->date('start_date'));
})
->when($request->filled('end_date'), function (Builder $query) use ($request) {
$query->where('active_at', '<=', $request->date('end_date'));
})
->when($request->filled('tags'), function (Builder $query) use ($request) {
$query->whereHas('organization.tags', function (Builder $query) use ($request) {
$query->where('id', $request->integer('tags'));
});
})
->when($request->isNotFilled(['start_date', 'end_date']), function (Builder $query) {
$query->where('active_at', '>=', now()->subDays(config('events-api.default_days')));
})
->oldest('active_at')
->get()
);
}
}
25 changes: 25 additions & 0 deletions app-modules/api/src/Http/Controllers/OrgsApiV0Controller.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
<?php

namespace HackGreenville\Api\Http\Controllers;

use App\Http\Controllers\Controller;
use App\Models\Org;
use HackGreenville\Api\Http\Requests\OrgsApiV0Request;
use HackGreenville\Api\Resources\Orgs\V0\OrganizationsCollection;
use Illuminate\Database\Eloquent\Builder;

class OrgsApiV0Controller extends Controller
{
public function __invoke(OrgsApiV0Request $request)
{
return new OrganizationsCollection(
resource: Org::query()
->when($request->filled('tags'), function (Builder $query) use ($request) {
$query->whereHas('tags', function ($query) use ($request) {
$query->where('id', $request->integer('tags'));
});
})
->get()
);
}
}
32 changes: 32 additions & 0 deletions app-modules/api/src/Http/Requests/EventApiV0Request.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
<?php

namespace HackGreenville\Api\Http\Requests;

use Illuminate\Foundation\Http\FormRequest;

class EventApiV0Request extends FormRequest
{
public function authorize()
{
return true;
}

public function rules()
{
return [
'start_date' => [
'nullable',
'sometimes',
'date_format:Y-m-d',
'before_or_equal:end_date',
],
'end_date' => [
'nullable',
'sometimes',
'date',
'date_format:Y-m-d',
'after_or_equal:start_date',
],
];
}
}
24 changes: 24 additions & 0 deletions app-modules/api/src/Http/Requests/OrgsApiV0Request.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
<?php

namespace HackGreenville\Api\Http\Requests;

use Illuminate\Foundation\Http\FormRequest;

class OrgsApiV0Request extends FormRequest
{
public function authorize()
{
return true;
}

public function rules()
{
return [
'tags' => [
'nullable',
'sometimes',
'integer',
],
];
}
}
16 changes: 16 additions & 0 deletions app-modules/api/src/Providers/ApiServiceProvider.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<?php

namespace HackGreenville\Api\Providers;

use Illuminate\Support\ServiceProvider;

class ApiServiceProvider extends ServiceProvider
{
public function register()
{
}

public function boot()
{
}
}
21 changes: 21 additions & 0 deletions app-modules/api/src/Resources/Events/V0/EventCollection.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
<?php

namespace HackGreenville\Api\Resources\Events\V0;

use Illuminate\Http\Request;
use Illuminate\Http\Resources\Json\ResourceCollection;

/**
* This exists merely to handle legacy events api.
*/
class EventCollection extends ResourceCollection
{
public static $wrap = null;

public $collects = EventResource::class;

public function toArray(Request $request): array
{
return $this->collection->toArray();
}
}
34 changes: 34 additions & 0 deletions app-modules/api/src/Resources/Events/V0/EventResource.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
<?php

namespace HackGreenville\Api\Resources\Events\V0;

use App\Models\Event;
use Illuminate\Http\Request;
use Illuminate\Http\Resources\Json\JsonResource;

class EventResource extends JsonResource
{
/** @var Event $resource */
public $resource;

public function toArray(Request $request): array
{
return [
'event_name' => $this->resource->event_name,
'group_name' => $this->resource->group_name,
'group_url' => $this->resource->organization->home_page,
'url' => $this->resource->url,
'time' => $this->resource->active_at->toISOString(),
'tags' => $this->resource->organization->tags->first()?->id ?? '',
'status' => $this->resource->getStatusAttribute(),
'rsvp_count' => $this->resource->rsvp_count,
'description' => $this->resource->description,
'uuid' => $this->resource->event_uuid,
'data_as_of' => now()->toISOString(),
'service_id' => $this->resource->service_id,
'service' => $this->resource->service,
'venue' => new VenueResource($this->resource->venue),
'created_at' => $this->resource->created_at->toISOString(),
];
}
}
27 changes: 27 additions & 0 deletions app-modules/api/src/Resources/Events/V0/VenueResource.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
<?php

namespace HackGreenville\Api\Resources\Events\V0;

use App\Models\Venue;
use Illuminate\Http\Request;
use Illuminate\Http\Resources\Json\JsonResource;

class VenueResource extends JsonResource
{
/** @var Venue $resource */
public $resource;

public function toArray(Request $request): array
{
return [
'name' => $this->resource->name,
'address' => $this->resource->address,
'city' => $this->resource->city,
'state' => $this->resource->state->abbr,
'zip' => $this->resource->zipcode,
'country' => $this->resource->country,
'lat' => $this->resource->lat,
'lon' => $this->resource->lng,
];
}
}
34 changes: 34 additions & 0 deletions app-modules/api/src/Resources/Orgs/V0/OrgResource.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
<?php

namespace HackGreenville\Api\Resources\Orgs\V0;

use App\Models\Org;
use Illuminate\Http\Request;
use Illuminate\Http\Resources\Json\JsonResource;

class OrgResource extends JsonResource
{
/** @var Org $resource */
public $resource;

public function toArray(Request $request): array
{
return [
'title' => $this->resource->title,
'path' => $this->resource->path,
'changed' => $this->resource->updated_at->toISOString(),
'field_city' => $this->resource->city,
'field_event_service' => $this->resource->service,
'field_events_api_key' => $this->resource->service_api_key,
'field_focus_area' => $this->resource->focus_area,
'field_homepage' => $this->resource->home_page,
'field_event_calendar_homepage' => $this->resource->event_calendar_uri,
'field_primary_contact_person' => $this->resource->primary_contact_person,
'field_org_status' => $this->resource->status,
'field_organization_type' => $this->resource->organization_type,
'field_year_established' => $this->resource->established_at->year,
'field_org_tags' => $this->resource->tags->first()?->id ?? '',
'uuid' => $this->resource->id,
];
}
}
21 changes: 21 additions & 0 deletions app-modules/api/src/Resources/Orgs/V0/OrganizationsCollection.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
<?php

namespace HackGreenville\Api\Resources\Orgs\V0;

use Illuminate\Http\Request;
use Illuminate\Http\Resources\Json\ResourceCollection;

/**
* This exists merely to handle legacy events api.
*/
class OrganizationsCollection extends ResourceCollection
{
public $collects = OrgResource::class;

public static $wrap = null;

public function toArray(Request $request): array
{
return $this->collection->toArray();
}
}
55 changes: 55 additions & 0 deletions app-modules/api/tests/Feature/EventApiV0Test.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
<?php

namespace HackGreenville\Api\Tests\Feature;

use App\Models\Event;
use App\Models\Tag;
use Tests\DatabaseTestCase;

class EventApiV0Test extends DatabaseTestCase
{
public function test_event_api_v0_return_correct_data(): void
{
// Lock-in the time
$this->travelTo(now());

$event = Event::factory()->create([
'cancelled_at' => now(),
]);

$tag = Tag::factory()->create();

$event->organization->tags()->attach($tag->id);

$this->getJson(route('api.v0.events.index'))
->assertSessionDoesntHaveErrors()
->assertExactJson([
[
'event_name' => $event->event_name,
'group_name' => $event->group_name,
'group_url' => $event->organization->home_page,
'url' => $event->url,
'time' => $event->active_at->toISOString(),
'tags' => $event->organization->tags->first()->id,
'rsvp_count' => $event->rsvp_count,
'created_at' => $event->created_at->toISOString(),
'description' => $event->description,
'uuid' => $event->event_uuid,
'data_as_of' => now()->toISOString(),
'status' => 'cancelled',
'service_id' => $event->service_id,
'service' => $event->service->value,
'venue' => [
'name' => $event->venue->name,
'address' => $event->venue->address,
'city' => $event->venue->city,
'state' => $event->venue->state->abbr,
'zip' => $event->venue->zipcode,
'country' => $event->venue->country,
'lat' => $event->venue->lat,
'lon' => $event->venue->lng,
],
],
]);
}
}
Loading

0 comments on commit 8442dc5

Please sign in to comment.