tsoft-cli 1.2.1 → 1.2.2

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/CHANGELOG.md CHANGED
@@ -28,3 +28,20 @@
28
28
  ### Fixed
29
29
  - Geliştirme ortamı başlatıldığında programın beklenmedik şekilde kapanmasına sebep olan hata giderildi.
30
30
  - T-Soft CLI'nın `start.js` dosyasında initialize fonksiyonunun doğru şekilde çalışmaması sorunu çözüldü.
31
+
32
+ # Changelog
33
+
34
+ ## [1.2.2] - 2024-06-14
35
+ ### Added
36
+ - Kurtarma anahtarı ile tema senkronizasyonu yapan `syncTheme` fonksiyonu eklendi.
37
+ - `syncTheme` fonksiyonu zip dosyasını indirip açma işlemi gerçekleştiriyor.
38
+ - Tema bilgilerini içeren `.theme` dosyası oluşturma ve `theme.env` dosyası yaratma işlemleri eklendi.
39
+ - Kullanıcı komut satırı etkileşimleri için `enquirer` kütüphanesi kullanıldı.
40
+
41
+ ### Changed
42
+ - `unzipFile` fonksiyonu eklendi, zip dosyalarını açmak için kullanılıyor.
43
+ - `sync.js` dosyasında kullanıcıdan kurtarma anahtarı alınarak gerekli işlemlerin yapılması sağlandı.
44
+
45
+ ### Fixed
46
+ - Zip dosyasının indirildikten sonra otomatik olarak silinmesi sağlandı.
47
+ - `sync.js` dosyasında oluşan hatalar giderildi ve kod kalitesi iyileştirildi.
package/README.md CHANGED
@@ -1,8 +1,3 @@
1
- <style>
2
- .container { max-width: 800px; margin: 0 auto; padding: 20px; box-shadow: 0 0 10px rgba(0,0,0,0.1); }
3
- </style>
4
- T-Soft CLI Kullanım Kılavuzu
5
-
6
1
  T-Soft CLI Kullanım Kılavuzu
7
2
  ============================
8
3
 
package/bin/index.js CHANGED
@@ -1,9 +1,10 @@
1
1
  #!/usr/bin/env node
2
2
 
3
- const { Select } = require('enquirer');
4
- const { start } = require('../src/commands/start');
5
- const { createTheme } = require('../src/commands/create');
6
- const { clearScreen, displayAsciiArt } = require('../src/utils');
3
+ const {Select} = require('enquirer');
4
+ const {start} = require('../src/commands/start');
5
+ const {syncTheme} = require('../src/commands/sync'); // Yeni komut dosyasını ekle
6
+ const {createTheme} = require('../src/commands/create');
7
+ const {clearScreen, displayAsciiArt} = require('../src/utils');
7
8
  const fs = require('fs');
8
9
  const path = require('path');
9
10
 
@@ -42,14 +43,14 @@ async function selectSiteAndTheme() {
42
43
 
43
44
  const selectedTheme = await selectFromChoices('Bir tema seçin:', themes);
44
45
 
45
- return { siteName: selectedSite, themeName: selectedTheme };
46
+ return {siteName: selectedSite, themeName: selectedTheme};
46
47
  }
47
48
 
