From 9c4fbfc56f9c84c06176e2002d6ed212326c459e Mon Sep 17 00:00:00 2001 From: Divit Patidar Date: Wed, 7 Aug 2024 23:14:55 -0500 Subject: [PATCH] download certificate button added & working --- .../api/v1/badge_certificate_controller.rb | 24 +++---- .../api/v1/badge_certificate_open_api.rb | 69 +++++++++--------- backend/app/services/open_badge_api.rb | 23 +++--- frontend/src/components/navbar/top-navbar.tsx | 1 - frontend/src/screens/achievements.tsx | 72 ++++++++++++------- 5 files changed, 102 insertions(+), 87 deletions(-) diff --git a/backend/app/controllers/api/v1/badge_certificate_controller.rb b/backend/app/controllers/api/v1/badge_certificate_controller.rb index b0a17758..07f1d270 100644 --- a/backend/app/controllers/api/v1/badge_certificate_controller.rb +++ b/backend/app/controllers/api/v1/badge_certificate_controller.rb @@ -1,24 +1,24 @@ +# frozen_string_literal: true + class Api::V1::BadgeCertificateController < Api::V1::BaseController -def show + def show badge_id = params[:badge_id] email = params[:email] if badge_id.blank? || email.blank? - render json: { error: 'Badge ID and email are required' }, status: :unprocessable_entity - return + render json: { error: 'Badge ID and email are required' }, status: :unprocessable_entity + return end response = OpenBadgeApi.instance.get_pdf(badge_id, email) - + if response[:pdf].present? - - pdf_content = response[:pdf].read - base64_pdf = Base64.encode64(pdf_content) - render json: { pdf: base64_pdf }, status: :ok + + pdf_content = response[:pdf].read + base64_pdf = Base64.encode64(pdf_content) + render json: { pdf: base64_pdf }, status: :ok else - render json: { error: 'Failed to retrieve PDF' }, status: :bad_request + render json: { error: 'Failed to retrieve PDF' }, status: :bad_request end + end end -end - - \ No newline at end of file diff --git a/backend/app/controllers/api/v1/badge_certificate_open_api.rb b/backend/app/controllers/api/v1/badge_certificate_open_api.rb index 652e651d..f3bf4f2a 100644 --- a/backend/app/controllers/api/v1/badge_certificate_open_api.rb +++ b/backend/app/controllers/api/v1/badge_certificate_open_api.rb @@ -2,47 +2,46 @@ class Api::V1::BadgeCertificateOpenApi include OpenStax::OpenApi::Blocks - - openapi_component do - schema :BadgeCertificateResponse do - property :pdf do - key :type, :string - key :description, 'Base64-encoded PDF data' - end + + openapi_component do + schema :BadgeCertificateResponse do + property :pdf do + key :type, :string + key :description, 'Base64-encoded PDF data' end end - - openapi_path '/badge_certificate' do - operation :get do - key :summary, 'Retrieve a PDF link for a badge' - key :description, 'Fetches a PDF link associated with a badge for a given email' - key :operationId, 'getBadgeCertificate' + end - parameter name: :badge_id, in: :query, required: true do - schema do - key :type, :string - key :description, 'Badge ID' - end - end - - parameter name: :email, in: :query, required: true do - schema do - key :type, :string - key :description, 'Recipient Email' - end + openapi_path '/badge_certificate' do + operation :get do + key :summary, 'Retrieve a PDF link for a badge' + key :description, 'Fetches a PDF link associated with a badge for a given email' + key :operationId, 'getBadgeCertificate' + + parameter name: :badge_id, in: :query, required: true do + schema do + key :type, :string + key :description, 'Badge ID' end - - response 200 do - key :description, 'PDF link retrieved successfully.' - content 'application/json' do - schema { key :$ref, :BadgeCertificateResponse } - end + end + + parameter name: :email, in: :query, required: true do + schema do + key :type, :string + key :description, 'Recipient Email' end - response 404 do - key :description, 'Badge or PDF link not found.' + end + + response 200 do + key :description, 'PDF link retrieved successfully.' + content 'application/json' do + schema { key :$ref, :BadgeCertificateResponse } end - extend Api::V1::OpenApiResponses::ServerError end + response 404 do + key :description, 'Badge or PDF link not found.' + end + extend Api::V1::OpenApiResponses::ServerError end end - \ No newline at end of file +end diff --git a/backend/app/services/open_badge_api.rb b/backend/app/services/open_badge_api.rb index 7fa53ce1..a324b7d8 100644 --- a/backend/app/services/open_badge_api.rb +++ b/backend/app/services/open_badge_api.rb @@ -58,14 +58,13 @@ def issue_badge(badge_id, emails) end def get_pdf(badge_id, email) - # Response is an octet-stream # Fetching the event id event_response = HTTPX.plugin(:auth) - .with(headers: { 'content-type' => 'application/json' }) - .authorization("Bearer #{token}") - .get("https://openbadgefactory.com/v1/event/#{@client_id}?email=#{email}") - + .with(headers: { 'content-type' => 'application/json' }) + .authorization("Bearer #{token}") + .get("https://openbadgefactory.com/v1/event/#{@client_id}?email=#{email}") + response_body = event_response.body.to_s json_objects = response_body.split("\n").map(&:strip).reject(&:empty?) @@ -78,19 +77,19 @@ def get_pdf(badge_id, email) # Fetching the pdf link pdf_response = HTTPX.plugin(:auth) - .with(headers: { 'content-type' => 'application/json' }) - .authorization("Bearer #{token}") - .get("https://openbadgefactory.com/v1/event/#{@client_id}/#{event_id}/assertion") + .with(headers: { 'content-type' => 'application/json' }) + .authorization("Bearer #{token}") + .get("https://openbadgefactory.com/v1/event/#{@client_id}/#{event_id}/assertion") data = JSON.parse(pdf_response) pdf_link = data['pdf']['en'] # Fetching the pdf from pdf_link pdf_response = HTTPX.plugin(:auth) - .authorization("Bearer #{token}") - .get(pdf_link) + .authorization("Bearer #{token}") + .get(pdf_link) - {pdf: pdf_response.body} + { pdf: pdf_response.body } end - + end diff --git a/frontend/src/components/navbar/top-navbar.tsx b/frontend/src/components/navbar/top-navbar.tsx index 99258178..dd77c627 100644 --- a/frontend/src/components/navbar/top-navbar.tsx +++ b/frontend/src/components/navbar/top-navbar.tsx @@ -105,7 +105,6 @@ export const TopNavBar: React.FC = ({ className }) => { )} - // achievements page {!isMobile && !user.isAdministrator && !user.isResearcher && ( diff --git a/frontend/src/screens/achievements.tsx b/frontend/src/screens/achievements.tsx index b41ebfb1..a7ef8bb5 100644 --- a/frontend/src/screens/achievements.tsx +++ b/frontend/src/screens/achievements.tsx @@ -10,11 +10,12 @@ import { RingProgress, Image, } from '@mantine/core'; -import { useApi } from '@lib' +import { useApi } from '@lib'; import { TopNavBar, Footer } from '@components'; import { colors } from '@theme'; import { StudyDetailsPreview } from '../screens/learner/details'; import { useParticipantStudies } from './learner/studies'; +import { useCurrentUser } from '@lib'; const BadgeDetail = ({ badge, @@ -95,8 +96,8 @@ const convertBase64ToPdf = (base64PDF: string) => { const byteArray = new Uint8Array(byteNumbers); const blob = new Blob([byteArray], { type: 'application/pdf' }); const url = URL.createObjectURL(blob); - return url -} + return url; +}; const AchievementBadge = ({ study, @@ -107,6 +108,7 @@ const AchievementBadge = ({ onBadgeClick: (study: any) => void; onStudySelect: (study: any) => void; }) => { + const [errorMessage, setErrorMessage] = useState(''); const completedStudies = study?.learningPath?.studies.filter( (s: any) => s.completedCount !== 0 ).length; @@ -119,20 +121,35 @@ const AchievementBadge = ({ ? 'Continue' : 'Start'; - // event block statement to download pdf - const api = useApi() + const api = useApi(); + const currentUser = useCurrentUser(); + const handleButtonClick = async ( - e: React.MouseEvent + e: React.MouseEvent, + badgeId: string ) => { e.stopPropagation(); if (isCompleted) { - try{ - const response = await api.getBadgeCertificate({badgeId: 'SAJSINa7DGDaC4D', email: 'srinivas.babu364@gmail.com'}) - console.log(response.pdf) - const pdfUrl = convertBase64ToPdf(response.pdf || '') + try { + let userEmail = ''; + + if (currentUser && currentUser.contactInfos) { + const emailInfo = currentUser.contactInfos.find( + (info) => info.type === 'EmailAddress' + ); + if (emailInfo && emailInfo.value) { + userEmail = emailInfo.value; + } + } + + const response = await api.getBadgeCertificate({ + badgeId, + email: userEmail, + }); + const pdfUrl = convertBase64ToPdf(response.pdf || ''); window.open(pdfUrl, '_blank'); } catch (error) { - console.error('Error fetching PDF:', error); + setErrorMessage('Error fetching PDF. Please try again later.'); } } else { const nextStudy = study?.learningPath?.studies.find( @@ -160,6 +177,12 @@ const AchievementBadge = ({ }} onClick={() => onBadgeClick(study)} > + {errorMessage && ( + + {errorMessage} + + )} + ); - const Achievements = () => { const [selectedTab, setSelectedTab] = useState<'Badges' | 'Points'>( 'Badges' @@ -312,7 +335,9 @@ const Achievements = () => { const [selectedStudy, setSelectedStudy] = useState(null); const [badgeDetail, setBadgeDetail] = useState(null); - const DATA = useParticipantStudies(); + const DATA = useParticipantStudies(); + const studies = DATA.studies; + const handleTabClick = (tab: any) => setSelectedTab(tab); const handleBadgeClick = (study: any) => { setBadgeDetail(study); @@ -339,16 +364,9 @@ const Achievements = () => { - {DATA.studies.map((study) => ( + {studies.map((study) => ( { onClick={() => handleTabClick('Badges')} /> - {renderContent()} {/* Always render content without loading check */} + {renderContent()} {/* Always render content without loading check */}