EventPublisher Support for TagMaster events
This commit is contained in:
parent
31deb4cce8
commit
5ae4f20637
7 changed files with 189 additions and 3 deletions
|
@ -5,7 +5,7 @@
|
||||||
module Nonprofits
|
module Nonprofits
|
||||||
class TagMastersController < ApplicationController
|
class TagMastersController < ApplicationController
|
||||||
include Controllers::Nonprofit::Current
|
include Controllers::Nonprofit::Current
|
||||||
include Controllers::Nonprofit::Authorization
|
include Controllers::Nonprofit::Authorization
|
||||||
before_action :authenticate_nonprofit_user!
|
before_action :authenticate_nonprofit_user!
|
||||||
|
|
||||||
def index
|
def index
|
||||||
|
@ -25,7 +25,7 @@ module Nonprofits
|
||||||
|
|
||||||
def destroy
|
def destroy
|
||||||
tag_master = current_nonprofit.tag_masters.find(params[:id])
|
tag_master = current_nonprofit.tag_masters.find(params[:id])
|
||||||
tag_master.update_attribute(:deleted, true)
|
tag_master.discard!
|
||||||
tag_master.tag_joins.destroy_all
|
tag_master.tag_joins.destroy_all
|
||||||
render json: {}, status: :ok
|
render json: {}, status: :ok
|
||||||
end
|
end
|
||||||
|
|
|
@ -13,7 +13,7 @@ class TagJoin < ApplicationRecord
|
||||||
|
|
||||||
def name
|
def name
|
||||||
tag_master.name
|
tag_master.name
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.create_with_name(nonprofit, h)
|
def self.create_with_name(nonprofit, h)
|
||||||
tm = nonprofit.tag_masters.find_by_name(h['name'])
|
tm = nonprofit.tag_masters.find_by_name(h['name'])
|
||||||
|
|
|
@ -3,6 +3,12 @@
|
||||||
# License: AGPL-3.0-or-later WITH WTO-AP-3.0-or-later
|
# License: AGPL-3.0-or-later WITH WTO-AP-3.0-or-later
|
||||||
# Full license explanation at https://github.com/houdiniproject/houdini/blob/master/LICENSE
|
# Full license explanation at https://github.com/houdiniproject/houdini/blob/master/LICENSE
|
||||||
class TagMaster < ApplicationRecord
|
class TagMaster < ApplicationRecord
|
||||||
|
|
||||||
|
# TODO replace with Discard gem
|
||||||
|
define_model_callbacks :discard
|
||||||
|
|
||||||
|
after_discard :publish_delete
|
||||||
|
|
||||||
# :nonprofit, :nonprofit_id,
|
# :nonprofit, :nonprofit_id,
|
||||||
# :name,
|
# :name,
|
||||||
# :deleted,
|
# :deleted,
|
||||||
|
@ -11,6 +17,7 @@ class TagMaster < ApplicationRecord
|
||||||
validates :name, presence: true
|
validates :name, presence: true
|
||||||
validate :no_dupes, on: :create
|
validate :no_dupes, on: :create
|
||||||
|
|
||||||
|
after_create :publish_create
|
||||||
belongs_to :nonprofit
|
belongs_to :nonprofit
|
||||||
has_many :tag_joins, dependent: :destroy
|
has_many :tag_joins, dependent: :destroy
|
||||||
has_one :email_list
|
has_one :email_list
|
||||||
|
@ -22,4 +29,50 @@ class TagMaster < ApplicationRecord
|
||||||
|
|
||||||
errors.add(:base, 'Duplicate tag') if nonprofit.tag_masters.not_deleted.where(name: name).any?
|
errors.add(:base, 'Duplicate tag') if nonprofit.tag_masters.not_deleted.where(name: name).any?
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
# TODO replace with discard gem
|
||||||
|
def discard!
|
||||||
|
run_callbacks(:discard) do
|
||||||
|
self.deleted = true
|
||||||
|
save!
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def to_builder(*expand)
|
||||||
|
Jbuilder.new do |tag|
|
||||||
|
tag.(self, :id, :name, :deleted)
|
||||||
|
tag.object 'tag_master'
|
||||||
|
if expand.include? :nonprofit && nonprofit
|
||||||
|
tag.nonprofit do
|
||||||
|
tag.id nonprofit.id
|
||||||
|
tag.name nonprofit.name
|
||||||
|
end
|
||||||
|
else
|
||||||
|
tag.nonprofit nonprofit && nonprofit.id
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
private
|
||||||
|
def publish_create
|
||||||
|
Houdini.event_publisher.announce(:tag_master_created, to_event('tag_master.created', :nonprofit).attributes!)
|
||||||
|
end
|
||||||
|
|
||||||
|
def publish_delete
|
||||||
|
Houdini.event_publisher.announce(:tag_master_deleted, to_event('tag_master.deleted', :nonprofit).attributes!)
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
def to_event(event_type, *expand)
|
||||||
|
Jbuilder.new do |event|
|
||||||
|
event.id SecureRandom.uuid
|
||||||
|
event.object 'event'
|
||||||
|
event.type event_type
|
||||||
|
event.data do
|
||||||
|
event.object to_builder(*expand)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
20
docs/event_definitions/Nonprofit/TagMaster.ts
Normal file
20
docs/event_definitions/Nonprofit/TagMaster.ts
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
// License: LGPL-3.0-or-later
|
||||||
|
|
||||||
|
import type { HoudiniEvent, HoudiniObject, IdType } from "../common";
|
||||||
|
import type Nonprofit from './';
|
||||||
|
|
||||||
|
export interface TagMaster extends HoudiniObject {
|
||||||
|
deleted: boolean;
|
||||||
|
name: string;
|
||||||
|
nonprofit: IdType | Nonprofit;
|
||||||
|
object: 'tag_master';
|
||||||
|
}
|
||||||
|
|
||||||
|
/** POST /nonprofits/:id/tag_masters */
|
||||||
|
export interface CreateTagMaster {
|
||||||
|
name: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export type TagMasterCreated = HoudiniEvent<'tag_master.created', TagMaster>;
|
||||||
|
|
||||||
|
export type TagMasterDeleted = HoudiniEvent<'tag_master.deleted', TagMaster>;
|
10
docs/event_definitions/Nonprofit/index.ts
Normal file
10
docs/event_definitions/Nonprofit/index.ts
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
// License: LGPL-3.0-or-later
|
||||||
|
import type { HoudiniObject } from '../common';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A single nonprofit organization on Houdini.
|
||||||
|
*/
|
||||||
|
export default interface Nonprofit extends HoudiniObject {
|
||||||
|
name: string;
|
||||||
|
object: "nonprofit";
|
||||||
|
}
|
48
docs/event_definitions/common.ts
Normal file
48
docs/event_definitions/common.ts
Normal file
|
@ -0,0 +1,48 @@
|
||||||
|
// License: LGPL-3.0-or-later
|
||||||
|
|
||||||
|
/**
|
||||||
|
* the main identifier for HoudiniObjects which is unique between all other HoudiniObjects with the same object value.
|
||||||
|
* Currently just an integer but we could reevaluate later;
|
||||||
|
*/
|
||||||
|
export type IdType = number;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Every object controlled by the Houdini event publisher must meet this standard interface
|
||||||
|
* and will inherit from it.
|
||||||
|
*/
|
||||||
|
export interface HoudiniObject {
|
||||||
|
/**
|
||||||
|
* An IdType which unique which uniquely identifies this object
|
||||||
|
* from all other similar objects
|
||||||
|
*/
|
||||||
|
id: IdType;
|
||||||
|
/**
|
||||||
|
* the type of object. Roughly corresponds to the object's class in Rails
|
||||||
|
*/
|
||||||
|
object: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An event published by Houdini
|
||||||
|
*
|
||||||
|
* Generics:
|
||||||
|
* * EventType a snake-cased string of the format: "<object_type>.<event_name>". As an example
|
||||||
|
* tag_master.created means the event fired by when a tag_master was created
|
||||||
|
* * DataObject: the interface representing the actual object which the event occurred on. An object of that type is
|
||||||
|
* on the 'data' attribute
|
||||||
|
*/
|
||||||
|
export interface HoudiniEvent<EventType extends string, DataObject extends HoudiniObject> {
|
||||||
|
/** data for the event. We wrap the object inside becuase we might want to provide some sort of */
|
||||||
|
data: {
|
||||||
|
/** the object after the event has occurred */
|
||||||
|
object: DataObject;
|
||||||
|
};
|
||||||
|
/**
|
||||||
|
* A UUID uniquely representing the event
|
||||||
|
*/
|
||||||
|
id: string;
|
||||||
|
object: 'event';
|
||||||
|
/** The type of event that this is */
|
||||||
|
type: EventType;
|
||||||
|
|
||||||
|
}
|
55
spec/models/tag_master_spec.rb
Normal file
55
spec/models/tag_master_spec.rb
Normal file
|
@ -0,0 +1,55 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
# License: AGPL-3.0-or-later WITH WTO-AP-3.0-or-later
|
||||||
|
# Full license explanation at https://github.com/houdiniproject/houdini/blob/master/LICENSE
|
||||||
|
require 'rails_helper'
|
||||||
|
|
||||||
|
RSpec.describe TagMaster, type: :model do
|
||||||
|
include_context :shared_donation_charge_context
|
||||||
|
let(:name) { "TAGNAME"}
|
||||||
|
|
||||||
|
let(:tag_master) { nonprofit.tag_masters.create(name: name) }
|
||||||
|
it 'creates' do
|
||||||
|
expect(tag_master.errors).to be_empty
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'announces create' do
|
||||||
|
expect(Houdini.event_publisher).to receive(:announce).with(:tag_master_created, {
|
||||||
|
'id' => kind_of(String),
|
||||||
|
'object' => 'event',
|
||||||
|
'type' => 'tag_master.created',
|
||||||
|
'data' => {
|
||||||
|
'object' => {
|
||||||
|
'id'=> kind_of(Numeric),
|
||||||
|
'deleted' => false,
|
||||||
|
'name' => name,
|
||||||
|
'nonprofit'=> nonprofit.id,
|
||||||
|
'object' => 'tag_master'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
tag_master
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'announces deleted' do
|
||||||
|
expect(Houdini.event_publisher).to receive(:announce).with(:tag_master_created, anything).ordered
|
||||||
|
expect(Houdini.event_publisher).to receive(:announce).with(:tag_master_deleted, {
|
||||||
|
'id' => kind_of(String),
|
||||||
|
'object' => 'event',
|
||||||
|
'type' => 'tag_master.deleted',
|
||||||
|
'data' => {
|
||||||
|
'object' => {
|
||||||
|
'id'=> kind_of(Numeric),
|
||||||
|
'deleted' => true,
|
||||||
|
'name' => name,
|
||||||
|
'nonprofit'=> nonprofit.id,
|
||||||
|
'object' => 'tag_master'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}).ordered
|
||||||
|
|
||||||
|
tag_master.discard!
|
||||||
|
|
||||||
|
end
|
||||||
|
end
|
Loading…
Reference in a new issue