48
49
  async function showMainMenu() {
49
50
  clearScreen();
50
51
  await displayAsciiArt();
51
52
 
52
- const commandChoices = ['Yeni bir tema oluştur', 'Geliştirme ortamını başlat', 'Çıkış'];
53
+ const commandChoices = ['Yeni bir tema oluştur', 'Geliştirme ortamını başlat', 'Uzak sunucudan dosyaları indir', 'Çıkış'];
53
54
  const selectedCommand = await selectFromChoices('Bir komut seçin', commandChoices);
54
55
 
55
56
  switch (selectedCommand) {
@@ -62,6 +63,9 @@ async function showMainMenu() {
62
63
  await start(selection.siteName, selection.themeName);
63
64
  }
64
65
  break;
66
+ case 'Uzak sunucudan dosyaları indir':
67
+ await syncTheme();
68
+ break;
65
69
  case 'Çıkış':
66
70
  console.log('Programdan çıkılıyor. Hoşça kalın!');
67
71
  process.exit(0);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tsoft-cli",
3
- "version": "1.2.1",
3
+ "version": "1.2.2",
4
4
  "description": "A theme development cli for developers who want to create themes for T-Soft.",
5
5
  "main": "index.js",
6
6
  "scripts": {
@@ -18,7 +18,8 @@
18
18
  "commander": "^12.1.0",
19
19
  "enquirer": "^2.4.1",
20
20
  "figlet": "^1.7.0",
21
- "fs": "^0.0.1-security"
21
+ "fs": "^0.0.1-security",
22
+ "unzipper": "^0.12.1"
22
23
  },
23
24
  "type": "commonjs",
24
25
  "devDependencies": {
@@ -1,4 +1,4 @@
1
- const buildPostRequest = require('./request');
1
+ const {buildPostRequest} = require('./request');
2
2
 
3
3
  class ClientCredentials {
4
4
  site;
@@ -29,6 +29,11 @@ class ClientCredentials {
29
29
  return this;
30
30
  }
31
31
 
32
+ setClientId(clientId) {
33
+ this.clientId = clientId;
34
+ return this;
35
+ }
36
+
32
37
  async register(CLIENT_UUID, clientConfiguration = {}) {
33
38
 
34
39
  const uri = "api/v3/admin/auth/auth-application";
@@ -37,7 +42,7 @@ class ClientCredentials {
37
42
  'Content-Type': 'application/json', 'Accept': 'application/json',
38
43
  }, body: JSON.stringify({
39
44
  uuid: CLIENT_UUID, configuration: {
40
- theme: clientConfiguration.theme,
45
+ name: clientConfiguration.name,
41
46
  author: clientConfiguration.author,
42
47
  version: clientConfiguration.version
43
48
  }
@@ -55,14 +60,19 @@ class ClientCredentials {
55
60
 
56
61
  async authorize() {
57
62
  const uri = "api/v3/admin/auth/auth-application/authorize";
58
- await this.buildPostRequest(uri, {
63
+ return await this.buildPostRequest(uri, {
59
64
  body: JSON.stringify({
60
65
  public_key: this.clientId, secret: this.clientSecret
61
66
  })
62
67
  }).then((result) => {
63
68
  if (result.status === true) {
64
69
  this.bearer = result.data.token.plainTextToken
70
+ return result;
65
71
  }
72
+ return false;
73
+ }).catch((error) => {
74
+ console.error('Hata:', error.message);
75
+ return false;
66
76
  });
67
77
 
68
78
  }
@@ -83,6 +93,20 @@ class ClientCredentials {
83
93
  });
84
94
  return response.message === 'ok';
85
95
  }
96
+
97
+ async recovery(token) {
98
+ const uri = 'api/v3/admin/auth/auth-application/recovery/' + token;
99
+
100
+ const response = await buildPostRequest(this.site, uri);
101
+
102
+ if (response.status) {
103
+ return {
104
+ secret: response.data.secret,
105
+ public_key: response.data.public_key
106
+ }
107
+ }
108
+
109
+ }
86
110
  }
87
111
 
88
112
  module.exports = ClientCredentials;
@@ -1,8 +1,8 @@
1
1
  const fs = require('fs');
2
2
  const path = require('path');
3
- const { Select, Input } = require('enquirer');
4
- const { slugify } = require('../utils');
5
- const { start } = require('./start');
3
+ const {Select, Input} = require('enquirer');
4
+ const {slugify} = require('../utils');
5
+ const {start} = require('./start');
6
6
  const ThemeManager = require('../theme-manager');
7
7
 
8
8
  async function getSites() {
@@ -79,7 +79,7 @@ async function getThemeDetails() {
79
79
  const author = await authorPrompt.run();
80
80
  const version = await versionPrompt.run();
81
81
 
82
- return { themeName, author, version };
82
+ return {themeName, author, version};
83
83
  }
84
84
 
85
85
  async function createThemeDirectory(siteName, themeNameSlug) {
@@ -87,7 +87,7 @@ async function createThemeDirectory(siteName, themeNameSlug) {
87
87
  const themePath = path.join(cwd, siteName, themeNameSlug);
88
88
 
89
89
  if (!fs.existsSync(themePath)) {
90
- fs.mkdirSync(themePath, { recursive: true });
90
+ fs.mkdirSync(themePath, {recursive: true});
91
91
  }
92
92
 
93
93
  return themePath;
@@ -103,13 +103,13 @@ async function createTheme() {
103
103
 
104
104
  if (!siteName) return;
105
105
 
106
- const { themeName, author, version } = await getThemeDetails();
106
+ const {themeName, author, version} = await getThemeDetails();
107
107
  const themeNameSlug = slugify(themeName);
108
108
  const themePath = await createThemeDirectory(siteName, themeNameSlug);
109
109
 
110
110
  const themeData = {
111
111
  site: siteName,
112
- theme: themeName,
112
+ name: themeName,
113
113
  author: author,
114
114
  version: version
115
115
  };
@@ -118,10 +118,9 @@ async function createTheme() {
118
118
 
119
119
  console.log(`Tema "${themeName}" başarıyla oluşturuldu.`);
120
120
 
121
- // Doğrudan start fonksiyonuna geçiş yap
122
121
  await start(siteName, themeNameSlug);
123
122
  }
124
123
 
125
124
  module.exports = {
126
- createTheme
125
+ createTheme, createThemeDirectory, selectSite
127
126
  };
@@ -231,4 +231,35 @@ async function start(siteName, themeName) {
231
231
  }
232
232
  }
233
233
 
234
+ async function updateTheme(tsoft, theme) {
235
+ const directoryName = path.basename(path.join(process.cwd(), tsoft.site, theme));
236
+ const response = await tsoft.updateTheme(directoryName);
237
+ if (response.status === true) {
238
+ return 'Successfully updated';
239
+ } else {
240
+ throw new Error('Update failed');
241
+ }
242
+ }
243
+ async function editThemeFile(themeManager, directoryName) {
244
+ const themePath = path.join(process.cwd(), themeManager.site, directoryName, '.theme');
245
+
246
+ if (!fs.existsSync(themePath)) {
247
+ console.error('.theme file not found.');
248
+ return;
249
+ }
250
+
251
+ console.log(`Opening .theme file: ${themePath}`);
252
+ const openCommand = process.platform === 'win32' ? 'start' :
253
+ process.platform === 'darwin' ? 'open' :
254
+ 'xdg-open';
255
+
256
+ exec(`${openCommand} ${themePath}`, (err) => {
257
+ if (err) {
258
+ console.error('Failed to open .theme file:', err);
259
+ } else {
260
+ console.log('.theme file opened successfully.');
261
+ }
262
+ });
263
+ }
264
+
234
265
  module.exports = { start };
@@ -0,0 +1,80 @@
1
+ const fs = require('fs');
2
+ const path = require('path');
3
+ const {Input} = require('enquirer');
4
+ const {clearScreen} = require('../utils');
5
+ const {selectSite, createThemeDirectory} = require('./create');
6
+ const Tsoft = require("../tsoft");
7
+ const {slugify} = require('../utils');
8
+ const unzipper = require('unzipper');
9
+
10
+ function unzipFile(zipFilePath, extractToDir) {
11
+ return new Promise((resolve, reject) => {
12
+ fs.createReadStream(zipFilePath)
13
+ .pipe(unzipper.Extract({path: extractToDir}))
14
+ .on('close', resolve)
15
+ .on('error', reject);
16
+ });
17
+ }
18
+
19
+ async function syncTheme() {
20
+ const cwd = process.cwd();
21
+ const sites = fs.readdirSync(cwd).filter(file => {
22
+ return file.charAt(0) !== '.' && !['node_modules', 'build', 'dist'].includes(file);
23
+ }).filter(file => fs.statSync(path.join(cwd, file)).isDirectory());
24
+
25
+ const selectedSite = await selectSite(sites);
26
+
27
+ const tsoft = new Tsoft(selectedSite);
28
+
29
+ const codePrompt = new Input({
30
+ name: 'code',
31
+ message: 'Lütfen kurtarma anahtarını girin:'
32
+ });
33
+
34
+ const recoveryCode = await codePrompt.run();
35
+
36
+
37
+ const {secret, public_key} = await tsoft.startRecovery(recoveryCode);
38
+
39
+ tsoft.clientCredentials.setClientSecret(secret).setClientId(public_key)
40
+ const authorizeResponse = await tsoft.clientCredentials.authorize(true)
41
+ const themeInformation = authorizeResponse.data.tokenable;
42
+
43
+ const themeName = themeInformation.name;
44
+ const themeNameSlug = slugify(themeName);
45
+ const themePath = await createThemeDirectory(selectedSite, themeNameSlug);
46
+
47
+ const themeData = {
48
+ site: selectedSite,
49
+ name: themeName,
50
+ author: themeInformation.author,
51
+ version: themeInformation.version
52
+ };
53
+
54
+ fs.writeFileSync(path.join(themePath, '.theme'), JSON.stringify(themeData, null, 2));
55
+ tsoft.themeManager.setTheme(themeNameSlug)
56
+
57
+
58
+ if (!fs.existsSync(themePath)) {
59
+ fs.mkdirSync(themePath, {recursive: true});
60
+ }
61
+
62
+ clearScreen();
63
+
64
+ const zipFilePath = path.join(themePath, 'theme.zip');
65
+
66
+ console.log('Zip dosyası indiriliyor...');
67
+ await tsoft.fileManager.downloadAndSaveZip(themePath, zipFilePath, tsoft.clientCredentials.bearer);
68
+ console.log('İndirme tamamlandı.');
69
+
70
+ console.log('Dosyalar çıkarılıyor...');
71
+ await unzipFile(zipFilePath, themePath);
72
+ console.log('Çıkarma işlemi tamamlandı.');
73
+ fs.unlinkSync(zipFilePath);
74
+
75
+ tsoft.buildEnvironment();
76
+ }
77
+
78
+ module.exports = {
79
+ syncTheme
80
+ };
@@ -1,6 +1,8 @@
1
1
  const fs = require('fs');
2
2
  const path = require('path');
3
3
  const utils = require('./utils');
4
+ const { exec } = require('child_process');
5
+ const {buildDownloadZipRequest} = require('./request');
4
6
 
5
7
  class FileManager {
6
8
  constructor(site) {
@@ -34,6 +36,35 @@ class FileManager {
34
36
  const ext = path.extname(file).substring(1);
35
37
  return utils.allowedExtensions.includes(ext);
36
38
  }
39
+
40
+ async downloadAndSaveZip(saveToDir, zipFilePath, bearerToken) {
41
+ // Fetch the zip file and save it
42
+ const response = await buildDownloadZipRequest(this.site, `api/v3/admin/online-store-2/theme/download-theme`, {
43
+ headers: {
44
+ 'Content-Type': 'application/zip',
45
+ 'Accept': 'application/zip',
46
+ 'Authorization': `Bearer ${bearerToken}`
47
+ }
48
+ });
49
+
50
+
51
+ fs.writeFileSync(zipFilePath, Buffer.from(response));
52
+
53
+ console.log(`Zip dosyası ${zipFilePath} konumuna kaydedildi.`);
54
+
55
+ // Open the directory in file explorer
56
+ const openCommand = process.platform === 'win32' ? 'start' :
57
+ process.platform === 'darwin' ? 'open' :
58
+ 'xdg-open';
59
+ exec(`${openCommand} ${saveToDir}`, (err) => {
60
+ if (err) {
61
+ console.error('Dizin açılamadı:', err);
62
+ } else {
63
+ console.log(`Dizin açıldı: ${saveToDir}`);
64
+ console.log('Lütfen zip dosyasını bu dizine çıkartın.');
65
+ }
66
+ });
67
+ }
37
68
  }
38
69
 
39
70
  module.exports = FileManager;
package/src/request.js CHANGED
@@ -1,4 +1,4 @@
1
- module.exports = (site, uri, options = {}) => {
1
+ buildPostRequest = (site, uri, options = {}) => {
2
2
  return fetch("https://" + site + '/' + uri, {
3
3
  method: 'POST',
4
4
  headers: {
@@ -14,3 +14,24 @@ module.exports = (site, uri, options = {}) => {
14
14
  })
15
15
  .catch((error) => console.error(error));
16
16
  }
17
+ buildDownloadZipRequest = (site, uri, options = {}) => {
18
+ return fetch("https://" + site + '/' + uri, {
19
+ method: 'POST',
20
+ headers: {
21
+ 'Content-Type': 'application/zip',
22
+ 'Accept': 'application/zip',
23
+ ...options.headers ?? {}
24
+ },
25
+ body: options.body
26
+ })
27
+ .then((response) => response.arrayBuffer())
28
+ .then((result) => {
29
+ return result
30
+ })
31
+ .catch((error) => console.error(error));
32
+ }
33
+
34
+ module.exports = {
35
+ buildPostRequest,
36
+ buildDownloadZipRequest
37
+ }
@@ -54,6 +54,9 @@ class ThemeManager {
54
54
  return true;
55
55
  }
56
56
 
57
+ setTheme(theme) {
58
+ this.theme = slugify(theme)
59
+ }
57
60
  isRegistered() {
58
61
  return this.registered;
59
62
  }
package/src/tsoft.js CHANGED
@@ -3,7 +3,7 @@ const constants = require('./constants');
3
3
  const FileManager = require('./file-manager');
4
4
  const ThemeManager = require('./theme-manager');
5
5
  const path = require("path");
6
- const buildPostRequest = require('./request');
6
+ const {buildPostRequest} = require('./request');
7
7
 
8
8
  class Tsoft {
9
9
  static TSOFT_CLI_UUID = '7583a318-8542-4ec8-980c-48ea67031be3';
@@ -49,7 +49,7 @@ class Tsoft {
49
49
  const fileName = this.fileManager.getRelativePath(theme, file);
50
50
  const content = this.fileManager.readFile(file);
51
51
  const env = this.themeManager.getEnvironment(theme);
52
- const result = await buildPostRequest(this.site, Tsoft.ONLINESTORE_SAVE_URI, {
52
+ await buildPostRequest(this.site, Tsoft.ONLINESTORE_SAVE_URI, {
53
53
  headers: {
54
54
  Authorization: `Bearer ${env.bearer}`
55
55
  },
@@ -133,6 +133,10 @@ class Tsoft {
133
133
  });
134
134
  }
135
135
 
136
+ async startRecovery(token) {
137
+ return await this.clientCredentials.recovery(token);
138
+ }
139
+
136
140
  }
137
141
 
138
142
  module.exports = Tsoft;