Filter for PDF files while exploring with Angular and Capacitor Filesystem - angularjs

I use the following code to explore the file system in an ionic App the save files to the device for uploading latter.
import { Component, ElementRef, ViewChild } from '#angular/core';
import { Filesystem, Directory } from '#capacitor/filesystem';
import write_blob from 'capacitor-blob-writer';
export class QuestionPhotosPage {
#ViewChild('filepicker') uploader: ElementRef;
addFile() {
this.uploader.nativeElement.click();
console.log("click open file explorer");
}
async fileSelected($event) {
console.log("$event", $event)
const selected = $event.target.files[0];
let fileName = this.createFileNameAlt(selected.name)
await write_blob({
directory: Directory.Documents,
path: `${this.FILE_DIR}/${fileName}`,
blob: selected,
fast_mode: true,
recursive: true,
on_fallback(error) { console.error(error) }
})
}
I was wondering if there is away to filter the addFile() to only show folders and pdf documents?

Using the plugin github.com/capawesome-team/capacitor-file-picker here is what my code looks like.
import { Filesystem, Directory } from '#capacitor/filesystem';
import write_blob from 'capacitor-blob-writer';
import { File, FilePicker } from '#capawesome/capacitor-file-picker';
async pickFile(): Promise<void> {
const types = ["application/pdf"];
const multiple = false;
const readData = true;
const { files } = await FilePicker.pickFiles({ types, multiple, readData });
this.fileSelected(files);
}
async fileSelected(file: any) {
let fileName = this.createFileNameAlt(file[0].name)
await write_blob({
directory: Directory.Documents,
path: `${this.FILE_DIR}/${fileName}`,
blob: file,
fast_mode: true,
recursive: true,
on_fallback(error) { console.error(error) }
})
}

Related

Generate static pages from json data

(This is just for my understanding)
If I have json file that contains array of data is it possible to generate html page for each entry/object of the array?
The json file is static and it is located under the src folder:
//+page.js
import snippets from '../../../data/product_data.json';
export async function load({ params }) {
const { slug } = params;
return snippets.filter((s) => s.name == slug)[0];
}
//+page.svelte
<script>
export const prerender = true;
export let data;
</script>
<div>{data.name}</div>
//svelte.config.js
import adapter from '#sveltejs/adapter-static';
/** #type {import('#sveltejs/kit').Config} */
const config = {
kit: {
adapter: adapter({ precompress: true, fallback: 'index.html' })
}
};
export default config;

Apollo Server - GET query missing

I am trying to use this template to learn how to use graphql/apollo/prisma etc.
When I try to start the server, I get a confirmation in the console, but an error in the browser that says: GET query missing.
import "reflect-metadata"
import "dotenv/config"
import { ApolloServerPluginCacheControl, ApolloServerPluginLandingPageDisabled } from "apollo-server-core"
import { ApolloServer } from "apollo-server-express"
import jwt from "express-jwt"
import { buildSchema } from "type-graphql"
import { Container } from "typedi"
import { JWT_AUTH } from "./lib/config"
import { ExpressContext } from "./lib/express"
import { formatResponse } from "./lib/formatResponse"
import { ErrorInterceptor } from "./lib/globalMiddleware"
import { loadPrismaHooks } from "./lib/hooks"
import { loadCurrentUser } from "./lib/loadCurrentUser"
import { loadResolvers } from "./lib/loadResolvers"
import { prisma } from "./lib/prisma"
import { Server } from "./lib/server"
class App extends Server {
constructor() {
super()
this.init().catch((error) => {
this.logger.error(error)
process.exit(1)
})
}
async init() {
await this.setUpDb()
await this.setUpAuth()
await this.setupApollo()
this.start()
}
async setUpDb() {
await prisma.$connect()
loadPrismaHooks()
this.logger.info("DB ready")
}
async setUpAuth() {
this.app
.use(jwt(JWT_AUTH))
.use((err: any, _: any, __: any, next: any) => {
if (err.name === "UnauthorizedError") next()
})
.use(loadCurrentUser)
this.logger.info("Auth ready")
}
async setupApollo() {
const schema = await buildSchema({
container: Container,
resolvers: loadResolvers(),
globalMiddlewares: [ErrorInterceptor],
})
const apolloServer = new ApolloServer({
context: ({ req, res }: ExpressContext) => ({ req, res, prisma }),
formatResponse,
plugins: [ApolloServerPluginCacheControl(), ApolloServerPluginLandingPageDisabled()],
schema,
// playground: true,
// introspection: true
})
await apolloServer.start()
apolloServer.applyMiddleware({ app: this.app })
// I deleted cors: true from the above line
this.logger.info("Apollo setup hello")
}
}
new App()
I have seen other posts describing that cors is no longer needed (not sure what the basis for that is) and also suggesting that I add the playground and introspection arguments to the new ApolloServer. I tried this (as shown in the commented lines), but the playground is not recognised as a valid argument.
Server is defined in the lib folder as:
import "reflect-metadata"
import "dotenv/config"
import * as Sentry from "#sentry/node"
import * as Tracing from "#sentry/tracing"
import chalk from "chalk"
import express from "express"
import morgan from "morgan"
import { IS_PRODUCTION, PORT, SENTRY_DSN } from "./config"
export class Server {
private readonly _app: express.Application
readonly logger: {
info: (message: string) => void
error: (message: string) => void
}
constructor() {
this._app = express()
.use(Sentry.Handlers.requestHandler())
.use(Sentry.Handlers.tracingHandler())
.enable("trust proxy")
.use(
morgan("dev", {
skip: (req) => req.method === "OPTIONS",
stream: { write: (message) => console.log(message + "\n\n") },
}),
)
if (IS_PRODUCTION) {
Sentry.init({
dsn: SENTRY_DSN,
integrations: [
new Sentry.Integrations.Http({ tracing: true }),
new Tracing.Integrations.Express({ app: this._app }),
],
enabled: IS_PRODUCTION,
tracesSampleRate: 1.0,
})
}
this.logger = {
info: this.info,
error: this.error,
}
}
protected error(message: string) {
console.log(`[${chalk.red("ERROR")}] `, message)
}
protected info(message: string) {
console.log(`[${chalk.blue("INFO")}] `, message)
}
protected get app(): express.Application {
return this._app
}
start(): void {
this._app
.use(Sentry.Handlers.errorHandler())
.listen(PORT, () => this.logger.info(`Server started at http://localhost:${PORT}/graphql 🚀` + "\n"))
}
}
The console logs in the terminal print the server started confirmation, but the browser just generates the cannot GET message. I don't know what this message means, to be able to begin to try and figure out how to get to the playground.
Can anyone recommend current instructions for how to configure the server?
the reason for this problem seems to be related to the move to the graphql sandbox environment. If you add localhost555 to the sandbox address bar, the page loads without an error.

how to replace strings with .env (dotenv-flow) with svelte-kit?

Inside svelte.config.js I have this:
preprocess: autoPreprocess({
replace: [
['API_ENDPOINT', JSON.stringify(process.env.API_ENDPOINT)]
]
}),
It should replace the string "API_ENDPOINT" but it isn't.
Here is how I'm using it:
async function api(url: string, body = {}, opts = {}) {
const endpoint = 'API_ENDPOINT';
console.log(endpoint);
const res = await fetch(endpoint + url, {
method: 'POST',
headers: {
'Content-type': 'application/json',
},
body: JSON.stringify(body)
});
if (!res.ok) {
const err = await res.json();
throw (err || res.statusText);
}
return opts.raw ? await res.text() : await res.json();
}
export default api;
All i get is http://localhost:3000/API_ENDPOINT/subscriptions
in your svelte.config.js file, instead of
autoPreprocess({
replace: [['process.env.NODE_ENV', JSON.stringify(process.env.NODE_ENV)]],
});
use
import sveltePreprocess from 'svelte-preprocess'
sveltePreprocess({
replace: [['process.env.NODE_ENV', JSON.stringify(process.env.NODE_ENV)]],
});
It seems to me that autoPreprocess was deprecated but the README docs were not correctly updated.
You also may want to consider doing one of the following:
use process.env.API_ENDPOINT directly
const endpoint = process.env.API_ENDPOINT;
create a separate javascript function to handle environment variables
something like this
envVars.js
import dotenv from 'dotenv-flow';
import path from 'path';
dotenv.config({
path: path.resolve(__dirname, `path-to-your-(.env)-file`),
});
export const getEnvVar = (key) => process.env[key];
and use it like this:
import { getEnvVar } from 'path-to-envVars'
const endpoint = getEnvVar('API_ENDPOINT');
if you're already using Vite as your build tool
Add the variables in a .env file like so:
VITE_YOUR_ENV_VAR_GOES_HERE=bar
in your case:
VITE_API_ENDPOINT=your_value
then import them in a separate javascript or typescript file
envVars.js
export const envVars = {
API_ENDPOINT: import.meta.env.VITE_API_ENDPOINT
};
and then import envVars and use it as so:
import { envVars } from 'path-to-envVars.js'
and now you can read your environment variable like this:
envVars.myVariable
or, in your case
const endpoint = envVars.API_ENDPOINT

Next.js | Is there any way to render an .xml file?

I'm trying to render an XML file when pointing to www.example.com/sitemap.xml. Since the project was developed using Next.js, the routing works with the js files stored in the pages directory:
example.com/help -> help.js
example.com/info -> info.js
So, is there any way to achieve this by avoiding accessing the backend?
JS Version
/pages/sitemap.xml.jsx
import React from 'react'
class Sitemap extends React.Component {
static async getInitialProps({ res }) {
res.setHeader('Content-Type', 'text/xml')
res.write(`<?xml version="1.0" encoding="UTF-8"?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
...
</urlset>`)
res.end()
}
}
export default Sitemap
TS Version
/pages/sitemap.xml.tsx
import { GetServerSideProps } from 'next'
import React from 'react'
const Sitemap: React.FC = () => null
export const getServerSideProps: GetServerSideProps = async ({ res }) => {
if (res) {
res.setHeader('Content-Type', 'text/xml')
res.write(`<?xml version="1.0" encoding="UTF-8"?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
</urlset>`)
res.end()
}
return {
props: {},
}
}
export default Sitemap
API Version
/pages/api/sitemap.xml.tsx
import type { NextApiRequest, NextApiResponse } from 'next'
import { getAllContentPagesQuery, getAllShopProductsQuery } from './utils/requests'
export default async (req: NextApiRequest, res: NextApiResponse<string>) => {
const pages = await getAllContentPagesQuery()
const products = await getAllShopProductsQuery()
const frontUrl = "https://localhost:3000"
const pagesAndSlugs = [...pages, ...products].map(url => ({
url: `${frontUrl}${'Variations' in url ? '/product/' : '/'}${url.slug}`, // -> /page1, /product/myproduct...
updatedAt: url.updatedAt,
}))
const urls = pagesAndSlugs.map(
({ url, updatedAt }) => `
<url>
<loc>${url}</loc>
<lastmod>${new Date(updatedAt).toISOString()}</lastmod>
</url>
`
)
.join('')
res
.setHeader('Content-Type', 'text/xml')
.setHeader(
'Cache-Control',
'public, s-maxage=10, stale-while-revalidate=59'
)
.status(200)
.send(`<?xml version="1.0" encoding="UTF-8"?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
${urls}
</urlset>`)
}
:D
Add a static file called sitemap.xml under public directory
public/sitemap.xml
after build you can access www.yourdomain.com/sitemap.xml
Read more on static files: https://nextjs.org/docs/basic-features/static-file-serving
You can use nextjs api routes.
path - pages/api/sitemap.ts
content -
import type { NextApiRequest, NextApiResponse } from 'next';
import { SitemapStream, streamToPromise } from 'sitemap';
async function sitemap(req: NextApiRequest, res: NextApiResponse<string>) {
try {
const smStream = new SitemapStream({
hostname: `https://${req.headers.host}`,
});
// List of posts
const posts: string[] = ['hello'];
// Create each URL row
posts.forEach(() => {
smStream.write({
url: `/post/hello`,
changefreq: 'daily',
priority: 0.9,
});
});
// End sitemap stream
smStream.end();
// XML sitemap string
const sitemapOutput = (await streamToPromise(smStream)).toString();
res.writeHead(200, {
'Content-Type': 'application/xml',
});
// Display output to user
res.end(sitemapOutput);
} catch (e) {
console.log(e);
res.send(JSON.stringify(e));
}
}
export default sitemap;
In robots.txt you can specify
Sitemap: https://[SITE_DOMAIN_HERE]/api/sitemap

avoid opening new window when downloading s3 object

download code
import React, { PureComponent } from "react";
import FaDownload from "react-icons/lib/fa/download";
import { Auth, API, Storage } from "aws-amplify";
class DownloadCell extends PureComponent {
onclick = async event => {
event.preventDefault();
try {
const stored = await Storage.get(this.props.node.data.Key.split('/')[1])
window.open(stored)
} catch (error) {
console.error("S3 download error: ", error);
}
};
trying to use AWS amplify to download s3 bucket files, not sure how to implement it correctly so the file does not end up in new window.
just remove the window.open()
onclick = async event => {
event.preventDefault();
try {
const stored = await Storage.get(this.props.node.data.Key.split('/')[1])
//whatever you want with the stored
//.....
} catch (error) {
console.error("S3 download error: ", error);
}

Resources