Skip to content

Commit 94c8099

Browse files
feat: Adiciona classe CertificatesOnSolana para registro de certificados na blockchain Solana e atualiza modelo Participant para incluir URL de verificação de autenticidade
1 parent bab3039 commit 94c8099

File tree

4 files changed

+74
-5
lines changed

4 files changed

+74
-5
lines changed
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
import logging
2+
import httpx
3+
from pydantic import BaseModel
4+
from config import config
5+
6+
logger = logging.getLogger(__name__)
7+
8+
9+
class CertificatesOnSolanaException(Exception):
10+
"""Custom exception for CertificatesOnSolana errors."""
11+
def __init__(self, message: str = "Error registering certificate on Solana",
12+
details: str = "",
13+
cause: Exception = None):
14+
super().__init__(message)
15+
self.details = details
16+
self.cause = cause
17+
class CertificatesOnSolana:
18+
19+
"""
20+
A class to manage certificates on the Solana blockchain Service."""
21+
22+
@staticmethod
23+
def register_certificate_on_solana(certificate_data: dict) -> dict:
24+
logger.info("Registering certificate on Solana blockchain")
25+
"""
26+
Registers a certificate on the Solana blockchain.
27+
28+
Args:
29+
certificate_data (dict): A dictionary containing certificate details.
30+
31+
Returns:
32+
dict: A dictionary with the registration result.
33+
"""
34+
try:
35+
with httpx.Client() as client:
36+
response = client.post(
37+
url= config.SERVICE_URL_REGISTRATION_API_SOLANA,
38+
headers={
39+
"x-api-key": config.SERVICE_API_KEY_REGISTRATION_API_SOLANA,
40+
"Content-Type": "application/json"
41+
},
42+
json=certificate_data
43+
)
44+
logger.info(f"Solana response status code: {response.status_code}")
45+
response.raise_for_status()
46+
solana_response = response.json()
47+
return solana_response
48+
logger.info("Certificate registered successfully on Solana")
49+
except Exception as e:
50+
logger.error(f"Error registering certificate on Solana: {str(e)}")
51+
raise CertificatesOnSolanaException(details=str(e), cause=e)

certified_builder/certified_builder.py

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
11
import logging
2+
import tempfile
3+
import os
24
from typing import List
3-
from models.participant import Participant
45
from PIL import Image, ImageDraw, ImageFont
56
from io import BytesIO
6-
import os
7+
from models.participant import Participant
78
from certified_builder.utils.fetch_file_certificate import fetch_file_certificate
8-
import tempfile
9+
from certified_builder.certificates_on_solana import CertificatesOnSolana
10+
911
FONT_NAME = os.path.join(os.path.dirname(__file__), "fonts/PinyonScript/PinyonScript-Regular.ttf")
1012
VALIDATION_CODE = os.path.join(os.path.dirname(__file__), "fonts/ChakraPetch/ChakraPetch-SemiBold.ttf")
1113
DETAILS_FONT = os.path.join(os.path.dirname(__file__), "fonts/ChakraPetch/ChakraPetch-Regular.ttf")
@@ -44,6 +46,20 @@ def build_certificates(self, participants: List[Participant]):
4446

4547
for participant in participants:
4648
try:
49+
# Register certificate on Solana, with returned data extract url for verification
50+
solana_response = CertificatesOnSolana.register_certificate_on_solana(
51+
certificate_data={
52+
"name": participant.name_completed(),
53+
"event": participant.event.product_name,
54+
"email": participant.email,
55+
"certificate_code": participant.formated_validation_code()
56+
}
57+
)
58+
participant.authenticity_verification_url = solana_response.get("blockchain", {}).get("verificacao_url", "")
59+
60+
if not participant.authenticity_verification_url:
61+
raise RuntimeError("Failed to get authenticity verification URL from Solana response")
62+
4763
# Download template and logo only if they are not shared
4864
if not all_same_background:
4965
certificate_template = self._download_image(participant.certificate.background)

config.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,8 @@ class Config(BaseSettings):
77
REGION: str
88
BUCKET_NAME: str
99
QUEUE_URL: str
10-
10+
SERVICE_URL_REGISTRATION_API_SOLANA: str
11+
SERVICE_API_KEY_REGISTRATION_API_SOLANA: str
1112

1213
class Config:
1314
env_file = ".env"

models/participant.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ class Participant(BaseModel):
2121
validation_code: Optional[str] = Field(default_factory= lambda: ''.join(random.choices(string.hexdigits, k=9)), init=False)
2222
certificate: Optional[Certificate] = None
2323
event: Optional[Event] = None
24+
authenticity_verification_url: Optional[str] = None
2425

2526
def __str__(self):
2627
return f"Participant: {self.first_name} {self.last_name} - {self.email}"
@@ -117,4 +118,4 @@ def create_name_certificate(self):
117118
logger.info(f"Código de validação antes da sanitização: {self.formated_validation_code()}")
118119
logger.info(f"Nome do certificado após a sanitização: {name_certificate}")
119120

120-
return name_certificate
121+
return name_certificate

0 commit comments

Comments
 (0)