@cryptotaxi247 / CoPilot / commits / b35c81d1

Markdown docker compose (#192)

* Add RetrieveDockerCompose API endpoint * updated license details component added docker compose config * precommit fixes --------- Co-authored-by: Davide Di Modica <webmaster.ddm@gmail.com>

taylor_socfortress committed Apr 17, 2024 at 13:54 UTC b35c81d14144c6ec2be16a2748b1efae7a00ccd7
5 files changed +102 -3
backend/app/middleware/license.py
+42
@@ -314,6 +314,12 @@ class CancelSubscriptionResponse(BaseModel):
314 message: str
315
316
317 +class RetrieveDockerCompose(BaseModel):
318 + docker_compose: str
319 + success: bool
320 + message: str
321 +
322 +
323 license_router = APIRouter()
324
325
@@ -824,6 +830,42 @@ async def replace_license_in_db(request: ReplaceLicenseRequest, session: AsyncSe
830 raise HTTPException(status_code=400, detail="License replacement failed")
831
832
833 +@license_router.post(
834 + "/retrieve-docker-compose",
835 + response_model=RetrieveDockerCompose,
836 + description="Retrieve Docker Compose for features enabled",
837 +)
838 +async def retrieve_docker_compose(session: AsyncSession = Depends(get_db)) -> RetrieveDockerCompose:
839 + """
840 + Retrieve the Docker Compose for features enabled in the license.
841 +
842 + Args:
843 + session (AsyncSession, optional): The database session. Defaults to Depends(get_db).
844 +
845 + Returns:
846 + RetrieveDockerCompose: A Pydantic model containing the Docker Compose for features enabled.
847 + """
848 + try:
849 + license = await get_license(session)
850 + if license.license_key:
851 + results = await send_post_request("retrieve-docker-compose", data={"license_key": license.license_key})
852 + logger.info(f"Results: {results}")
853 + return RetrieveDockerCompose(
854 + docker_compose=results["data"]["docker_compose"],
855 + success=results["success"],
856 + message=results["message"],
857 + )
858 + else:
859 + return RetrieveDockerCompose(
860 + docker_compose="",
861 + success=False,
862 + message="License key not found",
863 + )
864 + except Exception as e:
865 + logger.error(e)
866 + raise HTTPException(status_code=400, detail="Failed to retrieve Docker Compose")
867 +
868 +
869 def create_headers(request: ThreatIntelRegisterRequest) -> Dict[str, str]:
870 return {
871 "x-api-key": request.requesting_api_key,
frontend/src/api/license.ts
+3
@@ -56,6 +56,9 @@ export default {
56 cancelSubscription(payload: CancelSubscriptionPayload) {
57 return HttpClient.post<FlaskBaseResponse>(`/license/cancel_subscription`, payload)
58 },
59 + retrieveDockerCompose() {
60 + return HttpClient.post<FlaskBaseResponse & { docker_compose: string }>(`/license/retrieve-docker-compose`)
61 + },
62 // TODO: remove, deprecated
63 extendLicense(period: number) {
64 return HttpClient.post<FlaskBaseResponse>(
frontend/src/components/common/Markdown.vue
+15 -1
@@ -4,6 +4,7 @@
4 preset="commonmark"
5 :plugins="[[markdownItHighlightjs, { hljs, auto: true, code: true, inline: false, ignoreIllegals: true }]]"
6 class="markdown-style scrollbar-styled"
7 + :class="{ transparent }"
8 />
9 </template>
10
@@ -18,16 +19,19 @@ import powershell from "highlight.js/lib/languages/powershell"
19 import bash from "highlight.js/lib/languages/bash"
20 import json from "highlight.js/lib/languages/json"
21 import xml from "highlight.js/lib/languages/xml"
22 +import yaml from "highlight.js/lib/languages/yaml"
23
24 hljs.registerLanguage("powershell", powershell)
25 hljs.registerLanguage("bash", bash)
26 hljs.registerLanguage("json", json)
27 hljs.registerLanguage("xml", xml)
28 +hljs.registerLanguage("yaml", yaml)
29
30 const props = defineProps<{
31 source: string
32 + transparent?: boolean
33 }>()
30 -const { source } = toRefs(props)
34 +const { source, transparent } = toRefs(props)
35 </script>
36
37 <style lang="scss" scoped>
@@ -37,5 +41,15 @@ const { source } = toRefs(props)
41 margin-bottom: 15px;
42 }
43 }
44 +
45 + &.transparent {
46 + :deep() {
47 + & > pre {
48 + & > code {
49 + background-color: transparent;
50 + }
51 + }
52 + }
53 + }
54 }
55 </style>
frontend/src/components/license/LicenseDetails.vue
+41 -2
@@ -64,6 +64,17 @@
64 </div>
65 </template>
66 </KVCard>
67 + <KVCard class="!basis-auto" v-if="dockerCompose">
68 + <template #key>
69 + <span class="flex gap-3 items-center">
70 + <Icon :name="ConfigIcon" :size="14"></Icon>
71 + <span>Docker Configuration</span>
72 + </span>
73 + </template>
74 + <template #value>
75 + <Markdown :source="dockerCompose" transparent />
76 + </template>
77 + </KVCard>
78 </div>
79 </n-spin>
80 </template>
@@ -72,13 +83,14 @@
83 import { NSpin, useMessage } from "naive-ui"
84 import Icon from "@/components/common/Icon.vue"
85 import Api from "@/api"
75 -import { onBeforeMount, onMounted, ref, toRefs, computed } from "vue"
86 +import { onBeforeMount, onMounted, ref, toRefs, computed, defineAsyncComponent } from "vue"
87 import { type LicenseFeatures, type License } from "@/types/license.d"
88 import { formatDate } from "@/utils"
89 import { useSettingsStore } from "@/stores/settings"
90 import _startCase from "lodash/startCase"
91 import Badge from "@/components/common/Badge.vue"
92 import KVCard from "@/components/common/KVCard.vue"
93 +const Markdown = defineAsyncComponent(() => import("@/components/common/Markdown.vue"))
94
95 const emit = defineEmits<{
96 (e: "licenseLoaded", value: License): void
@@ -103,14 +115,17 @@ const ExpiresIcon = "ph:calendar-blank"
115 const CustomerIcon = "carbon:user"
116 const CheckIcon = "carbon:checkmark-outline"
117 const FeaturesIcon = "material-symbols:checklist"
118 +const ConfigIcon = "carbon:settings"
119
120 const message = useMessage()
121 const loadingLicense = ref(false)
122 const loadingFeatures = ref(false)
123 +const loadingDockerCompose = ref(false)
124 const dFormats = useSettingsStore().dateFormat
125
126 const licenseLoaded = ref<License | null>(null)
127 const featuresLoaded = ref<LicenseFeatures[]>([])
128 +const dockerCompose = ref<string | null>(null)
129 const license = computed(() => licenseLoaded.value || licenseData?.value || null)
130 const features = computed(() => featuresLoaded.value || featuresData?.value || [])
131 const expiresText = computed(() => (license.value ? formatDate(license.value.expires, dFormats.datetime) : ""))
@@ -118,7 +133,7 @@ const periodText = computed(() =>
133 license.value ? `${license.value.period} Day${license.value.period === 1 ? "" : "s"}` : ""
134 )
135
121 -const loading = computed(() => loadingLicense.value || loadingFeatures.value)
136 +const loading = computed(() => loadingLicense.value || loadingFeatures.value || loadingDockerCompose.value)
137
138 function getLicense() {
139 loadingLicense.value = true
@@ -165,6 +180,28 @@ function getLicenseFeatures() {
180 })
181 }
182
183 +function retrieveDockerCompose() {
184 + loadingDockerCompose.value = true
185 +
186 + Api.license
187 + .retrieveDockerCompose()
188 + .then(res => {
189 + if (res.data.success) {
190 + dockerCompose.value = res.data?.docker_compose
191 + } else {
192 + message.warning(res.data?.message || "An error occurred. Please try again later.")
193 + }
194 + })
195 + .catch(err => {
196 + if (err.response.status !== 404) {
197 + message.error(err.response?.data?.message || "An error occurred. Please try again later.")
198 + }
199 + })
200 + .finally(() => {
201 + loadingDockerCompose.value = false
202 + })
203 +}
204 +
205 function load() {
206 if (!license.value) {
207 getLicense()
@@ -172,6 +209,8 @@ function load() {
209 if (!hideFeatures.value && !features.value.length) {
210 getLicenseFeatures()
211 }
212 +
213 + retrieveDockerCompose()
214 }
215
216 function sanitizeKey(text: string) {
frontend/src/components/license/LicenseViewer.vue
+1
@@ -52,6 +52,7 @@ function licenseLoaded(license: License) {
52 .side-box {
53 overflow: hidden;
54 transition: all 0.3s var(--bezier-ease);
55 + border-radius: var(--border-radius);
56 }
57 &.has-side {
58 align-items: stretch;