5htp-core 0.5.1-4 → 0.5.1-6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "5htp-core",
3
3
  "description": "Convenient TypeScript framework designed for Performance and Productivity.",
4
- "version": "0.5.1-4",
4
+ "version": "0.5.1-6",
5
5
  "author": "Gaetan Le Gac (https://github.com/gaetanlegac)",
6
6
  "repository": "git://github.com/gaetanlegac/5htp-core.git",
7
7
  "license": "MIT",
@@ -170,11 +170,11 @@ export default function Liste<TRow extends TDonneeInconnue>({
170
170
 
171
171
  render = (
172
172
  <div class="row sp-05">
173
- {cell.map((item, i) => (
173
+ {cell.map((item, i) => typeof item === 'string' ? (
174
174
  <span class={"badge bg light" + ((i % 7) + 1)}>
175
175
  {item}
176
176
  </span>
177
- ))}
177
+ ) : item)}
178
178
  </div>
179
179
  )
180
180
 
@@ -5,14 +5,16 @@
5
5
  position: relative;
6
6
  overflow: hidden;
7
7
 
8
- border-radius: @radius;
9
- border: dashed 3px var(--cLine);
10
- background: @cBgPage + #090909;
11
-
12
- padding: @spacing;
13
- width: 100%;
14
- min-height: 200px;
15
- height: 14.15rem;
8
+ &.box {
9
+ border-radius: @radius;
10
+ border: dashed 3px var(--cLine);
11
+ background: @cBgPage + #090909;
12
+
13
+ padding: @spacing;
14
+ width: 100%;
15
+ min-height: 200px;
16
+ height: 14.15rem;
17
+ }
16
18
 
17
19
  .preview,
18
20
  .indication,
@@ -6,7 +6,7 @@ import React from 'react';
6
6
  import { ComponentChild } from 'preact';
7
7
 
8
8
  // Composants généraux
9
- import Bouton from '@client/components/button';
9
+ import Button, { Props as BtnProps } from '@client/components/button';
10
10
 
11
11
  // Core libs
12
12
  import { InputWrapper } from '../base';
@@ -67,6 +67,7 @@ export type Props = {
67
67
  emptyText?: ComponentChild,
68
68
  className?: string,
69
69
  previewUrl?: string,
70
+ button?: boolean | BtnProps,
70
71
 
71
72
  // Actions
72
73
  onChange: (file: FileToUpload | undefined) => void
@@ -85,11 +86,12 @@ export default (props: Props) => {
85
86
  let {
86
87
  // Input
87
88
  value: file,
88
- className,
89
+ className: customClassName,
89
90
 
90
91
  // Display
91
92
  emptyText = 'Click here to select a File',
92
93
  previewUrl: previewUrlInit,
94
+ button,
93
95
 
94
96
  // Actions
95
97
  onChange
@@ -97,7 +99,13 @@ export default (props: Props) => {
97
99
 
98
100
  const [previewUrl, setPreviewUrl] = React.useState<string | undefined>(previewUrlInit);
99
101
 
100
- className = 'input upload ' + (className === undefined ? '' : ' ' + className);
102
+ let className = 'input upload';
103
+
104
+ if (!button)
105
+ className += ' box';
106
+
107
+ if (customClassName !== undefined)
108
+ className += ' ' + customClassName;
101
109
 
102
110
  /*----------------------------------
103
111
  - ACTIONS
@@ -131,33 +139,49 @@ export default (props: Props) => {
131
139
 
132
140
  <div class={className}>
133
141
 
134
- {file && <>
135
- <div class="preview">
136
-
137
- {previewUrl ? (
138
- <img src={previewUrl} />
139
- ) : typeof file === 'string' ? <>
142
+ {button ? <>
143
+
144
+ <Button type="secondary"
145
+ {...button === true ? {} : button}
146
+ >
147
+ {emptyText}
148
+ </Button>
149
+
150
+ </> : <>
151
+
152
+ {file && <>
153
+ <div class="preview">
154
+
155
+ {previewUrl ? (
156
+ <img src={previewUrl} />
157
+ ) : typeof file === 'string' ? <>
158
+ <strong>A file has been selected</strong>
159
+ </> : file ? <>
160
+ <strong>{file.name}</strong>
161
+ </> : null}
162
+ </div>
163
+
164
+ <div class="row actions sp-05">
165
+
166
+ {typeof file === 'string' && <>
167
+ <Button type="secondary" icon="eye" shape="pill" size="s" link={file} />
168
+ </>}
169
+
170
+ <Button class='bg error' icon="trash" shape="pill" size="s"
171
+ async onClick={() => onChange(undefined)} />
172
+ </div>
173
+ </>}
174
+
175
+ <div class="indication col al-center">
176
+ {typeof file === 'string' ? <>
140
177
  <strong>A file has been selected</strong>
141
178
  </> : file ? <>
142
179
  <strong>{file.name}</strong>
143
- </> : null}
144
- </div>
145
-
146
- <div class="row actions sp-05">
147
-
148
- {typeof file === 'string' && <>
149
- <Bouton type="secondary" icon="eye" shape="pill" size="s" link={file} />
150
- </>}
151
-
152
- <Bouton class='bg error' icon="trash" shape="pill" size="s"
153
- async onClick={() => onChange(undefined)} />
180
+ </> : emptyText}
154
181
  </div>
182
+
155
183
  </>}
156
184
 
157
- <div class="indication col al-center">
158
- {emptyText}
159
- </div>
160
-
161
185
  <input type="file" onChange={selectFile} />
162
186
  </div>
163
187
  </InputWrapper>
@@ -255,8 +255,9 @@ export default class SQL extends Service<Config, Hooks, Application, Services> {
255
255
  }).join(' ').trim();
256
256
  }
257
257
 
258
- public equalities = (data: TObjetDonnees, keys = Object.keys(data)) =>
259
- keys.map(k => '' + k + ' = ' + this.esc( data[k] ))
258
+ public equalities = (data: TObjetDonnees, forStorage: boolean = false) => {
259
+ return Object.keys(data).map(k => '' + k + ' = ' + this.esc( data[k], forStorage ))
260
+ }
260
261
 
261
262
  /*----------------------------------
262
263
  - OPERATIONS: LOW LEVELf
@@ -380,7 +381,7 @@ export default class SQL extends Service<Config, Hooks, Application, Services> {
380
381
  }
381
382
 
382
383
  // Create equalities
383
- const egalitesData = this.equalities(data).join(', ')
384
+ const egalitesData = this.equalities(data, true).join(', ')
384
385
  const egalitesWhere = this.equalities(where).join(' AND ')
385
386
 
386
387
  // Build query
@@ -71,7 +71,7 @@ export default abstract class FsDriver<
71
71
  bucketName: TBucketName,
72
72
  filename: string,
73
73
  options: TReadFileOptions
74
- ): Promise<string>;
74
+ ): Promise<Buffer>;
75
75
 
76
76
  public abstract createReadStream( bucketName: TBucketName, filename: string );
77
77
 
@@ -76,7 +76,9 @@ export default class LocalFS<
76
76
  bucketName: TBucketName,
77
77
  filename: string
78
78
  ) {
79
- throw new Error("Method not available for local files.");
79
+ const bucketDir = this.config.buckets[bucketName];
80
+ const fullPath = path.join( this.rootDir, bucketDir, filename || '.' );
81
+ return fullPath;
80
82
  }
81
83
 
82
84
  public async readDir( bucketName: TBucketName, dirname?: string ) {
@@ -135,7 +137,7 @@ export default class LocalFS<
135
137
  const fullPath = path.join( this.rootDir, bucketDir, filename );
136
138
 
137
139
  this.config.debug && console.log(`readFile ${fullPath}`);
138
- return fs.readFileSync( fullPath ).toString();
140
+ return fs.readFileSync( fullPath );
139
141
  }
140
142
 
141
143
  public createReadStream( bucketName: TBucketName, filename: string ) {
@@ -605,8 +605,8 @@ declare type Routes = {
605
605
  } else {
606
606
 
607
607
  // For debugging HTTP errors
608
- if (this.app.env.profile === "dev")
609
- console.warn(e);
608
+ /*if (this.app.env.profile === "dev")
609
+ console.warn(e);*/
610
610
 
611
611
  await this.app.runHook('error.' + code, e, request);
612
612
  }
@@ -24,7 +24,21 @@ import ServerResponse from '../response';
24
24
  - TYPES
25
25
  ----------------------------------*/
26
26
 
27
- const localeFilter = (input: any) => typeof input === 'string' && ISO6391.validate(input) ? input : undefined;
27
+ const localeFilter = (input: any) => {
28
+
29
+ // Data type
30
+ if (typeof input !== 'string')
31
+ return;
32
+
33
+ // Extract ISO code
34
+ let lang = input.trim().split(/[-_]/)[0].toLowerCase();
35
+
36
+ // Check size
37
+ if (!ISO6391.validate(lang))
38
+ return;
39
+
40
+ return lang.toUpperCase();
41
+ }
28
42
 
29
43
  export type UploadedFile = With<FileToUpload, 'md5'|'ext'>
30
44
 
@@ -310,8 +310,15 @@ export default class ServerResponse<
310
310
  }
311
311
 
312
312
  // envoi filename
313
- const file = await disk.readFile('data', filename, {});
313
+ const file = await disk.readFile('data', filename, {
314
+ encoding: 'buffer'
315
+ });
314
316
  this.data = file;
317
+
318
+
319
+ // Mimetype
320
+ this.headers['Content-Type'] = 'image/jpeg';
321
+
315
322
  return this.end();
316
323
  }
317
324
 
@@ -29,7 +29,7 @@ type LexicalState = {
29
29
  root: LexicalNode
30
30
  }
31
31
 
32
- type LexicalNode = {
32
+ export type LexicalNode = {
33
33
  version: number,
34
34
  type: string,
35
35
  children?: LexicalNode[],
@@ -37,31 +37,43 @@ export class Slug {
37
37
 
38
38
  // Check if already existing
39
39
  if (SQL !== undefined) {
40
-
41
- const escapedSlug = escapeStringRegexp(slug);
42
-
43
- const duplicates = await SQL.selectVal<number>(`
44
- SELECT
45
- IF( ${column} LIKE ${SQL.esc(slug)},
46
- 1,
47
- CAST(SUBSTRING_INDEX(slug, '-', -1) AS UNSIGNED)
48
- ) AS duplicates
49
- FROM ${table}
50
- WHERE
51
- ${column} LIKE ${SQL.esc(slug)}
52
- OR
53
- ${column} REGEXP '^${escapedSlug}-[0-9]+$'
54
- ORDER BY duplicates DESC
55
- LIMIT 1
56
- `);
57
-
58
- if (duplicates && duplicates > 0)
59
- slug += `-${duplicates + 1}`;
40
+ slug = await this.Correct(slug, SQL, table, column);
60
41
  }
61
42
 
62
43
  return slug;
63
44
  }
64
45
 
46
+ public async Correct(
47
+ slug: string,
48
+ SQL: SQL,
49
+ table: string,
50
+ column: string
51
+ ) {
52
+
53
+ const escapedSlug = escapeStringRegexp(slug);
54
+
55
+ const duplicates = await SQL.selectVal<number>(`
56
+ SELECT
57
+ IF( ${column} LIKE ${SQL.esc(slug)},
58
+ 1,
59
+ CAST(SUBSTRING_INDEX(slug, '-', -1) AS UNSIGNED)
60
+ ) AS duplicates
61
+ FROM ${table}
62
+ WHERE
63
+ ${column} LIKE ${SQL.esc(slug)}
64
+ OR
65
+ ${column} REGEXP '^${escapedSlug}-[0-9]+$'
66
+ ORDER BY duplicates DESC
67
+ LIMIT 1
68
+ `);
69
+
70
+ if (duplicates && duplicates > 0)
71
+ slug += `-${duplicates + 1}`;
72
+
73
+ return slug;
74
+
75
+ }
76
+
65
77
  }
66
78
 
67
79
  export default new Slug;