Версия: 1.0.0
Дата: 2025-11-10
my-plugin/
├── plugin.yaml # Манифест
├── __init__.py # Entry point
├── hooks.py # Event hooks
├── fields.py # Кастомные поля (опционально)
└── ui/ # UI компоненты (опционально)
└── widgets.py
plugin:
id: social-media
name: "Social Media Fields"
version: "1.0.0"
author: "John Doe"
description: "Adds social media fields to Contact entity"
requires:
cifra: ">=1.0.0"
plugins:
- contacts: "^1.0.0"
permissions:
- entity:Contact:extend
- api:read
entities:
Contact:
fields:
facebook: {type: string}
twitter: {type: string}
linkedin: {type: string}
hooks:
- event: "entity.Contact.before_save"
handler: "hooks.validate_social_urls"
from cifra.plugins import hook
@hook('entity.*.before_save')
async def validate_data(entity, data):
"""Before save любой Entity"""
...
@hook('entity.Contact.after_create')
async def on_contact_created(contact):
"""After Contact создан"""
await send_welcome_email(contact.email)
@hook('entity.Deal.stage_changed')
async def on_deal_stage_changed(deal, old_stage, new_stage):
"""When Deal stage изменён"""
if new_stage == 'won':
await create_invoice(deal)
# Все доступные hooks:
# - entity.*.before_save
# - entity.*.after_save
# - entity.*.before_delete
# - entity.*.after_delete
# - entity.*.before_update
# - entity.*.after_update
# - api.*.before_request
# - api.*.after_response
# - auth.user.login
# - auth.user.logout
from cifra.plugins import extend_entity
from cifra.fields import StringField
@extend_entity('Contact')
def add_social_fields(entity_class):
"""Add social media fields to Contact"""
entity_class.add_field('facebook', StringField(
label="Facebook",
validators=[URLValidator()]
))
entity_class.add_field('twitter', StringField(
label="Twitter"
))
from cifra.plugins import register_endpoint
from fastapi import APIRouter
router = APIRouter()
@router.get('/api/contacts/{id}/social')
async def get_social_profiles(contact_id: UUID):
"""Get social media profiles for contact"""
contact = await Contact.get(contact_id)
return {
'facebook': contact.facebook,
'twitter': contact.twitter,
'linkedin': contact.linkedin
}
# Register in plugin
def register(app):
app.include_router(router)
from cifra.plugins import register_widget
from cifra.ui import Widget
@register_widget('SocialMediaCard')
class SocialMediaWidget(Widget):
"""Display social media links"""
def render(self, contact):
return f"""
<div class="social-links">
<a href="https://facebook.com/{contact.facebook}">Facebook</a>
<a href="https://twitter.com/{contact.twitter}">Twitter</a>
</div>
"""
from cifra.plugins import Plugin
class SocialMediaPlugin(Plugin):
def __init__(self):
super().__init__('social-media', version='1.0.0')
def install(self):
"""Called when plugin installed"""
print("Installing social-media plugin...")
def enable(self):
"""Called when plugin enabled"""
pass
def disable(self):
"""Called when plugin disabled"""
pass
def uninstall(self):
"""Called when plugin uninstalled"""
pass
Полная документация: https://docs.cifra.io/plugins