├── .gitignore ├── LICENSE ├── README.md ├── chakra-ui ├── .gitignore ├── .meteor │ ├── .finished-upgraders │ ├── .gitignore │ ├── .id │ ├── packages │ ├── platforms │ ├── release │ └── versions ├── README.md ├── client │ ├── main.html │ └── main.js ├── imports │ └── ui │ │ ├── App.js │ │ ├── HeroCallToAction.js │ │ └── Navbar.js ├── package-lock.json ├── package.json └── server │ └── main.js ├── complex-todos-svelte ├── .deploy │ ├── mup.js │ └── settings.json ├── .gitignore ├── .meteor │ ├── .finished-upgraders │ ├── .gitignore │ ├── .id │ ├── packages │ ├── platforms │ ├── release │ └── versions ├── LICENSE ├── README.md ├── client │ ├── init.js │ ├── main.css │ ├── main.html │ ├── main.js │ └── ui │ │ ├── About.svelte │ │ ├── App.svelte │ │ ├── Task.svelte │ │ ├── TaskAddNewForm.svelte │ │ └── Tasks.svelte ├── cypress.json ├── cypress │ ├── fixtures │ │ └── example.json │ ├── integration │ │ ├── constants │ │ │ └── test.js │ │ ├── tests │ │ │ ├── 1.prepareTestEnvironment.test.js │ │ │ ├── authentication.test.js │ │ │ ├── navigation.test.js │ │ │ └── tasks.test.js │ │ └── utilities │ │ │ ├── commons.js │ │ │ ├── doLogin.js │ │ │ └── doLogout.js │ ├── plugins │ │ └── index.js │ ├── readme.md │ └── support │ │ ├── commands.js │ │ └── index.js ├── imports │ ├── modules │ │ ├── eventEmitter │ │ │ ├── eventEmitterService.js │ │ │ └── server │ │ │ │ └── index.js │ │ ├── tasks │ │ │ ├── database │ │ │ │ └── tasks.js │ │ │ ├── enums │ │ │ │ ├── methodNames.js │ │ │ │ ├── publications.js │ │ │ │ └── rateLimitter.js │ │ │ ├── server │ │ │ │ ├── index.js │ │ │ │ ├── tasks.ensureIndexes.js │ │ │ │ ├── tasks.events.js │ │ │ │ ├── tasks.guards.js │ │ │ │ ├── tasks.publications.js │ │ │ │ └── tasks.rateLimiter.js │ │ │ ├── taskRepository.js │ │ │ ├── taskService.js │ │ │ ├── tasks.methods.js │ │ │ └── tasks.methods.test.js │ │ └── users │ │ │ ├── enums │ │ │ └── cacheKey.js │ │ │ └── server │ │ │ ├── index.js │ │ │ └── user.cache.js │ └── shared │ │ ├── enums │ │ └── events.js │ │ ├── functions │ │ ├── bound.js │ │ ├── isDefined.js │ │ ├── lang.js │ │ └── user.js │ │ ├── logger │ │ └── logger.js │ │ ├── mixins │ │ └── LoggedInMixin.js │ │ ├── repository │ │ └── baseRepository.js │ │ └── utilities │ │ └── dateUtility.js ├── package-lock.json ├── package.json ├── packages │ ├── logger │ │ ├── .github │ │ │ ├── FUNDING.yml │ │ │ ├── ISSUE_TEMPLATE │ │ │ └── PULL_REQUEST_TEMPLATE │ │ ├── .gitignore │ │ ├── .versions │ │ ├── CHANGELOG.md │ │ ├── CODE_OF_CONDUCT.md │ │ ├── CONTRIBUTING.md │ │ ├── HISTORY.md │ │ ├── LICENSE │ │ ├── README.md │ │ ├── logger-tests.js │ │ ├── logger.js │ │ ├── meteor-logger.jpg │ │ └── package.js │ └── readme.md ├── screenshot.jpg ├── server │ ├── init.js │ ├── main.js │ ├── modules.js │ ├── modules │ │ ├── cache │ │ │ ├── cacheService.js │ │ │ └── server │ │ │ │ └── index.js │ │ ├── dummies │ │ │ ├── dummiesService.js │ │ │ ├── fixtures │ │ │ │ ├── dummyTasks.js │ │ │ │ └── dummyUsers.js │ │ │ ├── readme.md │ │ │ └── server │ │ │ │ ├── dummies.methods.js │ │ │ │ └── index.js │ │ ├── jobs │ │ │ └── server │ │ │ │ ├── index.js │ │ │ │ └── tasks.expire.js │ │ └── migrations │ │ │ ├── database │ │ │ └── migrations.js │ │ │ ├── migrationRepository.js │ │ │ ├── migrationService.js │ │ │ ├── readme.md │ │ │ └── server │ │ │ ├── 1.0.1.js │ │ │ ├── index.js │ │ │ └── migrations.guards.js │ └── shared │ │ └── enums │ │ └── job.js ├── settings.json └── tests │ ├── enums │ └── users.js │ ├── main.js │ ├── package.json.test.js │ └── readme.md ├── cordova ├── .gitignore ├── .meteor │ ├── .gitignore │ ├── cordova-plugins │ ├── packages │ ├── platforms │ ├── release │ └── versions ├── README.md ├── client │ ├── main.css │ ├── main.html │ └── main.js ├── imports │ ├── collections │ │ └── links.js │ ├── infra │ │ ├── addPlayerId.js │ │ ├── apple-app-site-association.js │ │ ├── constants.js │ │ ├── database-seed.js │ │ ├── google-analytics.js │ │ ├── meta-tags.js │ │ ├── methodCall.js │ │ ├── native.js │ │ ├── one-signal.js │ │ ├── pwa-json.js │ │ ├── rest.js │ │ ├── sendPush.js │ │ └── serviceWorkerInit.js │ ├── methods │ │ └── createUser.js │ └── ui │ │ ├── App.js │ │ ├── Hello.js │ │ ├── Info.js │ │ └── User.js ├── mobile-config.js ├── package-lock.json ├── package.json ├── private │ ├── env │ │ └── production │ │ │ └── settings.json │ ├── jenkins.groovy │ └── native-app │ │ └── production │ │ ├── build.sh │ │ ├── publish-android.sh │ │ └── publish-ios.sh ├── public │ └── sw.js └── server │ └── main.js ├── nft-marketplace ├── .gitignore ├── .meteor │ ├── .finished-upgraders │ ├── .gitignore │ ├── .id │ ├── packages │ ├── platforms │ ├── release │ └── versions ├── README.md ├── app │ └── ui │ │ ├── AccountPage.jsx │ │ ├── App.jsx │ │ ├── ConnectPage.jsx │ │ ├── DetailsPage.jsx │ │ ├── HomePage.jsx │ │ ├── SellNftPage.jsx │ │ ├── common │ │ ├── CategoryOptions.jsx │ │ ├── CheckAccount.jsx │ │ ├── ConnectAccount.jsx │ │ ├── CurrentAccount.jsx │ │ ├── Footer.jsx │ │ ├── NavBar.jsx │ │ ├── RoutePaths.jsx │ │ ├── Routes.jsx │ │ └── SortOptions.jsx │ │ ├── components │ │ ├── Button.jsx │ │ ├── Card.jsx │ │ └── Fields │ │ │ ├── InputField.jsx │ │ │ ├── Select.jsx │ │ │ └── useField.jsx │ │ └── util │ │ ├── formatPrice.js │ │ └── usePriceConverter.js ├── client │ ├── main.css │ ├── main.html │ └── main.jsx ├── config.js ├── contracts │ └── NFTMarketplace.sol ├── hardhat.config.js ├── package-lock.json ├── package.json ├── postcss.config.js ├── public │ └── images │ │ ├── bg-stars.svg │ │ ├── default-profile-avatar.png │ │ ├── logo.png │ │ └── metamask-logo.png ├── scripts │ └── deploy.js ├── server │ └── main.js ├── tailwind.config.js └── tests │ ├── hardhat.js │ └── main.js ├── parties ├── .gitignore ├── .meteor │ ├── .finished-upgraders │ ├── .gitignore │ ├── .id │ ├── packages │ ├── platforms │ ├── release │ └── versions ├── client │ ├── main.css │ ├── main.html │ └── main.js ├── imports │ └── model.js ├── package-lock.json ├── package.json ├── public │ └── soma.png ├── server │ └── main.js └── tests │ └── main.js ├── tailwindcss ├── .gitignore ├── .meteor │ ├── .finished-upgraders │ ├── .gitignore │ ├── .id │ ├── packages │ ├── platforms │ ├── release │ └── versions ├── .postcssrc.js ├── README.md ├── client │ ├── main.css │ ├── main.html │ └── main.js ├── imports │ └── ui │ │ ├── App.js │ │ ├── Dashboard.js │ │ └── List.js ├── package-lock.json ├── package.json ├── public │ └── logo.svg ├── server │ └── main.js └── tailwind.config.js └── tic-tac-toe ├── .gitignore ├── .meteor ├── .finished-upgraders ├── .gitignore ├── .id ├── packages ├── platforms ├── release └── versions ├── README.md ├── client ├── main.css ├── main.html └── main.jsx ├── imports ├── api │ └── rooms.js └── ui │ ├── App.jsx │ ├── GameScreen.jsx │ ├── RoomList.jsx │ └── game.css ├── package-lock.json ├── package.json ├── public ├── circle.png └── cross.png └── server └── main.js /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | lerna-debug.log* 8 | 9 | # Diagnostic reports (https://nodejs.org/api/report.html) 10 | report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json 11 | 12 | # Runtime data 13 | pids 14 | *.pid 15 | *.seed 16 | *.pid.lock 17 | 18 | # Directory for instrumented libs generated by jscoverage/JSCover 19 | lib-cov 20 | 21 | # Coverage directory used by tools like istanbul 22 | coverage 23 | *.lcov 24 | 25 | # nyc test coverage 26 | .nyc_output 27 | 28 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) 29 | .grunt 30 | 31 | # Bower dependency directory (https://bower.io/) 32 | bower_components 33 | 34 | # node-waf configuration 35 | .lock-wscript 36 | 37 | # Compiled binary addons (https://nodejs.org/api/addons.html) 38 | build/Release 39 | 40 | # Dependency directories 41 | node_modules/ 42 | jspm_packages/ 43 | 44 | # TypeScript v1 declaration files 45 | typings/ 46 | 47 | # TypeScript cache 48 | *.tsbuildinfo 49 | 50 | # Optional npm cache directory 51 | .npm 52 | 53 | # Optional eslint cache 54 | .eslintcache 55 | 56 | # Microbundle cache 57 | .rpt2_cache/ 58 | .rts2_cache_cjs/ 59 | .rts2_cache_es/ 60 | .rts2_cache_umd/ 61 | 62 | # Optional REPL history 63 | .node_repl_history 64 | 65 | # Output of 'npm pack' 66 | *.tgz 67 | 68 | # Yarn Integrity file 69 | .yarn-integrity 70 | 71 | # dotenv environment variables file 72 | .env 73 | .env.test 74 | 75 | # parcel-bundler cache (https://parceljs.org/) 76 | .cache 77 | 78 | # Next.js build output 79 | .next 80 | 81 | # Nuxt.js build / generate output 82 | .nuxt 83 | dist 84 | 85 | # Gatsby files 86 | .cache/ 87 | # Comment in the public line in if your project uses Gatsby and *not* Next.js 88 | # https://nextjs.org/blog/next-9-1#public-directory-support 89 | # public 90 | 91 | # vuepress build output 92 | .vuepress/dist 93 | 94 | # Serverless directories 95 | .serverless/ 96 | 97 | # FuseBox cache 98 | .fusebox/ 99 | 100 | # DynamoDB Local files 101 | .dynamodb/ 102 | 103 | # TernJS port file 104 | .tern-port 105 | 106 | # Intelij IDEs project configuration folder 107 | .idea 108 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 Meteor 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /chakra-ui/.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | 8 | # Runtime data 9 | pids 10 | *.pid 11 | *.seed 12 | *.pid.lock 13 | 14 | # Directory for instrumented libs generated by jscoverage/JSCover 15 | lib-cov 16 | 17 | # Coverage directory used by tools like istanbul 18 | coverage 19 | 20 | # nyc test coverage 21 | .nyc_output 22 | 23 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 24 | .grunt 25 | 26 | # Bower dependency directory (https://bower.io/) 27 | bower_components 28 | 29 | # node-waf configuration 30 | .lock-wscript 31 | 32 | # Compiled binary addons (https://nodejs.org/api/addons.html) 33 | build/Release 34 | 35 | # Dependency directories 36 | node_modules/ 37 | jspm_packages/ 38 | 39 | # TypeScript v1 declaration files 40 | typings/ 41 | 42 | # Optional npm cache directory 43 | .npm 44 | 45 | # Optional eslint cache 46 | .eslintcache 47 | 48 | # Optional REPL history 49 | .node_repl_history 50 | 51 | # Output of 'npm pack' 52 | *.tgz 53 | 54 | # Yarn Integrity file 55 | .yarn-integrity 56 | 57 | # dotenv environment variables file 58 | .env 59 | 60 | yarn.lock 61 | 62 | # next.js build output 63 | .next 64 | 65 | # webstorm 66 | **/.idea/* 67 | !.idea/runConfigurations 68 | -------------------------------------------------------------------------------- /chakra-ui/.meteor/.finished-upgraders: -------------------------------------------------------------------------------- 1 | # This file contains information which helps Meteor properly upgrade your 2 | # app when you run 'meteor update'. You should check it into version control 3 | # with your project. 4 | 5 | notices-for-0.9.0 6 | notices-for-0.9.1 7 | 0.9.4-platform-file 8 | notices-for-facebook-graph-api-2 9 | 1.2.0-standard-minifiers-package 10 | 1.2.0-meteor-platform-split 11 | 1.2.0-cordova-changes 12 | 1.2.0-breaking-changes 13 | 1.3.0-split-minifiers-package 14 | 1.4.0-remove-old-dev-bundle-link 15 | 1.4.1-add-shell-server-package 16 | 1.4.3-split-account-service-packages 17 | 1.5-add-dynamic-import-package 18 | 1.7-split-underscore-from-meteor-base 19 | 1.8.3-split-jquery-from-blaze 20 | -------------------------------------------------------------------------------- /chakra-ui/.meteor/.gitignore: -------------------------------------------------------------------------------- 1 | local 2 | -------------------------------------------------------------------------------- /chakra-ui/.meteor/.id: -------------------------------------------------------------------------------- 1 | # This file contains a token that is unique to your project. 2 | # Check it into your repository along with the rest of this directory. 3 | # It can be used for purposes such as: 4 | # - ensuring you don't accidentally deploy one app on top of another 5 | # - providing package authors with aggregated statistics 6 | 7 | j3mxcj0j3jfj.pzmhdxgvur2 8 | -------------------------------------------------------------------------------- /chakra-ui/.meteor/packages: -------------------------------------------------------------------------------- 1 | # Meteor packages used by this project, one per line. 2 | # Check this file (and the other files in this directory) into your repository. 3 | # 4 | # 'meteor add' and 'meteor remove' will edit this file for you, 5 | # but you can also edit it by hand. 6 | 7 | meteor-base@1.5.2-alpha300.19 # Packages every Meteor app needs to have 8 | mobile-experience@1.1.1-alpha300.19 # Packages for a great mobile UX 9 | mongo@2.0.0-alpha300.19 # The database Meteor supports right now 10 | reactive-var@1.0.13-alpha300.19 # Reactive variable for tracker 11 | 12 | standard-minifier-css@1.9.3-alpha300.19 # CSS minifier run for production mode 13 | standard-minifier-js@3.0.0-alpha300.19 # JS minifier run for production mode 14 | es5-shim@4.8.1-alpha300.19 # ECMAScript 5 compatibility for older browsers 15 | ecmascript@0.16.8-alpha300.19 # Enable ECMAScript2015+ syntax in app code 16 | typescript@4.9.5-alpha300.19 # Enable TypeScript syntax in .ts and .tsx modules 17 | shell-server@0.6.0-alpha300.19 # Server-side component of the `meteor shell` command 18 | hot-module-replacement@0.5.4-alpha300.19 # Update client in development without reloading the page 19 | 20 | autopublish@1.0.8-alpha300.19 # Publish all data to the clients (for prototyping) 21 | insecure@1.0.8-alpha300.19 # Allow all DB writes from clients (for prototyping) 22 | static-html@1.3.3-alpha300.19 # Define static page content in .html files 23 | react-meteor-data # React higher-order component for reactively tracking Meteor data 24 | -------------------------------------------------------------------------------- /chakra-ui/.meteor/platforms: -------------------------------------------------------------------------------- 1 | server 2 | browser 3 | -------------------------------------------------------------------------------- /chakra-ui/.meteor/release: -------------------------------------------------------------------------------- 1 | METEOR@3.0-alpha.19 2 | -------------------------------------------------------------------------------- /chakra-ui/.meteor/versions: -------------------------------------------------------------------------------- 1 | allow-deny@2.0.0-alpha300.19 2 | autopublish@1.0.8-alpha300.19 3 | autoupdate@2.0.0-alpha300.19 4 | babel-compiler@7.11.0-alpha300.19 5 | babel-runtime@1.5.2-alpha300.19 6 | base64@1.0.13-alpha300.19 7 | binary-heap@1.0.12-alpha300.19 8 | blaze-tools@2.0.0-alpha300.17 9 | boilerplate-generator@2.0.0-alpha300.19 10 | caching-compiler@2.0.0-alpha300.19 11 | caching-html-compiler@2.0.0-alpha300.17 12 | callback-hook@1.6.0-alpha300.19 13 | check@1.3.3-alpha300.19 14 | core-runtime@1.0.0-alpha300.19 15 | ddp@1.4.2-alpha300.19 16 | ddp-client@3.0.0-alpha300.19 17 | ddp-common@1.4.1-alpha300.19 18 | ddp-server@3.0.0-alpha300.19 19 | diff-sequence@1.1.3-alpha300.19 20 | dynamic-import@0.7.4-alpha300.19 21 | ecmascript@0.16.8-alpha300.19 22 | ecmascript-runtime@0.8.2-alpha300.19 23 | ecmascript-runtime-client@0.12.2-alpha300.19 24 | ecmascript-runtime-server@0.11.1-alpha300.19 25 | ejson@1.1.4-alpha300.19 26 | es5-shim@4.8.1-alpha300.19 27 | facts-base@1.0.2-alpha300.19 28 | fetch@0.1.4-alpha300.19 29 | geojson-utils@1.0.12-alpha300.19 30 | hot-code-push@1.0.5-alpha300.19 31 | hot-module-replacement@0.5.4-alpha300.19 32 | html-tools@2.0.0-alpha300.17 33 | htmljs@2.0.0-alpha300.17 34 | id-map@1.2.0-alpha300.19 35 | insecure@1.0.8-alpha300.19 36 | inter-process-messaging@0.1.2-alpha300.19 37 | launch-screen@1.3.1-alpha300.19 38 | logging@1.3.3-alpha300.19 39 | meteor@2.0.0-alpha300.19 40 | meteor-base@1.5.2-alpha300.19 41 | minifier-css@2.0.0-alpha300.19 42 | minifier-js@3.0.0-alpha300.19 43 | minimongo@2.0.0-alpha300.19 44 | mobile-experience@1.1.1-alpha300.19 45 | mobile-status-bar@1.1.1-alpha300.19 46 | modern-browsers@0.1.10-alpha300.19 47 | modules@0.19.1-alpha300.19 48 | modules-runtime@0.13.2-alpha300.19 49 | modules-runtime-hot@0.14.3-alpha300.19 50 | mongo@2.0.0-alpha300.19 51 | mongo-decimal@0.1.4-alpha300.19 52 | mongo-dev-server@1.1.1-alpha300.19 53 | mongo-id@1.0.9-alpha300.19 54 | npm-mongo@4.16.1-alpha300.19 55 | ordered-dict@1.2.0-alpha300.19 56 | promise@1.0.0-alpha300.19 57 | random@1.2.2-alpha300.19 58 | react-fast-refresh@0.2.8-alpha300.19 59 | react-meteor-data@2.7.2 60 | reactive-var@1.0.13-alpha300.19 61 | reload@1.3.2-alpha300.19 62 | retry@1.1.1-alpha300.19 63 | routepolicy@1.1.2-alpha300.19 64 | shell-server@0.6.0-alpha300.19 65 | socket-stream-client@0.5.2-alpha300.19 66 | spacebars-compiler@2.0.0-alpha300.17 67 | standard-minifier-css@1.9.3-alpha300.19 68 | standard-minifier-js@3.0.0-alpha300.19 69 | static-html@1.3.3-alpha300.19 70 | templating-tools@2.0.0-alpha300.17 71 | tracker@1.3.3-alpha300.19 72 | typescript@4.9.5-alpha300.19 73 | underscore@1.0.14-alpha300.19 74 | webapp@2.0.0-alpha300.19 75 | webapp-hashing@1.1.2-alpha300.19 76 | -------------------------------------------------------------------------------- /chakra-ui/README.md: -------------------------------------------------------------------------------- 1 | # Meteor + Chakra UI + Dark mode example 2 | 3 | Demo deployed on [Galaxy](https://meteor.com/cloud): 4 | 5 | https://chakraui.meteorapp.com/ 6 | 7 | ## Chakra UI 8 | 9 | The setup is already done in this project, but if you want to do it in another project you can follow the steps below. 10 | 11 | They are pretty much the same as the recommended on the [installation page](https://chakra-ui.com/docs/getting-started) of Chakra UI. 12 | 13 | ### 1 - Install npm dependencies 14 | ```bash 15 | npm i @chakra-ui/react @emotion/react @emotion/styled framer-motion 16 | ``` 17 | 18 | ### 2 - Install Chakra UI icons 19 | 20 | ```bash 21 | npm i @chakra-ui/icons 22 | ``` 23 | 24 | See [package.json](package.json) as example. 25 | 26 | ### 3 - Setup Chakra UI Provider + Color Mode 27 | 28 | ```js 29 | import React from 'react'; 30 | import { ChakraProvider, ColorModeScript, extendTheme } from '@chakra-ui/react'; 31 | import { HeroCallToAction } from './HeroCallToAction'; 32 | import { Navbar } from './Navbar'; 33 | 34 | const theme = extendTheme({ config: { 35 | initialColorMode: 'dark', 36 | useSystemColorMode: false, 37 | } }); 38 | 39 | export const App = () => ( 40 | <> 41 | 42 | 43 | 44 | 45 | 46 | 47 | ); 48 | 49 | ``` 50 | 51 | See [main.js](client/main.js) and [App.js](imports/ui/App.js) as example. 52 | 53 | ## Running the example 54 | 55 | ### Install dependencies 56 | 57 | ```bash 58 | meteor npm install 59 | ``` 60 | 61 | ### Running 62 | 63 | ```bash 64 | meteor npm run start 65 | ``` 66 | -------------------------------------------------------------------------------- /chakra-ui/client/main.html: -------------------------------------------------------------------------------- 1 | 2 | Meteor + Chakra UI Example 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 |
13 | 14 | -------------------------------------------------------------------------------- /chakra-ui/client/main.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { Meteor } from 'meteor/meteor'; 3 | import { render } from 'react-dom'; 4 | import { App } from '../imports/ui/App'; 5 | 6 | Meteor.startup(() => { 7 | render(, document.getElementById('react-target')); 8 | }); 9 | -------------------------------------------------------------------------------- /chakra-ui/imports/ui/App.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { ChakraProvider, ColorModeScript, extendTheme } from '@chakra-ui/react'; 3 | import { HeroCallToAction } from './HeroCallToAction'; 4 | import { Navbar } from './Navbar'; 5 | 6 | const theme = extendTheme({ config: { 7 | initialColorMode: 'dark', 8 | useSystemColorMode: false, 9 | } }); 10 | 11 | export const App = () => ( 12 | <> 13 | 14 | 15 | 16 | 17 | 18 | 19 | ); 20 | -------------------------------------------------------------------------------- /chakra-ui/imports/ui/HeroCallToAction.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { 3 | Box, 4 | Button, 5 | Container, 6 | createIcon, 7 | Heading, 8 | Icon, 9 | Stack, 10 | Text, 11 | useColorModeValue, 12 | } from '@chakra-ui/react'; 13 | import { SearchIcon, StarIcon } from '@chakra-ui/icons'; 14 | 15 | const Arrow = createIcon({ 16 | displayName: 'Arrow', 17 | viewBox: '0 0 72 24', 18 | path: ( 19 | 25 | ), 26 | }); 27 | 28 | export function HeroCallToAction() { 29 | return ( 30 | <> 31 | 32 | 37 | 41 | 42 | Meteor 3.0 {' '} 43 | + {' '} 44 | 45 | Node 20 {' '} 46 | 47 | + Chakra UI 48 | 49 | 50 | Meteor is a framework for building Web, Mobile, and Desktop applications in JS. 51 | Chakra UI is a simple, modular and accessible component library to build your React applications. 52 | 53 | 59 | 73 | 76 | 77 | 85 | 92 | Create your app 93 | 94 | 95 | 96 | 97 | 98 | 99 | ); 100 | } 101 | -------------------------------------------------------------------------------- /chakra-ui/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "chakra-ui-meteor-example", 3 | "private": true, 4 | "scripts": { 5 | "start": "meteor run", 6 | "eslint": "eslint . --fix" 7 | }, 8 | "dependencies": { 9 | "@babel/runtime": "^7.23.5", 10 | "@chakra-ui/icons": "^2.1.1", 11 | "@chakra-ui/react": "^2.8.2", 12 | "@emotion/react": "^11.11.1", 13 | "@emotion/styled": "^11.11.0", 14 | "framer-motion": "^10.16.12", 15 | "meteor-node-stubs": "^1.2.7", 16 | "react": "^18.2.0", 17 | "react-dom": "^18.2.0" 18 | }, 19 | "devDependencies": { 20 | "@quave/eslint-config-quave": "^1.0.7", 21 | "@types/meteor": "^2.9.7", 22 | "@types/react": "^18.2.41", 23 | "@types/react-dom": "^18.2.17" 24 | }, 25 | "meteor": { 26 | "mainModule": { 27 | "client": "client/main.js", 28 | "server": "server/main.js" 29 | } 30 | }, 31 | "eslintConfig": { 32 | "extends": [ 33 | "@quave/quave" 34 | ] 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /chakra-ui/server/main.js: -------------------------------------------------------------------------------- 1 | import { Meteor } from 'meteor/meteor'; 2 | 3 | Meteor.startup(() => { 4 | // eslint-disable-next-line no-console 5 | console.info('server ready'); 6 | }); 7 | -------------------------------------------------------------------------------- /complex-todos-svelte/.deploy/mup.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | servers: { 3 | one: { 4 | host: '1.2.3.4', 5 | username: 'root', 6 | password: 'password', 7 | opts: { 8 | port: 22 9 | } 10 | } 11 | }, 12 | 13 | app: { 14 | name: 'complex-todo-svelte', 15 | path: '../', 16 | docker: { 17 | image: 'abernix/meteord:node-12-base', 18 | }, 19 | servers: { 20 | one: {}, 21 | }, 22 | buildOptions: { 23 | serverOnly: true, 24 | }, 25 | env: { 26 | ROOT_URL: 'http://app.com', 27 | }, 28 | deployCheckPort: 80, 29 | enableUploadProgressBar: true 30 | }, 31 | }; 32 | -------------------------------------------------------------------------------- /complex-todos-svelte/.deploy/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "public": { 3 | "log": [ 4 | "ERROR", 5 | "FATAL", 6 | "WARN", 7 | "INFO", 8 | "TRACE", 9 | ] 10 | }, 11 | "monti": { 12 | "appId": "bzuQ34N4GPrwEu6Bo", 13 | "appSecret": "a7343029-4163-4c69-9342-d09b4d515e0c" 14 | } 15 | } -------------------------------------------------------------------------------- /complex-todos-svelte/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | -------------------------------------------------------------------------------- /complex-todos-svelte/.meteor/.finished-upgraders: -------------------------------------------------------------------------------- 1 | # This file contains information which helps Meteor properly upgrade your 2 | # app when you run 'meteor update'. You should check it into version control 3 | # with your project. 4 | 5 | notices-for-0.9.0 6 | notices-for-0.9.1 7 | 0.9.4-platform-file 8 | notices-for-facebook-graph-api-2 9 | 1.2.0-standard-minifiers-package 10 | 1.2.0-meteor-platform-split 11 | 1.2.0-cordova-changes 12 | 1.2.0-breaking-changes 13 | 1.3.0-split-minifiers-package 14 | 1.4.0-remove-old-dev-bundle-link 15 | 1.4.1-add-shell-server-package 16 | 1.4.3-split-account-service-packages 17 | 1.5-add-dynamic-import-package 18 | 1.7-split-underscore-from-meteor-base 19 | 1.8.3-split-jquery-from-blaze 20 | -------------------------------------------------------------------------------- /complex-todos-svelte/.meteor/.gitignore: -------------------------------------------------------------------------------- 1 | local 2 | -------------------------------------------------------------------------------- /complex-todos-svelte/.meteor/.id: -------------------------------------------------------------------------------- 1 | # This file contains a token that is unique to your project. 2 | # Check it into your repository along with the rest of this directory. 3 | # It can be used for purposes such as: 4 | # - ensuring you don't accidentally deploy one app on top of another 5 | # - providing package authors with aggregated statistics 6 | 7 | ou78pym2e7kf.kuc1f56r19il 8 | -------------------------------------------------------------------------------- /complex-todos-svelte/.meteor/packages: -------------------------------------------------------------------------------- 1 | # Meteor packages used by this project, one per line. 2 | # Check this file (and the other files in this directory) into your repository. 3 | # 4 | # 'meteor add' and 'meteor remove' will edit this file for you, 5 | # but you can also edit it by hand. 6 | 7 | meteor-base@1.5.1 # Packages every Meteor app needs to have 8 | mobile-experience@1.1.0 # Packages for a great mobile UX 9 | mongo@1.12.0 # The database Meteor supports right now 10 | jquery # Wrapper package for npm-installed jquery 11 | reactive-var@1.0.11 # Reactive variable for tracker 12 | tracker@1.2.0 # Meteor's client-side reactive programming library 13 | 14 | standard-minifier-css@1.7.3 # CSS minifier run for production mode 15 | standard-minifier-js@2.6.1 # JS minifier run for production mode 16 | es5-shim@4.8.0 # ECMAScript 5 compatibility for older browsers 17 | ecmascript@0.15.3 # Enable ECMAScript2015+ syntax in app code 18 | typescript@4.3.5 # Enable TypeScript syntax in .ts and .tsx modules 19 | shell-server@0.5.0 # Server-side component of the `meteor shell` command 20 | 21 | svelte:compiler 22 | rdb:svelte-meteor-data 23 | static-html 24 | svelte:blaze-integration 25 | meteortesting:mocha 26 | 27 | # 28 | # Accounts and roles 29 | # 30 | accounts-ui@1.4.0 31 | accounts-password@2.0.0 32 | 33 | # 34 | # Data layer 35 | # 36 | aldeed:collection2 37 | dburles:mongo-collection-instances 38 | 39 | # 40 | # Validated methods 41 | # 42 | mdg:validated-method 43 | ddp-rate-limiter@1.1.0 44 | 45 | # 46 | # Logging 47 | # 48 | ostrio:logger 49 | ostrio:loggerconsole 50 | 51 | # 52 | # Scheduled jobs 53 | # 54 | msavin:sjobs 55 | 56 | # 57 | # APM 58 | # 59 | montiapm:agent 60 | -------------------------------------------------------------------------------- /complex-todos-svelte/.meteor/platforms: -------------------------------------------------------------------------------- 1 | server 2 | browser 3 | -------------------------------------------------------------------------------- /complex-todos-svelte/.meteor/release: -------------------------------------------------------------------------------- 1 | METEOR@2.3.5 2 | -------------------------------------------------------------------------------- /complex-todos-svelte/.meteor/versions: -------------------------------------------------------------------------------- 1 | accounts-base@2.0.1 2 | accounts-password@2.0.0 3 | accounts-ui@1.4.0 4 | accounts-ui-unstyled@1.5.0 5 | aldeed:collection2@3.4.1 6 | allow-deny@1.1.0 7 | autoupdate@1.7.0 8 | babel-compiler@7.7.0 9 | babel-runtime@1.5.0 10 | base64@1.0.12 11 | binary-heap@1.0.11 12 | blaze@2.5.0 13 | blaze-tools@1.1.2 14 | boilerplate-generator@1.7.1 15 | caching-compiler@1.2.2 16 | caching-html-compiler@1.2.1 17 | callback-hook@1.3.1 18 | check@1.3.1 19 | dburles:mongo-collection-instances@0.3.1 20 | ddp@1.4.0 21 | ddp-client@2.5.0 22 | ddp-common@1.4.0 23 | ddp-rate-limiter@1.1.0 24 | ddp-server@2.4.1 25 | diff-sequence@1.1.1 26 | dynamic-import@0.7.1 27 | ecmascript@0.15.3 28 | ecmascript-runtime@0.7.0 29 | ecmascript-runtime-client@0.11.1 30 | ecmascript-runtime-server@0.10.1 31 | ejson@1.1.1 32 | email@2.1.1 33 | es5-shim@4.8.0 34 | fetch@0.1.1 35 | geojson-utils@1.0.10 36 | hot-code-push@1.0.4 37 | html-tools@1.1.2 38 | htmljs@1.1.1 39 | http@1.4.4 40 | id-map@1.1.1 41 | inter-process-messaging@0.1.1 42 | jquery@3.0.0 43 | launch-screen@1.3.0 44 | less@3.0.2 45 | livedata@1.0.18 46 | localstorage@1.2.0 47 | logging@1.2.0 48 | mdg:validated-method@1.2.0 49 | meteor@1.9.3 50 | meteor-base@1.5.1 51 | meteortesting:browser-tests@1.3.4 52 | meteortesting:mocha@2.0.2 53 | meteortesting:mocha-core@8.1.2 54 | minifier-css@1.5.4 55 | minifier-js@2.6.1 56 | minimongo@1.7.0 57 | mobile-experience@1.1.0 58 | mobile-status-bar@1.1.0 59 | modern-browsers@0.1.5 60 | modules@0.16.0 61 | modules-runtime@0.12.0 62 | mongo@1.12.0 63 | mongo-decimal@0.1.2 64 | mongo-dev-server@1.1.0 65 | mongo-id@1.0.8 66 | mongo-livedata@1.0.12 67 | montiapm:agent@2.44.1 68 | montiapm:meteorx@2.2.0 69 | msavin:sjobs@4.1.0 70 | npm-mongo@3.9.1 71 | observe-sequence@1.0.19 72 | ordered-dict@1.1.0 73 | ostrio:logger@2.0.9 74 | ostrio:loggerconsole@2.0.5 75 | promise@0.12.0 76 | raix:eventemitter@1.0.0 77 | random@1.2.0 78 | rate-limit@1.0.9 79 | rdb:svelte-meteor-data@0.3.0 80 | react-fast-refresh@0.1.1 81 | reactive-dict@1.3.0 82 | reactive-var@1.0.11 83 | reload@1.3.1 84 | retry@1.1.0 85 | routepolicy@1.1.1 86 | service-configuration@1.1.0 87 | session@1.2.0 88 | sha@1.0.9 89 | shell-server@0.5.0 90 | socket-stream-client@0.4.0 91 | spacebars@1.2.0 92 | spacebars-compiler@1.3.0 93 | standard-minifier-css@1.7.3 94 | standard-minifier-js@2.6.1 95 | static-html@1.3.2 96 | svelte:blaze-integration@0.4.0 97 | svelte:compiler@3.31.2 98 | templating@1.4.1 99 | templating-compiler@1.4.1 100 | templating-runtime@1.5.0 101 | templating-tools@1.2.1 102 | tmeasday:check-npm-versions@1.0.2 103 | tracker@1.2.0 104 | typescript@4.3.5 105 | underscore@1.0.10 106 | url@1.3.2 107 | webapp@1.11.1 108 | webapp-hashing@1.1.0 109 | zodern:meteor-package-versions@0.2.1 110 | -------------------------------------------------------------------------------- /complex-todos-svelte/LICENSE: -------------------------------------------------------------------------------- 1 | ======================================== 2 | Meteor is licensed under the MIT License 3 | ======================================== 4 | 5 | Copyright (C) 2011--2016 Meteor Development Group 6 | 7 | Permission is hereby granted, free of charge, to any person obtaining a copy of 8 | this software and associated documentation files (the "Software"), to deal in 9 | the Software without restriction, including without limitation the rights to 10 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 11 | the Software, and to permit persons to whom the Software is furnished to do so, 12 | subject to the following conditions: 13 | 14 | The above copyright notice and this permission notice shall be included in all 15 | copies or substantial portions of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 19 | FOR A PARTICULAR PURPOSE AND NONINFINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 20 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 21 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 22 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23 | -------------------------------------------------------------------------------- /complex-todos-svelte/client/init.js: -------------------------------------------------------------------------------- 1 | import {log} from '../imports/shared/logger/logger.js'; 2 | import {Accounts} from 'meteor/accounts-base'; 3 | import App from './ui/App.svelte'; 4 | 5 | /** 6 | * Initialize client at startup 7 | * @locus server 8 | */ 9 | class ClientInit 10 | { 11 | /** 12 | * @constructor 13 | */ 14 | constructor() 15 | { 16 | log.info('Client is starting'); 17 | 18 | this._accountUIConfig(); 19 | 20 | this._renderApp(); 21 | } 22 | 23 | _accountUIConfig() 24 | { 25 | log.debug('Configuring accounts user interface'); 26 | 27 | Accounts.ui.config({ 28 | passwordSignupFields: 'USERNAME_ONLY' 29 | }); 30 | } 31 | 32 | _renderApp() 33 | { 34 | log.debug('Rendering app'); 35 | 36 | new App({ 37 | target: document.getElementById('app') 38 | }); 39 | } 40 | } 41 | 42 | /** 43 | * No need to export it 44 | * It will only run once on client initialize 45 | */ 46 | Meteor.startup(function() 47 | { 48 | new ClientInit; 49 | }); -------------------------------------------------------------------------------- /complex-todos-svelte/client/main.css: -------------------------------------------------------------------------------- 1 | .nav-login { 2 | padding: 8px; 3 | } -------------------------------------------------------------------------------- /complex-todos-svelte/client/main.html: -------------------------------------------------------------------------------- 1 | 2 | Complex Todo List 3 | 4 | 5 | 6 | 7 |
8 | 9 | 10 | -------------------------------------------------------------------------------- /complex-todos-svelte/client/main.js: -------------------------------------------------------------------------------- 1 | import './init.js'; -------------------------------------------------------------------------------- /complex-todos-svelte/client/ui/About.svelte: -------------------------------------------------------------------------------- 1 |
2 |

About

3 |

This is an example app to show how anyone can combine Meteor.js with svelte. The example is like a simple to-do application and it covers lots of things related with the real world 4 |

5 |
-------------------------------------------------------------------------------- /complex-todos-svelte/client/ui/App.svelte: -------------------------------------------------------------------------------- 1 | 15 | 16 | 17 |
18 | 39 | 40 | 41 | 42 |
43 |
-------------------------------------------------------------------------------- /complex-todos-svelte/client/ui/Task.svelte: -------------------------------------------------------------------------------- 1 | 32 | 33 | 36 | 37 |
38 | 48 |
49 | 50 | 51 | {#if showButton} 52 | 56 | 60 | {/if} 61 | 62 | 63 | -------------------------------------------------------------------------------- /complex-todos-svelte/client/ui/TaskAddNewForm.svelte: -------------------------------------------------------------------------------- 1 | 16 |
17 |
18 | 19 |
20 | 24 | 25 | 29 |
30 |
31 |
-------------------------------------------------------------------------------- /complex-todos-svelte/client/ui/Tasks.svelte: -------------------------------------------------------------------------------- 1 | 30 | 31 |
32 |
33 |
34 | {#if $currentUser} 35 | 36 | {/if} 37 |
38 |
39 | 40 |

Pending Items ({ $incompleteCount })

41 | 42 |
43 |
44 | 45 | 46 | 47 | 57 | 60 | 61 | 62 | 63 | {#each tasks as task} 64 | 68 | {/each} 69 | 70 |
48 | 56 | 58 | Actions 59 |
71 |
72 |
73 |
-------------------------------------------------------------------------------- /complex-todos-svelte/cypress.json: -------------------------------------------------------------------------------- 1 | { 2 | "baseUrl": "http://localhost:3000/", 3 | "watchForFileChanges": true, 4 | "defaultCommandTimeout": 15000, 5 | "requestTimeout": 15000, 6 | "pageLoadTimeout": 120000, 7 | "responseTimeout": 60000, 8 | "retries": { 9 | "runMode": 2, 10 | "openMode": 0 11 | }, 12 | "projectId": "ctdsm1" 13 | } 14 | -------------------------------------------------------------------------------- /complex-todos-svelte/cypress/fixtures/example.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Using fixtures to represent data", 3 | "email": "hello@cypress.io", 4 | "body": "Fixtures are a great way to mock data for responses to routes" 5 | } -------------------------------------------------------------------------------- /complex-todos-svelte/cypress/integration/constants/test.js: -------------------------------------------------------------------------------- 1 | export const TEST = { 2 | USER: { 3 | DEMO: { 4 | USERNAME: 'gunce', 5 | PASSWORD: 'password' 6 | }, 7 | TEST: { 8 | USERNAME: 'username', 9 | PASSWORD: 'password' 10 | } 11 | }, 12 | TASK: { 13 | PUBLIC: 'Public test task', 14 | PRIVATE: 'Private test task' 15 | } 16 | }; -------------------------------------------------------------------------------- /complex-todos-svelte/cypress/integration/tests/1.prepareTestEnvironment.test.js: -------------------------------------------------------------------------------- 1 | import {visit, wait} from '../utilities/commons.js'; 2 | 3 | describe('Prepare Test Environment', function() 4 | { 5 | it('Clear database', function() 6 | { 7 | visit('/'); 8 | 9 | cy.window().then((win) => 10 | { 11 | win.Meteor.call('clear.database'); 12 | }); 13 | 14 | wait(1000); 15 | 16 | cy.url().should('contain', 'localhost'); 17 | }); 18 | 19 | it('Insert dummy data', function() 20 | { 21 | visit('/'); 22 | 23 | cy.window().then((win) => 24 | { 25 | win.Meteor.call('insert.dummy.data'); 26 | }); 27 | 28 | wait(1000); 29 | 30 | cy.url().should('contain', 'localhost'); 31 | }); 32 | }); 33 | -------------------------------------------------------------------------------- /complex-todos-svelte/cypress/integration/tests/authentication.test.js: -------------------------------------------------------------------------------- 1 | import {visit} from '../utilities/commons.js'; 2 | import {TEST} from '../constants/test.js'; 3 | import {doLogin} from '../utilities/doLogin.js'; 4 | import {doLogout} from '../utilities/doLogout.js'; 5 | 6 | describe('Authentication', function() 7 | { 8 | it('Sign up - Fail - Passwords must match', function() 9 | { 10 | visit('/'); 11 | 12 | cy.get('#login-sign-in-link').click(); 13 | 14 | cy.get('#signup-link').click(); 15 | 16 | cy.get('#login-username').clear().type(TEST.USER.TEST.USERNAME); 17 | 18 | cy.get('#login-password').clear().type('password1'); 19 | 20 | cy.get('#login-password-again').clear().type('password2'); 21 | 22 | cy.get('#login-buttons-password').click(); 23 | 24 | cy.get('.message.error-message').should('contain', 'Passwords don\'t match'); 25 | }); 26 | 27 | it('Sign up - Fail - Password must long', function() 28 | { 29 | visit('/'); 30 | 31 | cy.get('#login-sign-in-link').click(); 32 | 33 | cy.get('#signup-link').click(); 34 | 35 | cy.get('#login-username').clear().type(TEST.USER.TEST.USERNAME); 36 | 37 | cy.get('#login-password').clear().type('pass'); 38 | 39 | cy.get('#login-password-again').clear().type('pass'); 40 | 41 | cy.get('#login-buttons-password').click(); 42 | 43 | cy.get('.message.error-message').should('contain', 'Password must be at least 6 characters long'); 44 | }); 45 | 46 | it('Sign up - Success', function() 47 | { 48 | visit('/'); 49 | 50 | cy.get('#login-sign-in-link').click(); 51 | 52 | cy.get('#signup-link').click(); 53 | 54 | cy.get('#login-username').clear().type(TEST.USER.TEST.USERNAME); 55 | 56 | cy.get('#login-password').clear().type(TEST.USER.TEST.PASSWORD); 57 | 58 | cy.get('#login-password-again').clear().type(TEST.USER.TEST.PASSWORD); 59 | 60 | cy.get('#login-buttons-password').click(); 61 | 62 | cy.get('#login-name-link').should('contain', TEST.USER.TEST.USERNAME); 63 | }); 64 | 65 | it('Sign in - Fail - Incorrect password', function() 66 | { 67 | visit('/'); 68 | 69 | cy.get('#login-sign-in-link').click(); 70 | 71 | cy.get('#login-username').clear().type(TEST.USER.TEST.USERNAME); 72 | 73 | cy.get('#login-password').clear().type('pass'); 74 | 75 | cy.get('#login-buttons-password').click(); 76 | 77 | cy.get('.message.error-message').should('contain', 'Incorrect password'); 78 | }); 79 | 80 | it('Sign in - Fail - User not found', function() 81 | { 82 | visit('/'); 83 | 84 | cy.get('#login-sign-in-link').click(); 85 | 86 | cy.get('#login-username').clear().type('user'); 87 | 88 | cy.get('#login-password').clear().type('pass'); 89 | 90 | cy.get('#login-buttons-password').click(); 91 | 92 | cy.get('.message.error-message').should('contain', 'User not found'); 93 | }); 94 | 95 | it('Sign in - Success', function() 96 | { 97 | visit('/'); 98 | 99 | doLogin(); 100 | }); 101 | 102 | it('Sign out', function() 103 | { 104 | visit('/'); 105 | 106 | doLogout() 107 | 108 | cy.get('#login-sign-in-link').should('contain', 'Sign in'); 109 | }); 110 | }); -------------------------------------------------------------------------------- /complex-todos-svelte/cypress/integration/tests/navigation.test.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/meteor/examples/c44bd2426dac0d3b6edf2535e82a7c39236f6e6e/complex-todos-svelte/cypress/integration/tests/navigation.test.js -------------------------------------------------------------------------------- /complex-todos-svelte/cypress/integration/tests/tasks.test.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/meteor/examples/c44bd2426dac0d3b6edf2535e82a7c39236f6e6e/complex-todos-svelte/cypress/integration/tests/tasks.test.js -------------------------------------------------------------------------------- /complex-todos-svelte/cypress/integration/utilities/commons.js: -------------------------------------------------------------------------------- 1 | import {waitForMeteorSubscriptions} from '../../support/commands.js'; 2 | 3 | /** 4 | * Wait for provided ms 5 | * @param timeMs {number} 6 | */ 7 | export function wait(timeMs = 500) 8 | { 9 | cy.wait(timeMs); 10 | } 11 | 12 | /** 13 | * Subscription aware visit function 14 | * @param url {string} 15 | */ 16 | export function visit(url) 17 | { 18 | cy.visit(url); 19 | 20 | waitForMeteorSubscriptions(); 21 | } -------------------------------------------------------------------------------- /complex-todos-svelte/cypress/integration/utilities/doLogin.js: -------------------------------------------------------------------------------- 1 | import {TEST} from '../constants/constantsForTests.js'; 2 | import {waitForMeteorSubscriptions} from '../../support/commands.js'; 3 | 4 | /** 5 | * Login with provided user name and password (subscription aware) 6 | * @param username {string} 7 | * @param password {string} 8 | */ 9 | export function doLogin(username = TEST.USER.DEMO.USERNAME, password = TEST.USER.DEMO.PASSWORD) 10 | { 11 | cy.visit('/'); 12 | 13 | cy.get('#login-sign-in-link').click(); 14 | 15 | cy.get('#login-username').clear().type(TEST.USER.TEST.USERNAME); 16 | 17 | cy.get('#login-password').clear().type(TEST.USER.TEST.PASSWORD); 18 | 19 | cy.get('#login-buttons-password').click(); 20 | 21 | cy.get('#login-name-link').should('contain', TEST.USER.TEST.USERNAME); 22 | 23 | cy.window().its('Meteor').invoke('userId').should((userId) => 24 | { 25 | expect(userId).not.to.be.null; 26 | }); 27 | 28 | waitForMeteorSubscriptions(); 29 | } -------------------------------------------------------------------------------- /complex-todos-svelte/cypress/integration/utilities/doLogout.js: -------------------------------------------------------------------------------- 1 | export function doLogout() 2 | { 3 | cy.window().then((win) => 4 | { 5 | win.Meteor.logout(); 6 | }); 7 | } -------------------------------------------------------------------------------- /complex-todos-svelte/cypress/plugins/index.js: -------------------------------------------------------------------------------- 1 | /// 2 | // *********************************************************** 3 | // This example plugins/index.js can be used to load plugins 4 | // 5 | // You can change the location of this file or turn off loading 6 | // the plugins file with the 'pluginsFile' configuration option. 7 | // 8 | // You can read more here: 9 | // https://on.cypress.io/plugins-guide 10 | // *********************************************************** 11 | 12 | // This function is called when a project is opened or re-opened (e.g. due to 13 | // the project's config changing) 14 | 15 | /** 16 | * @type {Cypress.PluginConfig} 17 | */ 18 | module.exports = (on, config) => 19 | { 20 | // `on` is used to hook into various events Cypress emits 21 | // `config` is the resolved Cypress config 22 | }; 23 | -------------------------------------------------------------------------------- /complex-todos-svelte/cypress/readme.md: -------------------------------------------------------------------------------- 1 | # E2E Tests 2 | 3 | This folder contains e2e tests 4 | 5 | ### Test Strategy 6 | 7 | Some test may require dummy data, the responsibility of dummy data should not be on cypress. The test data is different 8 | from dummy data. Test data will be stored and modified by cypress. 9 | 10 | ### Test Plan 11 | 12 | 1. Authentication 13 | - [x] Sign up - Fail - Passwords must match 14 | - [x] Sign up - Fail - Password must long 15 | - [x] Sign up - Success 16 | - [x] Sign in - Fail - Incorrect password 17 | - [x] Sign in - Fail - User not found 18 | - [x] Sign in - Success 19 | - [ ] Sign out 20 | 21 | 1. Navigation 22 | - [ ] Go to tasks page 23 | - [ ] Go to about page 24 | 25 | 1. Task 26 | - [ ] Guest can not see the new task form 27 | - [ ] Insert a new task 28 | - [ ] Update a task as checked 29 | - [ ] Update a task as unchecked 30 | - [ ] Update a task as private 31 | - [ ] Update a task as public 32 | - [ ] Remove a task 33 | - [ ] Check if a task is expired 34 | 35 | ### How to start tests 36 | 37 | Type ```npm run cypress``` into terminal 38 | 39 | ### Location of tests 40 | 41 | If cypress cache exists after file change, delete 42 | ~/Library/Application Support/Cypress/cy -------------------------------------------------------------------------------- /complex-todos-svelte/cypress/support/commands.js: -------------------------------------------------------------------------------- 1 | // *********************************************** 2 | // This example commands.js shows you how to 3 | // create various custom commands and overwrite 4 | // existing commands. 5 | // 6 | // For more comprehensive examples of custom 7 | // commands please read more here: 8 | // https://on.cypress.io/custom-commands 9 | // *********************************************** 10 | // 11 | // 12 | // -- This is a parent command -- 13 | // Cypress.Commands.add("login", (email, password) => { ... }) 14 | // 15 | // 16 | // -- This is a child command -- 17 | // Cypress.Commands.add("drag", { prevSubject: 'element'}, (subject, options) => { ... }) 18 | // 19 | // 20 | // -- This is a dual command -- 21 | // Cypress.Commands.add("dismiss", { prevSubject: 'optional'}, (subject, options) => { ... }) 22 | // 23 | // 24 | // -- This will overwrite an existing command -- 25 | // Cypress.Commands.overwrite("visit", (originalFn, url, options) => { ... }) 26 | 27 | Cypress.Commands.add('allSubscriptionsReady', (options = {}) => 28 | { 29 | const log = { 30 | name: 'allSubscriptionsReady' 31 | }; 32 | 33 | const getValue = () => 34 | { 35 | return cy.state('window').DDP._allSubscriptionsReady(); 36 | }; 37 | 38 | const resolveValue = () => 39 | { 40 | return Cypress.Promise.try(getValue).then((value) => 41 | { 42 | return cy.verifyUpcomingAssertions(value, options, { 43 | onRetry: resolveValue 44 | }); 45 | }); 46 | }; 47 | 48 | return resolveValue().then((value) => 49 | { 50 | Cypress.log(log); 51 | return value; 52 | }); 53 | }); 54 | 55 | export function waitForMeteorSubscriptions() 56 | { 57 | cy.window().its('DDP').invoke('_allSubscriptionsReady').should((ready) => 58 | { 59 | expect(ready).to.be.true; 60 | }); 61 | } 62 | -------------------------------------------------------------------------------- /complex-todos-svelte/cypress/support/index.js: -------------------------------------------------------------------------------- 1 | // *********************************************************** 2 | // This example support/index.js is processed and 3 | // loaded automatically before your test files. 4 | // 5 | // This is a great place to put global configuration and 6 | // behavior that modifies Cypress. 7 | // 8 | // You can change the location of this file or turn off 9 | // automatically serving support files with the 10 | // 'supportFile' configuration option. 11 | // 12 | // You can read more here: 13 | // https://on.cypress.io/configuration 14 | // *********************************************************** 15 | 16 | // Import commands.js using ES2015 syntax: 17 | import './commands'; 18 | 19 | // Alternatively you can use CommonJS syntax: 20 | // require('./commands') 21 | -------------------------------------------------------------------------------- /complex-todos-svelte/imports/modules/eventEmitter/eventEmitterService.js: -------------------------------------------------------------------------------- 1 | const EventEmitter = require('events'); 2 | 3 | export const eventEmitter = new EventEmitter(); -------------------------------------------------------------------------------- /complex-todos-svelte/imports/modules/eventEmitter/server/index.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/meteor/examples/c44bd2426dac0d3b6edf2535e82a7c39236f6e6e/complex-todos-svelte/imports/modules/eventEmitter/server/index.js -------------------------------------------------------------------------------- /complex-todos-svelte/imports/modules/tasks/database/tasks.js: -------------------------------------------------------------------------------- 1 | import {Mongo} from 'meteor/mongo'; 2 | import SimpleSchema from 'simpl-schema'; 3 | 4 | const Tasks = new Mongo.Collection('tasks'); 5 | 6 | Tasks.attachSchema(new SimpleSchema({ 7 | text: { 8 | type: String 9 | }, 10 | createdAt: { 11 | type: Date 12 | }, 13 | owner: { 14 | type: String 15 | }, 16 | username: { 17 | type: String 18 | }, 19 | checked: { 20 | type: Boolean, 21 | optional: true 22 | }, 23 | expired: { 24 | type: Boolean, 25 | optional: true 26 | }, 27 | private: { 28 | type: Boolean, 29 | optional: true 30 | } 31 | })); 32 | 33 | export {Tasks}; -------------------------------------------------------------------------------- /complex-todos-svelte/imports/modules/tasks/enums/methodNames.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @type {{UPDATE_AS_CHECKED: string, UPDATE_AS_PRIVATE: string, REMOVE: string, INSERT: string}} 3 | */ 4 | export const TASKS_METHOD = { 5 | INSERT: 'tasks.insert', 6 | REMOVE: 'tasks.remove', 7 | UPDATE_AS_CHECKED: 'tasks.update.asChecked', 8 | UPDATE_AS_PRIVATE: 'tasks.update.asPrivate' 9 | }; -------------------------------------------------------------------------------- /complex-todos-svelte/imports/modules/tasks/enums/publications.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @type {{TASKS: string}} 3 | */ 4 | export const TASKS_PUBLICATION = { 5 | TASKS: 'tasks' 6 | }; -------------------------------------------------------------------------------- /complex-todos-svelte/imports/modules/tasks/enums/rateLimitter.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @typedef RATE_LIMITER 3 | * @type {{TIME_INTERVAL: number, REQUEST_COUNT: number}} 4 | */ 5 | export const RATE_LIMITER = { 6 | REQUEST_COUNT: 5, 7 | TIME_INTERVAL: 1000 8 | } -------------------------------------------------------------------------------- /complex-todos-svelte/imports/modules/tasks/server/index.js: -------------------------------------------------------------------------------- 1 | import './tasks.ensureIndexes.js'; 2 | import './tasks.events.js'; 3 | import './tasks.guards.js'; 4 | import './tasks.publications.js'; 5 | import './tasks.rateLimiter.js'; -------------------------------------------------------------------------------- /complex-todos-svelte/imports/modules/tasks/server/tasks.ensureIndexes.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/meteor/examples/c44bd2426dac0d3b6edf2535e82a7c39236f6e6e/complex-todos-svelte/imports/modules/tasks/server/tasks.ensureIndexes.js -------------------------------------------------------------------------------- /complex-todos-svelte/imports/modules/tasks/server/tasks.events.js: -------------------------------------------------------------------------------- 1 | import {eventEmitter} from '../../eventEmitter/eventEmitterService.js'; 2 | import {EVENT} from '../../../shared/enums/events.js'; 3 | import {log} from '../../../shared/logger/logger.js'; 4 | import {taskRepository} from '../taskRepository.js'; 5 | 6 | eventEmitter.on(EVENT.TASKS.EXPIRE, ({maxDate}) => 7 | { 8 | log.debug(`Event ${EVENT.TASKS.EXPIRE} triggered`); 9 | 10 | taskRepository.updateMany({createdAt: {$lte: maxDate}}, {$set: {expired: true}}); 11 | }); -------------------------------------------------------------------------------- /complex-todos-svelte/imports/modules/tasks/server/tasks.guards.js: -------------------------------------------------------------------------------- 1 | import {Tasks} from '../database/tasks.js'; 2 | 3 | Tasks.allow({ 4 | insert() 5 | { 6 | return false; 7 | }, 8 | update() 9 | { 10 | return false; 11 | }, 12 | remove() 13 | { 14 | return false; 15 | } 16 | }); -------------------------------------------------------------------------------- /complex-todos-svelte/imports/modules/tasks/server/tasks.publications.js: -------------------------------------------------------------------------------- 1 | import {Meteor} from 'meteor/meteor'; 2 | import {Tasks} from '../database/tasks.js'; 3 | import {TASKS_PUBLICATION} from '../enums/publications.js'; 4 | 5 | Meteor.publish(TASKS_PUBLICATION.TASKS, function tasksPublication() 6 | { 7 | return Tasks.find({ 8 | $or: [ 9 | {private: {$ne: true}}, 10 | {owner: this.userId} 11 | ] 12 | }); 13 | }); -------------------------------------------------------------------------------- /complex-todos-svelte/imports/modules/tasks/server/tasks.rateLimiter.js: -------------------------------------------------------------------------------- 1 | import {_} from 'meteor/underscore'; 2 | import {RATE_LIMITER} from '../enums/rateLimitter.js'; 3 | import {tasksInsert, tasksRemove, tasksUpdateAsChecked, tasksUpdateAsPrivate} from '../tasks.methods.js'; 4 | 5 | const LISTS_METHODS = _.pluck([ 6 | tasksInsert, 7 | tasksRemove, 8 | tasksUpdateAsChecked, 9 | tasksUpdateAsPrivate 10 | ], 'name'); 11 | 12 | DDPRateLimiter.addRule({ 13 | name(name) 14 | { 15 | return _.contains(LISTS_METHODS, name); 16 | }, 17 | // Rate limit per connection 18 | connectionId() 19 | { 20 | return true; 21 | } 22 | }, RATE_LIMITER.REQUEST_COUNT, RATE_LIMITER.TIME_INTERVAL); -------------------------------------------------------------------------------- /complex-todos-svelte/imports/modules/tasks/taskRepository.js: -------------------------------------------------------------------------------- 1 | import {BaseRepository} from '../../shared/repository/baseRepository.js'; 2 | import {Tasks} from './database/tasks.js'; 3 | 4 | class TaskRepository extends BaseRepository 5 | { 6 | /** 7 | * @constructor 8 | */ 9 | constructor() 10 | { 11 | super(Tasks); 12 | } 13 | } 14 | 15 | export const taskRepository = new TaskRepository(); -------------------------------------------------------------------------------- /complex-todos-svelte/imports/modules/tasks/taskService.js: -------------------------------------------------------------------------------- 1 | import {taskRepository} from './taskRepository.js'; 2 | import {Meteor} from 'meteor/meteor'; 3 | import {User} from '../../shared/functions/user.js'; 4 | 5 | class TaskService 6 | { 7 | /** 8 | * @param taskId {string} 9 | * @returns {*} 10 | */ 11 | getTask(taskId) 12 | { 13 | return taskRepository.findOne(taskId); 14 | } 15 | 16 | /** 17 | * @param text {string} 18 | * @returns {string} 19 | */ 20 | insert(text) 21 | { 22 | return taskRepository.insert({ 23 | text, 24 | createdAt: new Date(), 25 | owner: User._id, 26 | username: User.details.username 27 | }); 28 | } 29 | 30 | /** 31 | * @param taskId 32 | */ 33 | remove(taskId) 34 | { 35 | const task = this.getTask(taskId); 36 | 37 | if(task.private && task.owner !== User._id) 38 | { 39 | // If the task is private, make sure only the owner can delete it 40 | throw new Meteor.Error('not-authorized'); 41 | } 42 | 43 | taskRepository.remove(taskId); 44 | } 45 | 46 | /** 47 | * @param taskId {string} 48 | * @param setChecked 49 | */ 50 | updateAsChecked(taskId, setChecked) 51 | { 52 | const task = this.getTask(taskId); 53 | 54 | if(task.private && task.owner !== User._id) 55 | { 56 | // If the task is private, make sure only the owner can check it off 57 | throw new Meteor.Error('not-authorized'); 58 | } 59 | 60 | taskRepository.update(taskId, {$set: {checked: setChecked}}); 61 | } 62 | 63 | /** 64 | * @param taskId {string} 65 | * @param setPrivate {boolean} 66 | */ 67 | updateAsPrivate(taskId, setPrivate) 68 | { 69 | const task = this.getTask(taskId); 70 | 71 | // Make sure only the task owner can make a task private 72 | if(task.owner !== User._id) 73 | { 74 | throw new Meteor.Error('not-authorized'); 75 | } 76 | 77 | taskRepository.update(taskId, {$set: {private: setPrivate}}); 78 | } 79 | } 80 | 81 | export const taskService = new TaskService(); -------------------------------------------------------------------------------- /complex-todos-svelte/imports/modules/tasks/tasks.methods.js: -------------------------------------------------------------------------------- 1 | import {ValidatedMethod} from 'meteor/mdg:validated-method'; 2 | import SimpleSchema from 'simpl-schema'; 3 | import {taskService} from './taskService.js'; 4 | import {LoggedInMixin} from '../../shared/mixins/LoggedInMixin.js'; 5 | import {TASKS_METHOD} from './enums/methodNames.js'; 6 | 7 | /** 8 | * @type {ValidatedMethod} 9 | */ 10 | export const tasksInsert = new ValidatedMethod({ 11 | name: TASKS_METHOD.INSERT, 12 | mixins: [LoggedInMixin], 13 | validate: new SimpleSchema({ 14 | text: {type: String} 15 | }).validator(), 16 | /** 17 | * @param text {string} 18 | * @returns {string} 19 | */ 20 | run({text}) 21 | { 22 | return taskService.insert(text); 23 | } 24 | }); 25 | 26 | /** 27 | * @type {ValidatedMethod} 28 | */ 29 | export const tasksRemove = new ValidatedMethod({ 30 | name: TASKS_METHOD.REMOVE, 31 | mixins: [LoggedInMixin], 32 | validate: new SimpleSchema({ 33 | taskId: {type: String} 34 | }).validator(), 35 | /** 36 | * @param taskId {string} 37 | */ 38 | run({taskId}) 39 | { 40 | taskService.remove(taskId); 41 | } 42 | }); 43 | 44 | /** 45 | * @type {ValidatedMethod} 46 | */ 47 | export const tasksUpdateAsChecked = new ValidatedMethod({ 48 | name: TASKS_METHOD.UPDATE_AS_CHECKED, 49 | mixins: [LoggedInMixin], 50 | validate: new SimpleSchema({ 51 | taskId: {type: String}, 52 | setChecked: {type: Boolean} 53 | }).validator(), 54 | /** 55 | * @param taskId {string} 56 | * @param setChecked {boolean} 57 | */ 58 | run({taskId, setChecked}) 59 | { 60 | taskService.updateAsChecked(taskId, setChecked); 61 | } 62 | }); 63 | 64 | /** 65 | * @type {ValidatedMethod} 66 | */ 67 | export const tasksUpdateAsPrivate = new ValidatedMethod({ 68 | name: TASKS_METHOD.UPDATE_AS_PRIVATE, 69 | mixins: [LoggedInMixin], 70 | validate: new SimpleSchema({ 71 | taskId: {type: String}, 72 | setPrivate: {type: Boolean} 73 | }).validator(), 74 | /** 75 | * @param taskId {string} 76 | * @param setPrivate {boolean} 77 | */ 78 | run({taskId, setPrivate}) 79 | { 80 | taskService.updateAsPrivate(taskId, setPrivate); 81 | } 82 | }); -------------------------------------------------------------------------------- /complex-todos-svelte/imports/modules/tasks/tasks.methods.test.js: -------------------------------------------------------------------------------- 1 | import {assert} from 'chai'; 2 | import {taskRepository} from './taskRepository.js'; 3 | import {tasksInsert, tasksRemove, tasksUpdateAsChecked} from './tasks.methods.js'; 4 | import {UNIT_TEST} from '../../../tests/enums/users.js'; 5 | 6 | describe('Tasks methods', () => 7 | { 8 | const userId = UNIT_TEST.USER_ID; 9 | let taskId; 10 | 11 | beforeEach(function() 12 | { 13 | taskRepository.remove({}); 14 | }); 15 | 16 | it('tasksInsert', () => 17 | { 18 | // Set up method arguments and context 19 | const context = {userId}; 20 | 21 | const args = {text: 'new task'}; 22 | 23 | // Execute the method 24 | tasksInsert._execute(context, args); 25 | 26 | // Verify that the method does what we expected 27 | assert.equal(taskRepository.find().count(), 1); 28 | }); 29 | 30 | it('tasksRemove', () => 31 | { 32 | // Set up method arguments and context 33 | const context = {userId}; 34 | 35 | taskId = taskRepository.insert({ 36 | text: 'test task', 37 | createdAt: new Date(), 38 | owner: userId, 39 | username: 'john doe' 40 | }); 41 | 42 | const args = {taskId}; 43 | 44 | // Execute the method 45 | tasksRemove._execute(context, args); 46 | 47 | // Verify that the method does what we expected 48 | assert.equal(taskRepository.find().count(), 0); 49 | }); 50 | 51 | it('tasksUpdateAsChecked', () => 52 | { 53 | // Set up method arguments and context 54 | const context = {userId}; 55 | 56 | taskId = taskRepository.insert({ 57 | text: 'test task', 58 | createdAt: new Date(), 59 | owner: userId, 60 | username: 'john doe' 61 | }); 62 | 63 | const args = { 64 | taskId: taskId, 65 | setChecked: true 66 | }; 67 | 68 | // Execute the method 69 | tasksUpdateAsChecked._execute(context, args); 70 | 71 | let task = taskRepository.findOne(taskId); 72 | 73 | // Verify that the method does what we expected 74 | assert.equal(task.checked, true); 75 | }); 76 | }); -------------------------------------------------------------------------------- /complex-todos-svelte/imports/modules/users/enums/cacheKey.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @type {{USER: string}} 3 | */ 4 | export const CACHE_KEY = { 5 | USER: 'user' 6 | } -------------------------------------------------------------------------------- /complex-todos-svelte/imports/modules/users/server/index.js: -------------------------------------------------------------------------------- 1 | import './user.cache.js'; -------------------------------------------------------------------------------- /complex-todos-svelte/imports/modules/users/server/user.cache.js: -------------------------------------------------------------------------------- 1 | import {memcache} from '../../../../server/modules/cache/cacheService.js'; 2 | import {CACHE_KEY} from '../enums/cacheKey.js'; 3 | import {Meteor} from 'meteor/meteor'; 4 | 5 | class UserCache 6 | { 7 | /** 8 | * Returns cached profile info 9 | * @locus server 10 | * @param userId {string} 11 | * @returns {object|null} 12 | */ 13 | get(userId) 14 | { 15 | if(memcache.hasKey(`${CACHE_KEY.USER}.${userId}`)) 16 | { 17 | return memcache.getValue(`${CACHE_KEY.USER}.${userId}`); 18 | } 19 | else 20 | { 21 | let userFromDB = Meteor.users.findOne(userId); 22 | 23 | if(userFromDB !== null) 24 | { 25 | memcache.setValue(`${CACHE_KEY.USER}.${userId}`, userFromDB); 26 | } 27 | 28 | return userFromDB; 29 | } 30 | } 31 | /** 32 | * Adds provided user to the cache 33 | * @locus server 34 | * @param user {object} 35 | */ 36 | cache(user) 37 | { 38 | memcache.setValue(`${CACHE_KEY.USER}.${user._id}`, user); 39 | } 40 | /** 41 | * Removes cache of provided profile 42 | * @locus server 43 | * @param userId {string} 44 | */ 45 | remove(userId) 46 | { 47 | memcache.remove(`${CACHE_KEY.USER}.${userId}`); 48 | } 49 | } 50 | 51 | export const userCache = new UserCache(); -------------------------------------------------------------------------------- /complex-todos-svelte/imports/shared/enums/events.js: -------------------------------------------------------------------------------- 1 | export const EVENT = { 2 | TASKS: { 3 | EXPIRE: 'tasks.expire' 4 | } 5 | }; -------------------------------------------------------------------------------- /complex-todos-svelte/imports/shared/functions/bound.js: -------------------------------------------------------------------------------- 1 | import {Meteor} from 'meteor/meteor'; 2 | 3 | /** 4 | * Used in callbacks which should be called with Meteor context 5 | */ 6 | export const bound = Meteor.bindEnvironment((callback) => 7 | { 8 | callback(); 9 | }); -------------------------------------------------------------------------------- /complex-todos-svelte/imports/shared/functions/isDefined.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @param reference {*} 3 | * @return {boolean} 4 | */ 5 | export const isUndefined = (reference) => 6 | { 7 | return reference === void 0; 8 | }; 9 | 10 | /** 11 | * @param reference {*} 12 | * @return {boolean} 13 | */ 14 | export const isDefined = (reference) => 15 | { 16 | return !isUndefined(reference); 17 | }; -------------------------------------------------------------------------------- /complex-todos-svelte/imports/shared/functions/lang.js: -------------------------------------------------------------------------------- 1 | import {TAPi18n} from 'meteor/tap:i18n'; 2 | 3 | /** 4 | * @param key {string} 5 | * @param options {*} 6 | * @return {*} 7 | */ 8 | export const lang = (key, options = '') => 9 | { 10 | return TAPi18n.__(key, options); 11 | }; -------------------------------------------------------------------------------- /complex-todos-svelte/imports/shared/functions/user.js: -------------------------------------------------------------------------------- 1 | import {Meteor} from 'meteor/meteor'; 2 | import {UNIT_TEST} from '../../../tests/enums/users.js'; 3 | 4 | /** 5 | * @type {{readonly details: (*), readonly _id: *}} 6 | */ 7 | export const User = { 8 | get _id() 9 | { 10 | if(Meteor.isTest) 11 | { 12 | return UNIT_TEST.USER_ID; 13 | } 14 | 15 | return Meteor.userId(); 16 | }, 17 | get details() 18 | { 19 | if(Meteor.isTest) 20 | { 21 | return { 22 | _id: UNIT_TEST.USER_ID, 23 | username: UNIT_TEST.USERNAME 24 | }; 25 | } 26 | 27 | if(Meteor.isClient) 28 | { 29 | return Meteor.users.findOne(this._id); 30 | } 31 | else 32 | { 33 | const {userCache} = require('../../modules/users/server/user.cache.js'); 34 | return userCache.get(this._id); 35 | } 36 | } 37 | }; -------------------------------------------------------------------------------- /complex-todos-svelte/imports/shared/mixins/LoggedInMixin.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Mixin for validated methods 3 | * @param methodOptions {object} 4 | * @returns {*} 5 | * @constructor 6 | */ 7 | export const LoggedInMixin = function(methodOptions) 8 | { 9 | const runFunction = methodOptions.run; 10 | 11 | methodOptions.run = function() 12 | { 13 | if(!this.userId) 14 | { 15 | throw new Meteor.Error(`Only users can run this`); 16 | } 17 | 18 | return runFunction.call(this, ...arguments); 19 | }; 20 | 21 | return methodOptions; 22 | }; -------------------------------------------------------------------------------- /complex-todos-svelte/imports/shared/utilities/dateUtility.js: -------------------------------------------------------------------------------- 1 | export class DateUtility 2 | { 3 | /** 4 | * @param day {number} 5 | * @returns {Date} 6 | */ 7 | static beforeDays(day = 1) 8 | { 9 | let date = new Date(); 10 | date.setDate(date.getDate() - day); 11 | 12 | return date; 13 | } 14 | } -------------------------------------------------------------------------------- /complex-todos-svelte/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "complex-todos-svelte", 3 | "private": true, 4 | "scripts": { 5 | "start": "meteor -s settings.json --port 3000", 6 | "test": "TEST_WATCH=1 meteor -s settings.json --port 3000 test --driver-package meteortesting:mocha", 7 | "cypress": "cypress open", 8 | "visualize": "meteor -s settings.json --production --extra-packages bundle-visualizer", 9 | "deploy": "cd .deploy && mup deploy" 10 | }, 11 | "dependencies": { 12 | "@babel/runtime": "^7.15.3", 13 | "bcrypt": "^5.0.1", 14 | "jquery": "^3.4.1", 15 | "meteor-node-stubs": "^1.0.0", 16 | "node-cache": "^5.1.2", 17 | "simpl-schema": "^1.10.2", 18 | "svelte": "^3.31.2", 19 | "svelte-routing": "^1.6.0" 20 | }, 21 | "meteor": { 22 | "mainModule": { 23 | "client": "client/main.js", 24 | "server": "server/main.js" 25 | }, 26 | "testModule": "tests/main.js" 27 | }, 28 | "devDependencies": { 29 | "chai": "^4.2.0", 30 | "cypress": "^7.3.0" 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /complex-todos-svelte/packages/logger/.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | patreon: dr_dimitru 4 | custom: https://paypal.me/veliovgroup 5 | -------------------------------------------------------------------------------- /complex-todos-svelte/packages/logger/.github/ISSUE_TEMPLATE: -------------------------------------------------------------------------------- 1 | ### I'm having an issue: 2 | - Give an expressive description of what is went wrong 3 | - Version of `ostrio:logger` you're experiencing this issue 4 | - Version of `Meteor` you're experiencing this issue 5 | - Is it *Server* or *Client* (*Browser*) issue? 6 | - Browser name and its version (Chrome, Firefox, Safari, etc.)? 7 | - Platform name and its version (Win, Mac, Linux)? 8 | - If you're getting an error or exception, please provide its full stack-trace as plain-text or screenshot 9 | 10 | ### I have a suggestion: 11 | - Describe your feature / request 12 | - How you going to use it? Give a usage example(s) 13 | 14 | ### Documentation is missing something or incorrect (have typos, etc.): 15 | - Give an expressive description what you have changed/added and why 16 | - Make sure you're using correct markdown markup 17 | - Make sure all code blocks starts with tripple ``` (*backtick*) and have a syntax tag, for more read [this docs](https://help.github.com/articles/creating-and-highlighting-code-blocks/#syntax-highlighting) 18 | - Post your addition/changes in issue, we will manage it 19 | 20 | ## Thank you, and do not forget to get rid of this default message 21 | -------------------------------------------------------------------------------- /complex-todos-svelte/packages/logger/.github/PULL_REQUEST_TEMPLATE: -------------------------------------------------------------------------------- 1 | Thank you for contribution. Before you go: 2 | 1. Make sure you're using `spaces` for indentation 3 | 2. Make sure all new code is documented in-code-docs 4 | 3. Make sure new features, or changes in behavior is documented in README.md and/or other docs materials 5 | 4. Make sure this PR was previously discussed, if not create new issue ticket for your PR 6 | 5. Give an expressive description what you have changed/added and why 7 | 8 | Thank you for making this package better :) 9 | 10 | ## Do not forget to get rid of this default message -------------------------------------------------------------------------------- /complex-todos-svelte/packages/logger/.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | .npm 3 | node_modules -------------------------------------------------------------------------------- /complex-todos-svelte/packages/logger/.versions: -------------------------------------------------------------------------------- 1 | allow-deny@1.1.0 2 | babel-compiler@7.6.0 3 | babel-runtime@1.3.0 4 | base64@1.0.11 5 | binary-heap@1.0.11 6 | boilerplate-generator@1.6.0 7 | callback-hook@1.1.0 8 | check@1.3.1 9 | ddp@1.4.0 10 | ddp-client@2.3.3 11 | ddp-common@1.4.0 12 | ddp-server@2.2.0 13 | diff-sequence@1.1.1 14 | dynamic-import@0.5.0 15 | ecmascript@0.12.4 16 | ecmascript-runtime@0.7.0 17 | ecmascript-runtime-client@0.8.0 18 | ecmascript-runtime-server@0.7.1 19 | ejson@1.1.0 20 | fetch@0.1.0 21 | geojson-utils@1.0.10 22 | id-map@1.1.0 23 | inter-process-messaging@0.1.0 24 | local-test:ostrio:logger@2.0.8 25 | logging@1.1.20 26 | meteor@1.9.2 27 | minimongo@1.4.5 28 | modern-browsers@0.1.3 29 | modules@0.13.0 30 | modules-runtime@0.10.3 31 | mongo@1.6.0 32 | mongo-decimal@0.1.0 33 | mongo-dev-server@1.1.0 34 | mongo-id@1.0.7 35 | npm-mongo@3.1.1 36 | ordered-dict@1.1.0 37 | ostrio:logger@2.0.8 38 | promise@0.11.2 39 | random@1.1.0 40 | reactive-var@1.0.11 41 | reload@1.2.0 42 | retry@1.1.0 43 | routepolicy@1.1.0 44 | socket-stream-client@0.2.2 45 | tinytest@1.1.0 46 | tracker@1.2.0 47 | underscore@1.0.10 48 | webapp@1.7.1 49 | webapp-hashing@1.0.9 50 | -------------------------------------------------------------------------------- /complex-todos-svelte/packages/logger/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | Changelog 2 | ========= 3 | For full package history, please see [releases at GitHub](https://github.com/VeliovGroup/Meteor-logger/releases) -------------------------------------------------------------------------------- /complex-todos-svelte/packages/logger/CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Covenant Code of Conduct 2 | 3 | ## Our Pledge 4 | 5 | In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project, and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation. 6 | 7 | ## Our Standards 8 | 9 | Examples of behavior that contributes to creating a positive environment include: 10 | 11 | * Using welcoming and inclusive language 12 | * Being respectful of differing viewpoints and experiences 13 | * Gracefully accepting constructive criticism 14 | * Focusing on what is best for the community 15 | * Showing empathy towards other community members 16 | 17 | Examples of unacceptable behavior by participants include: 18 | 19 | * The use of sexualized language or imagery and unwelcome sexual attention or advances 20 | * Trolling, insulting/derogatory comments, and personal or political attacks 21 | * Public or private harassment 22 | * Publishing others' private information, such as a physical or electronic address, without explicit permission 23 | * Other conduct which could reasonably be considered inappropriate in a professional setting 24 | 25 | ## Our Responsibilities 26 | 27 | Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior. 28 | 29 | Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful. 30 | 31 | ## Scope 32 | 33 | This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers. 34 | 35 | ## Enforcement 36 | 37 | Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at info@veliovgroup.com. The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately. 38 | 39 | Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership. 40 | 41 | ## Attribution 42 | 43 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version] 44 | 45 | [homepage]: http://contributor-covenant.org 46 | [version]: http://contributor-covenant.org/version/1/4/ 47 | -------------------------------------------------------------------------------- /complex-todos-svelte/packages/logger/CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | ### I'm having an issue: 2 | 1. Search [issues](https://github.com/VeliovGroup/Meteor-logger/issues?utf8=✓&q=is%3Aissue), maybe your issue is already solved 3 | 2. Before submitting an issue make sure it's only related to `ostrio:logger` package 4 | 3. If your issue is not solved: 5 | - Give an expressive description of what is gone wrong 6 | - Version of `ostrio:logger` you're experiencing this issue 7 | - Version of `Meteor` you're experiencing this issue 8 | - Is it *Server* or *Client* (*Browser*) issue? 9 | - Browser name and its version (Chrome, Firefox, Safari, etc.)? 10 | - Platform name and its version (Win, Mac, Linux)? 11 | - If you're getting an error or exception, please provide its full stack-trace as plain-text or screenshot 12 | 13 | ### I have a suggestion: 14 | 1. PRs are always welcome - [send a PR](https://github.com/VeliovGroup/Meteor-logger/pulls) 15 | 2. If you're can not send a PR for some reason: 16 | - Create a new issue ticket 17 | - Describe your feature / request 18 | - How are you going to use it? Give a usage example(s) 19 | 20 | ### Documentation is missing something or incorrect (have typos, etc.): 21 | 1. PRs are always welcome - [send a PR](https://github.com/VeliovGroup/Meteor-logger/pulls) 22 | 2. If you're can not send a PR to docs for some reason: 23 | - Create a new issue ticket 24 | - Give an expressive description what you have changed/added and why 25 | - Make sure you're using correct markdown markup 26 | - Make sure all code blocks starts with triple ``` (*backtick*) and have a syntax tag, for more read [this docs](https://help.github.com/articles/creating-and-highlighting-code-blocks/#syntax-highlighting) 27 | - Post addition/changes as issue ticket, we will manage it -------------------------------------------------------------------------------- /complex-todos-svelte/packages/logger/HISTORY.md: -------------------------------------------------------------------------------- 1 | History 2 | ========= 3 | For full package history, please see [releases at GitHub](https://github.com/VeliovGroup/Meteor-logger/releases) -------------------------------------------------------------------------------- /complex-todos-svelte/packages/logger/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2019, dr.dimitru (Dmitry A.; Veliov Group, LLC) 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, 5 | with or without modification, are permitted provided 6 | that the following conditions are met: 7 | 8 | 1. Redistributions of source code must retain the 9 | above copyright notice, this list of conditions 10 | and the following disclaimer. 11 | 12 | 2. Redistributions in binary form must reproduce the 13 | above copyright notice, this list of conditions and 14 | the following disclaimer in the documentation and/or 15 | other materials provided with the distribution. 16 | 17 | 3. Neither the name of the copyright holder nor the 18 | names of its contributors may be used to endorse or 19 | promote products derived from this software without 20 | specific prior written permission. 21 | 22 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 23 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 24 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 25 | ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 26 | LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 27 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 28 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 29 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 30 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 31 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 32 | -------------------------------------------------------------------------------- /complex-todos-svelte/packages/logger/meteor-logger.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/meteor/examples/c44bd2426dac0d3b6edf2535e82a7c39236f6e6e/complex-todos-svelte/packages/logger/meteor-logger.jpg -------------------------------------------------------------------------------- /complex-todos-svelte/packages/logger/package.js: -------------------------------------------------------------------------------- 1 | Package.describe({ 2 | name: 'ostrio:logger', 3 | version: '2.0.9', // couldn't change the version because the other dependencies of logger 4 | summary: 'Logging: isomorphic driver with support of MongoDB, File (FS) and Console', 5 | git: 'https://github.com/VeliovGroup/Meteor-logger', 6 | documentation: 'README.md' 7 | }); 8 | 9 | Package.onUse((api) => { 10 | api.versionsFrom('1.4'); 11 | api.use(['ecmascript', 'reactive-var', 'check'], ['client', 'server']); 12 | api.mainModule('logger.js', ['client', 'server']); 13 | }); 14 | 15 | Package.onTest((api) => { 16 | api.use('tinytest'); 17 | api.use(['ecmascript', 'underscore', 'ostrio:logger']); 18 | api.addFiles('logger-tests.js'); 19 | }); 20 | -------------------------------------------------------------------------------- /complex-todos-svelte/packages/readme.md: -------------------------------------------------------------------------------- 1 | # Custom & Local Packages 2 | If you want you can write your own Meteor packages or change a current one. 3 | 4 | For example, I found a small bug in ```ostrio:logger``` and put that package into the folder. 5 | Then, I fixed it for my own purpose. 6 | -------------------------------------------------------------------------------- /complex-todos-svelte/screenshot.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/meteor/examples/c44bd2426dac0d3b6edf2535e82a7c39236f6e6e/complex-todos-svelte/screenshot.jpg -------------------------------------------------------------------------------- /complex-todos-svelte/server/init.js: -------------------------------------------------------------------------------- 1 | import {log} from '../imports/shared/logger/logger.js'; 2 | import {Jobs} from 'meteor/msavin:sjobs'; 3 | import {JOB} from './shared/enums/job.js'; 4 | 5 | /** 6 | * Initialize server at startup 7 | * @locus server 8 | */ 9 | class ServerInit 10 | { 11 | /** 12 | * @constructor 13 | */ 14 | constructor() 15 | { 16 | log.info('Server is starting'); 17 | 18 | this.initializeJobs(); 19 | } 20 | 21 | /** 22 | * Run added jobs 23 | */ 24 | initializeJobs() 25 | { 26 | Jobs.run(JOB.TASKS.EXPIRE, { 27 | in: { 28 | days: 7 29 | } 30 | } 31 | ); 32 | } 33 | } 34 | 35 | /** 36 | * No need to export it 37 | * It will only run once on server initialize 38 | */ 39 | Meteor.startup(function() 40 | { 41 | new ServerInit; 42 | }); 43 | -------------------------------------------------------------------------------- /complex-todos-svelte/server/main.js: -------------------------------------------------------------------------------- 1 | import './modules.js'; 2 | import './init.js'; 3 | -------------------------------------------------------------------------------- /complex-todos-svelte/server/modules.js: -------------------------------------------------------------------------------- 1 | import '../imports/modules/tasks/server'; 2 | import '../imports/modules/users/server'; 3 | 4 | import './modules/cache/server'; 5 | import './modules/dummies/server'; 6 | import './modules/jobs/server'; 7 | import './modules/migrations/server'; -------------------------------------------------------------------------------- /complex-todos-svelte/server/modules/cache/server/index.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/meteor/examples/c44bd2426dac0d3b6edf2535e82a7c39236f6e6e/complex-todos-svelte/server/modules/cache/server/index.js -------------------------------------------------------------------------------- /complex-todos-svelte/server/modules/dummies/dummiesService.js: -------------------------------------------------------------------------------- 1 | import {log} from '../../../imports/shared/logger/logger.js'; 2 | import {DUMMY_USERS} from './fixtures/dummyUsers.js'; 3 | import {DUMMY_TASKS} from './fixtures/dummyTasks.js'; 4 | import {taskRepository} from '../../../imports/modules/tasks/taskRepository.js'; 5 | import {Mongo} from 'meteor/mongo'; 6 | 7 | /** 8 | * This service adds dummy data to test all features including franchise and admin actions 9 | * the user which will be added is an admin account. Thus, the tester can check everything 10 | * @development 11 | * @locus server 12 | */ 13 | class DummiesService 14 | { 15 | /** 16 | * @constructor 17 | * @development 18 | * @locus server 19 | */ 20 | constructor() 21 | { 22 | if(Meteor.isProduction) 23 | { 24 | return true; 25 | } 26 | 27 | this.tasks = DUMMY_TASKS; 28 | this.users = DUMMY_USERS; 29 | } 30 | 31 | /** 32 | * Clears all database 33 | * @development 34 | * @locus server 35 | */ 36 | clearDatabase() 37 | { 38 | log.debug(__fn); 39 | 40 | const collections = Mongo.Collection.getAll(); 41 | 42 | // Add special collections here to prevent restart to start the tests 43 | const restrictedCollections = ['roles', 'migrations', 'jobs_data', 'jobs_dominator_3']; 44 | 45 | collections.forEach(collection => 46 | { 47 | if(!restrictedCollections.includes(collection)) 48 | { 49 | collection.instance.remove({}); 50 | } 51 | }); 52 | } 53 | 54 | /** 55 | * Inserts dummy data 56 | * @development 57 | * @locus server 58 | * @returns {boolean} 59 | */ 60 | insertDummyData() 61 | { 62 | log.debug(__fn); 63 | 64 | this._insertTasks(); 65 | this._insertUsers(); 66 | } 67 | 68 | /** 69 | * @development 70 | * @locus server 71 | * @private 72 | */ 73 | _insertTasks() 74 | { 75 | log.debug(__fn); 76 | 77 | this.tasks.forEach(task => 78 | { 79 | taskRepository.insertBulk(task); 80 | }); 81 | 82 | taskRepository.executeBulk(); 83 | } 84 | 85 | /** 86 | * @development 87 | * @locus server 88 | * @private 89 | */ 90 | _insertUsers() 91 | { 92 | log.debug(__fn); 93 | 94 | this.users.forEach(user => 95 | { 96 | Meteor.users.insert(user); 97 | }); 98 | } 99 | } 100 | 101 | export const dummiesService = new DummiesService(); -------------------------------------------------------------------------------- /complex-todos-svelte/server/modules/dummies/fixtures/dummyTasks.js: -------------------------------------------------------------------------------- 1 | export const DUMMY_TASKS = [{ 2 | '_id': 't6xnFenfSrXFkdTek', 3 | 'text': 'expired task', 4 | 'createdAt': new Date('2021-05-05'), 5 | 'owner': 'jtX6xqGj29tq5Nhdh', 6 | 'username': 'gunce', 7 | 'expired': 'true' 8 | }, { 9 | '_id': 'NnNQmTdR7LbQrCePr', 10 | 'text': 'new task', 11 | 'createdAt': new Date(), 12 | 'owner': 'jtX6xqGj29tq5Nhdh', 13 | 'username': 'gunce' 14 | }, { 15 | '_id': 'oYtokZEpZu4SRgQcF', 16 | 'text': 'completed task', 17 | 'createdAt': new Date(), 18 | 'owner': 'jtX6xqGj29tq5Nhdh', 19 | 'username': 'gunce', 20 | 'checked': true 21 | }, { 22 | '_id': 'pPRcej6wE3uGYWHJq', 23 | 'text': 'private task', 24 | 'createdAt': new Date(), 25 | 'owner': 'jtX6xqGj29tq5Nhdh', 26 | 'username': 'gunce', 27 | 'private': true 28 | }]; -------------------------------------------------------------------------------- /complex-todos-svelte/server/modules/dummies/fixtures/dummyUsers.js: -------------------------------------------------------------------------------- 1 | export const DUMMY_USERS = [{ 2 | '_id': 'jtX6xqGj29tq5Nhdh', 3 | 'services': { 4 | 'password': { 5 | 'bcrypt': '$2b$10$tzdAErrtFnBVIe/xyazlZe.q5DUUOVBx8iZXftOXwiudsJRtPaiye' 6 | } 7 | }, 8 | 'username': 'gunce' 9 | }]; -------------------------------------------------------------------------------- /complex-todos-svelte/server/modules/dummies/readme.md: -------------------------------------------------------------------------------- 1 | # Dummy data 2 | This module helps us to insert and clear dummy data from database in development. 3 | 4 | This module has no use in production. 5 | -------------------------------------------------------------------------------- /complex-todos-svelte/server/modules/dummies/server/dummies.methods.js: -------------------------------------------------------------------------------- 1 | import {dummiesService} from '../dummiesService.js'; 2 | 3 | /** 4 | * These methods and dummiesService are not working 5 | * in production server 6 | * @development 7 | * @locus server 8 | */ 9 | Meteor.methods({ 10 | /** 11 | * Clears database of the applications to run before tests 12 | * Some collections such as roles or migrations are scoped out 13 | * @development 14 | * @locus server 15 | */ 16 | 'clear.database'() 17 | { 18 | dummiesService.clearDatabase(); 19 | }, 20 | /** 21 | * Inserts dummy data to mimic real world examples before tests 22 | * @development 23 | * @locus server 24 | */ 25 | 'insert.dummy.data'() 26 | { 27 | dummiesService.insertDummyData(); 28 | } 29 | }); -------------------------------------------------------------------------------- /complex-todos-svelte/server/modules/dummies/server/index.js: -------------------------------------------------------------------------------- 1 | import './dummies.methods.js'; -------------------------------------------------------------------------------- /complex-todos-svelte/server/modules/jobs/server/index.js: -------------------------------------------------------------------------------- 1 | import './tasks.expire.js'; -------------------------------------------------------------------------------- /complex-todos-svelte/server/modules/jobs/server/tasks.expire.js: -------------------------------------------------------------------------------- 1 | import {Jobs} from 'meteor/msavin:sjobs'; 2 | import {DateUtility} from '../../../../imports/shared/utilities/dateUtility.js'; 3 | import {eventEmitter} from '../../../../imports/modules/eventEmitter/eventEmitterService.js'; 4 | import {EVENT} from '../../../../imports/shared/enums/events.js'; 5 | 6 | Jobs.register({ 7 | 'tasks.expire': function() 8 | { 9 | let date = DateUtility.beforeDays(1); 10 | 11 | eventEmitter.emit(EVENT.TASKS.EXPIRE, {maxDate: date}); 12 | } 13 | }); 14 | -------------------------------------------------------------------------------- /complex-todos-svelte/server/modules/migrations/database/migrations.js: -------------------------------------------------------------------------------- 1 | import SimpleSchema from 'simpl-schema'; 2 | 3 | const Migrations = new Mongo.Collection('_migrations'); 4 | 5 | Migrations.attachSchema( 6 | new SimpleSchema({ 7 | version: { 8 | type: String, 9 | defaultValue: 0 10 | } 11 | }) 12 | ); 13 | 14 | export {Migrations}; -------------------------------------------------------------------------------- /complex-todos-svelte/server/modules/migrations/migrationRepository.js: -------------------------------------------------------------------------------- 1 | import {BaseRepository} from '../../../imports/shared/repository/baseRepository.js'; 2 | import {Migrations} from './database/migrations.js'; 3 | 4 | /** 5 | * @locus server 6 | */ 7 | class MigrationRepository extends BaseRepository 8 | { 9 | /** 10 | * @constructor 11 | * @locus server 12 | */ 13 | constructor() 14 | { 15 | super(Migrations); 16 | } 17 | } 18 | 19 | export const migrationRepository = new MigrationRepository(); -------------------------------------------------------------------------------- /complex-todos-svelte/server/modules/migrations/readme.md: -------------------------------------------------------------------------------- 1 | # Migration Files 2 | - This folder includes migration files. 3 | - All files have a version number 4 | - The version of the files are not same with the project version 5 | - Current migration version is located in the database 6 | - Current migration version will be increased after each successful migration -------------------------------------------------------------------------------- /complex-todos-svelte/server/modules/migrations/server/1.0.1.js: -------------------------------------------------------------------------------- 1 | import {migrationService} from '../migrationService.js'; 2 | import {log} from '../../../../imports/shared/logger/logger.js'; 3 | 4 | const version = '1.0.1'; 5 | const migrationName = 'A log for migration'; 6 | 7 | migrationService.addMigration(version, () => 8 | { 9 | log.info(version, migrationName); 10 | }); -------------------------------------------------------------------------------- /complex-todos-svelte/server/modules/migrations/server/index.js: -------------------------------------------------------------------------------- 1 | import './migrations.guards.js'; 2 | 3 | import './1.0.1.js'; -------------------------------------------------------------------------------- /complex-todos-svelte/server/modules/migrations/server/migrations.guards.js: -------------------------------------------------------------------------------- 1 | import {Migrations} from '../database/migrations.js'; 2 | 3 | // This collection is defined on server side only but 4 | // We may want to use a server side database in the shared space 5 | // Thus, defining guards is always a good practice 6 | Migrations.allow({ 7 | /** 8 | * @locus server 9 | * @returns {boolean} 10 | */ 11 | insert() 12 | { 13 | return false; 14 | }, 15 | /** 16 | * @locus server 17 | * @returns {boolean} 18 | */ 19 | update() 20 | { 21 | return false; 22 | }, 23 | /** 24 | * @locus server 25 | * @returns {boolean} 26 | */ 27 | remove() 28 | { 29 | return false; 30 | } 31 | }); -------------------------------------------------------------------------------- /complex-todos-svelte/server/shared/enums/job.js: -------------------------------------------------------------------------------- 1 | export const JOB = { 2 | TASKS: { 3 | EXPIRE: 'tasks.expire' 4 | } 5 | }; -------------------------------------------------------------------------------- /complex-todos-svelte/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "public": { 3 | "log": [ 4 | "ERROR", 5 | "FATAL", 6 | "WARN", 7 | "INFO", 8 | "TRACE", 9 | "DEBUG" 10 | ] 11 | } 12 | } -------------------------------------------------------------------------------- /complex-todos-svelte/tests/enums/users.js: -------------------------------------------------------------------------------- 1 | export const UNIT_TEST = { 2 | USER_ID: 'ecFkNaLpNATJ8avNr', 3 | USERNAME: 'Unit test user' 4 | }; -------------------------------------------------------------------------------- /complex-todos-svelte/tests/main.js: -------------------------------------------------------------------------------- 1 | import assert from 'assert'; 2 | import './package.json.test.js'; 3 | import '../imports/modules/tasks/tasks.methods.test.js'; 4 | 5 | describe('Meteor tests', function() 6 | { 7 | if(Meteor.isClient) 8 | { 9 | it('client is not server', function() 10 | { 11 | assert.strictEqual(Meteor.isServer, false); 12 | }); 13 | } 14 | 15 | if(Meteor.isServer) 16 | { 17 | it('server is not client', function() 18 | { 19 | assert.strictEqual(Meteor.isClient, false); 20 | }); 21 | } 22 | }); 23 | -------------------------------------------------------------------------------- /complex-todos-svelte/tests/package.json.test.js: -------------------------------------------------------------------------------- 1 | import assert from 'assert'; 2 | 3 | describe('complex-todos-svelte', function() 4 | { 5 | it('package.json has correct name', async function() 6 | { 7 | const {name} = await import('../package.json'); 8 | assert.strictEqual(name, 'complex-todos-svelte'); 9 | }); 10 | }); -------------------------------------------------------------------------------- /complex-todos-svelte/tests/readme.md: -------------------------------------------------------------------------------- 1 | # Unit Tests 2 | 3 | This folder contains unit tests 4 | 5 | ### Test Strategy 6 | 7 | Some test may require dummy data, the responsibility of dummy data should not be on test. The test data is different 8 | from dummy data. Test data will be stored and modified by tests. 9 | 10 | ### Test Plan 11 | 12 | 1. Application 13 | - [x] package.json has correct name 14 | 15 | 1. Meteor test 16 | - [x] client is not server 17 | - [x] server is not client 18 | 19 | 1. Task methods 20 | - [x] tasksInsert 21 | - [x] tasksRemove 22 | - [x] tasksUpdateAsChecked 23 | - [ ] tasksUpdateAsPrivate 24 | 25 | ### How to start tests 26 | 27 | Type ```npm test``` into terminal 28 | 29 | ### Location of tests 30 | The ```/test/main.js``` is the entry point of tests, and it 31 | includes tests that are related with application level 32 | Other test are located in their own module folder and 33 | imported into the ```main.js``` -------------------------------------------------------------------------------- /cordova/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | 3 | -------------------------------------------------------------------------------- /cordova/.meteor/.gitignore: -------------------------------------------------------------------------------- 1 | local 2 | -------------------------------------------------------------------------------- /cordova/.meteor/cordova-plugins: -------------------------------------------------------------------------------- 1 | cordova-plugin-appsettings@1.0.2 2 | cordova-plugin-statusbar@2.4.3 3 | fairmanager-cordova-plugin-universal-links@https://github.com/pathable/plugin-universal-links.git#e0177fa5f7084a679c061aa25bc2949ea6d5f95a 4 | onesignal-cordova-plugin@2.8.0 5 | -------------------------------------------------------------------------------- /cordova/.meteor/packages: -------------------------------------------------------------------------------- 1 | # Meteor packages used by this project, one per line. 2 | # Check this file (and the other files in this directory) into your repository. 3 | # 4 | # 'meteor add' and 'meteor remove' will edit this file for you, 5 | # but you can also edit it by hand. 6 | 7 | meteor-base@1.5.1 # Packages every Meteor app needs to have 8 | mobile-experience@1.1.0 # Packages for a great mobile UX 9 | mongo@1.13.0 # The database Meteor supports right now 10 | reactive-var@1.0.11 # Reactive variable for tracker 11 | 12 | standard-minifier-css@1.7.4 # CSS minifier run for production mode 13 | standard-minifier-js@2.7.2 # JS minifier run for production mode 14 | es5-shim@4.8.0 # ECMAScript 5 compatibility for older browsers 15 | ecmascript@0.16.0 # Enable ECMAScript2015+ syntax in app code 16 | typescript@4.4.0 # Enable TypeScript syntax in .ts and .tsx modules 17 | shell-server@0.5.0 # Server-side component of the `meteor shell` command 18 | 19 | autopublish@1.0.7 # Publish all data to the clients (for prototyping) 20 | insecure@1.0.7 # Allow all DB writes from clients (for prototyping) 21 | static-html@1.3.2 # Define static page content in .html files 22 | server-render@0.4.0 # Inject tags into the initial HTML 23 | accounts-base@2.2.0 24 | accounts-password@2.2.0 25 | react-meteor-data 26 | -------------------------------------------------------------------------------- /cordova/.meteor/platforms: -------------------------------------------------------------------------------- 1 | android 2 | browser 3 | ios 4 | server 5 | -------------------------------------------------------------------------------- /cordova/.meteor/release: -------------------------------------------------------------------------------- 1 | METEOR@2.5.1 2 | -------------------------------------------------------------------------------- /cordova/.meteor/versions: -------------------------------------------------------------------------------- 1 | accounts-base@2.2.0 2 | accounts-password@2.2.0 3 | allow-deny@1.1.0 4 | autopublish@1.0.7 5 | autoupdate@1.8.0 6 | babel-compiler@7.7.0 7 | babel-runtime@1.5.0 8 | base64@1.0.12 9 | binary-heap@1.0.11 10 | blaze-tools@1.1.2 11 | boilerplate-generator@1.7.1 12 | caching-compiler@1.2.2 13 | caching-html-compiler@1.2.1 14 | callback-hook@1.4.0 15 | check@1.3.1 16 | ddp@1.4.0 17 | ddp-client@2.5.0 18 | ddp-common@1.4.0 19 | ddp-rate-limiter@1.1.0 20 | ddp-server@2.5.0 21 | diff-sequence@1.1.1 22 | dynamic-import@0.7.2 23 | ecmascript@0.16.0 24 | ecmascript-runtime@0.8.0 25 | ecmascript-runtime-client@0.12.1 26 | ecmascript-runtime-server@0.11.0 27 | ejson@1.1.1 28 | email@2.2.0 29 | es5-shim@4.8.0 30 | fetch@0.1.1 31 | geojson-utils@1.0.10 32 | hot-code-push@1.0.4 33 | html-tools@1.1.2 34 | htmljs@1.1.0 35 | id-map@1.1.1 36 | insecure@1.0.7 37 | inter-process-messaging@0.1.1 38 | launch-screen@1.3.0 39 | localstorage@1.2.0 40 | logging@1.3.1 41 | meteor@1.10.0 42 | meteor-base@1.5.1 43 | minifier-css@1.6.0 44 | minifier-js@2.7.2 45 | minimongo@1.7.0 46 | mobile-experience@1.1.0 47 | mobile-status-bar@1.1.0 48 | modern-browsers@0.1.7 49 | modules@0.17.0 50 | modules-runtime@0.12.0 51 | mongo@1.13.0 52 | mongo-decimal@0.1.2 53 | mongo-dev-server@1.1.0 54 | mongo-id@1.0.8 55 | npm-mongo@3.9.1 56 | ordered-dict@1.1.0 57 | promise@0.12.0 58 | random@1.2.0 59 | rate-limit@1.0.9 60 | react-fast-refresh@0.2.1 61 | react-meteor-data@2.4.0 62 | reactive-var@1.0.11 63 | reload@1.3.1 64 | retry@1.1.0 65 | routepolicy@1.1.1 66 | server-render@0.4.0 67 | service-configuration@1.3.0 68 | sha@1.0.9 69 | shell-server@0.5.0 70 | socket-stream-client@0.4.0 71 | spacebars-compiler@1.3.0 72 | standard-minifier-css@1.7.4 73 | standard-minifier-js@2.7.2 74 | static-html@1.3.2 75 | templating-tools@1.2.1 76 | tracker@1.2.0 77 | typescript@4.4.0 78 | underscore@1.0.10 79 | url@1.3.2 80 | webapp@1.13.0 81 | webapp-hashing@1.1.0 82 | -------------------------------------------------------------------------------- /cordova/client/main.css: -------------------------------------------------------------------------------- 1 | body { 2 | padding: 10px; 3 | font-family: sans-serif; 4 | } 5 | -------------------------------------------------------------------------------- /cordova/client/main.html: -------------------------------------------------------------------------------- 1 | 2 | MeteorApp 3 | 4 | 5 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 |
18 | 19 | -------------------------------------------------------------------------------- /cordova/client/main.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { Meteor } from 'meteor/meteor'; 3 | import { render } from 'react-dom'; 4 | 5 | import '../imports/infra/serviceWorkerInit'; 6 | import '../imports/infra/one-signal'; 7 | 8 | import { App } from '/imports/ui/App'; 9 | 10 | Meteor.startup(() => { 11 | render(, document.getElementById('react-target')); 12 | }); 13 | -------------------------------------------------------------------------------- /cordova/imports/collections/links.js: -------------------------------------------------------------------------------- 1 | import { Mongo } from 'meteor/mongo'; 2 | 3 | export const LinksCollection = new Mongo.Collection('links'); 4 | -------------------------------------------------------------------------------- /cordova/imports/infra/addPlayerId.js: -------------------------------------------------------------------------------- 1 | import {Meteor} from 'meteor/meteor'; 2 | 3 | Meteor.methods({ 4 | addPlayerId({playerId}) { 5 | this.unblock(); 6 | if (Meteor.isClient || !this.userId || !playerId) return null; 7 | 8 | Meteor.users.update(this.userId, {$addToSet: {playersIds: playerId}}); 9 | }, 10 | }); 11 | -------------------------------------------------------------------------------- /cordova/imports/infra/apple-app-site-association.js: -------------------------------------------------------------------------------- 1 | import { getNativeStoresInfo } from './native'; 2 | 3 | export const appleAppSiteAssociation = (req, res) => { 4 | // if you have multiple apps using the same backend you can customize here 5 | // the color, name, description, etc using the req.headers 6 | const nativeStoresInfo = getNativeStoresInfo(); 7 | 8 | if (!nativeStoresInfo.nativeAppEnabled) { 9 | res.setHeader('Content-Type', 'text/html'); 10 | res.writeHead(405); 11 | res.end(`

Native App not enabled

`); 12 | return; 13 | } 14 | if (!nativeStoresInfo.appleTeamId || !nativeStoresInfo.appleItunesAppId) { 15 | res.setHeader('Content-Type', 'text/html'); 16 | res.writeHead(405); 17 | res.end( 18 | `

Apple iTunes App ID and Apple Prefix are not configured

` 19 | ); 20 | return; 21 | } 22 | 23 | const appSiteAssociation = { 24 | applinks: { 25 | apps: [], 26 | details: [ 27 | { 28 | appID: `${nativeStoresInfo.appleTeamId}.${nativeStoresInfo.appleBundleId}`, 29 | paths: ['*'], 30 | }, 31 | ], 32 | }, 33 | }; 34 | 35 | res.setHeader('Content-Type', 'application/json'); 36 | res.writeHead(200); 37 | res.end(JSON.stringify(appSiteAssociation)); 38 | }; 39 | -------------------------------------------------------------------------------- /cordova/imports/infra/constants.js: -------------------------------------------------------------------------------- 1 | // replace cordova-example constants below 2 | export const Colors = {BACKGROUND: 'white', PRIMARY: '#e45735'}; 3 | export const LANGUAGE = 'en-US'; 4 | export const NAME = 'Cordova'; 5 | export const SHORT_NAME = NAME; 6 | export const DESCRIPTION = ''; 7 | export const KEYWORDS = ['', '']; 8 | export const LOGO_URL_WITHOUT_EXT = 9 | 'https://com-meteor-public-assets.s3.amazonaws.com/logo-black'; 10 | -------------------------------------------------------------------------------- /cordova/imports/infra/database-seed.js: -------------------------------------------------------------------------------- 1 | import { Meteor } from 'meteor/meteor'; 2 | import { LinksCollection } from '/imports/collections/links'; 3 | 4 | function insertLink({ title, url }) { 5 | LinksCollection.insert({title, url, createdAt: new Date()}); 6 | } 7 | 8 | Meteor.startup(() => { 9 | // If the Links collection is empty, add some data. 10 | if (LinksCollection.find().count() === 0) { 11 | insertLink({ 12 | title: 'Do the Tutorial', 13 | url: 'https://www.meteor.com/tutorials/react/creating-an-app' 14 | }); 15 | 16 | insertLink({ 17 | title: 'Follow the Guide', 18 | url: 'http://guide.meteor.com' 19 | }); 20 | 21 | insertLink({ 22 | title: 'Read the Docs', 23 | url: 'https://docs.meteor.com' 24 | }); 25 | 26 | insertLink({ 27 | title: 'Discussions', 28 | url: 'https://forums.meteor.com' 29 | }); 30 | } 31 | }); 32 | -------------------------------------------------------------------------------- /cordova/imports/infra/google-analytics.js: -------------------------------------------------------------------------------- 1 | import { Meteor } from 'meteor/meteor'; 2 | import { useEffect, useRef } from 'react'; 3 | 4 | const DEFAULT_ANALYTICS_TRACKER_ID = 5 | Meteor.settings.public.googleAnalyticsTrackingId; 6 | 7 | const getTrackingsIds = ({ gaWebPropertyId } = {}) => 8 | [DEFAULT_ANALYTICS_TRACKER_ID, gaWebPropertyId].filter(Boolean); 9 | 10 | const ga = (...rest) => { 11 | const googleAnalytics = window.gtag; 12 | if (!googleAnalytics || typeof googleAnalytics !== 'function') { 13 | console.warn('googleAnalytics is not available', googleAnalytics); 14 | return; 15 | } 16 | googleAnalytics(...rest); 17 | }; 18 | 19 | export const sendConfigToAnalytics = ({ store } = {}, data, options) => { 20 | getTrackingsIds(store).forEach(trackingId => { 21 | ga('config', trackingId, data, options); 22 | }); 23 | }; 24 | 25 | const addAnalyticsTag = (sink, trackingId) => { 26 | sink.appendToHead(` 27 | 28 | 29 | 35 | `); 36 | }; 37 | 38 | export const addGoogleAnalyticsScript = sink => { 39 | addAnalyticsTag(sink, DEFAULT_ANALYTICS_TRACKER_ID); 40 | }; 41 | 42 | /** 43 | * inspired by https://github.com/mib200/vue-gtm/ 44 | */ 45 | const hasScript = () => 46 | Array.from(document.getElementsByName('script')).some(script => 47 | script.src.includes('googletagmanager') 48 | ); 49 | 50 | // TODO mobile do we need this? 51 | export const loadGoogleAnalytics = (store = {}) => { 52 | if (!Meteor.isClient || hasScript()) { 53 | return false; 54 | } 55 | const { gaPrimaryDomain } = store; 56 | 57 | const script = document.createElement('script'); 58 | script.async = true; 59 | script.src = `https://www.googletagmanager.com/gtag/js?id=${DEFAULT_ANALYTICS_TRACKER_ID}`; 60 | document.head.appendChild(script); 61 | const scriptContent = document.createElement('script'); 62 | const domain = gaPrimaryDomain 63 | ? `gtag('set', 'linker', { 'domains': '${gaPrimaryDomain}' });` 64 | : ''; 65 | scriptContent.innerHTML = ` 66 | window.dataLayer = window.dataLayer || []; 67 | function gtag(){dataLayer.push(arguments);} 68 | gtag('js', new Date()); 69 | gtag('config', '${DEFAULT_ANALYTICS_TRACKER_ID}', { 'transport_type': 'beacon' }); 70 | ${domain} 71 | `; 72 | document.head.appendChild(scriptContent); 73 | return true; 74 | }; 75 | 76 | export const initializeGoogleAnalytics = () => { 77 | loadGoogleAnalytics(); 78 | }; 79 | 80 | export const useGoogleAnalyticsPageView = ({ title, store }) => { 81 | const pageLocationPath = window.location.pathname; 82 | 83 | const lastPageLocationPathRef = useRef(null); 84 | 85 | useEffect(() => { 86 | if ( 87 | !lastPageLocationPathRef.current || 88 | lastPageLocationPathRef.current !== pageLocationPath 89 | ) { 90 | sendConfigToAnalytics( 91 | { store }, 92 | { 93 | page_title: title, 94 | page_location: window.location.href, 95 | page_path: pageLocationPath, 96 | } 97 | ); 98 | } 99 | lastPageLocationPathRef.current = pageLocationPath; 100 | }, [pageLocationPath, title]); 101 | }; 102 | -------------------------------------------------------------------------------- /cordova/imports/infra/methodCall.js: -------------------------------------------------------------------------------- 1 | import { Meteor } from 'meteor/meteor'; 2 | 3 | export const methodCall = (methodName, ...args) => 4 | new Promise((resolve, reject) => { 5 | Meteor.call(methodName, ...args, (error, result) => { 6 | if (error) reject(error); 7 | else resolve(result); 8 | }); 9 | }); 10 | -------------------------------------------------------------------------------- /cordova/imports/infra/native.js: -------------------------------------------------------------------------------- 1 | import { Meteor } from "meteor/meteor"; 2 | 3 | // TODO mobile replace values in settings. 4 | // replace cordova-example native details in the settings 5 | export const APPLE_ITUNES_APP_ID = 6 | Meteor.settings.public.native.appleItunesAppId; 7 | const APPLE_TEAM_ID = Meteor.settings.public.native.appleTeamId; 8 | const APPLE_BUNDLE_ID = 9 | Meteor.settings.public.native.appleBundleId; 10 | const GOOGLE_PLAY_APP_ID = 11 | Meteor.settings.public.native.googlePlayAppId; 12 | const ONE_SIGNAL_GCM_SENDER_ID = Meteor.settings.public.oneSignalGcmSenderId; 13 | export const ONE_SIGNAL_REST_API_KEY = 14 | Meteor.settings.public.native.oneSignalRestApiKey; 15 | export const ONE_SIGNAL_APP_ID = 16 | Meteor.settings.public.native.oneSignalAppId; 17 | 18 | export const getGoolePlayAppUrl = ({googlePlayAppId}) => { 19 | if (!googlePlayAppId) { 20 | return null; 21 | } 22 | return `https://play.google.com/store/apps/details?id=${googlePlayAppId}`; 23 | }; 24 | 25 | export const getAppleItunesAppUrl = ({appleItunesAppId}) => { 26 | if (!appleItunesAppId) { 27 | return null; 28 | } 29 | return `https://itunes.apple.com/app/id${appleItunesAppId}`; 30 | }; 31 | 32 | export const getNativeStoresInfo = () => ({ 33 | appleItunesAppId: APPLE_ITUNES_APP_ID, 34 | googlePlayAppId: GOOGLE_PLAY_APP_ID, 35 | appleTeamId: APPLE_TEAM_ID, 36 | appleBundleId: APPLE_BUNDLE_ID, 37 | oneSignalGcmSenderId: ONE_SIGNAL_GCM_SENDER_ID, 38 | // change to true to disable native stuff 39 | nativeAppEnabled: true, 40 | }); 41 | -------------------------------------------------------------------------------- /cordova/imports/infra/one-signal.js: -------------------------------------------------------------------------------- 1 | import {Meteor} from 'meteor/meteor'; 2 | // TODO mobile add accounts 3 | import {Accounts} from 'meteor/accounts-base'; 4 | 5 | import {methodCall} from './methodCall'; 6 | 7 | let currentPlayerId = null; 8 | 9 | export const addPlayerId = playerId => { 10 | methodCall('addPlayerId', { 11 | playerId, 12 | }) 13 | .catch(e => { 14 | console.error(`Error adding player id ${playerId}`, e); 15 | }); 16 | }; 17 | 18 | const goTo = route => { 19 | const navigateTo = `${!route.startsWith('/') ? '/' : ''}${route}`; 20 | console.debug(`navigateTo ${navigateTo}`); 21 | history.push(navigateTo); 22 | }; 23 | 24 | Meteor.startup(() => { 25 | Accounts.onLogin(data => { 26 | console.log('onLogin', Meteor.userId(), data); 27 | addPlayerId(currentPlayerId); 28 | }); 29 | 30 | if (!Meteor.isCordova) { 31 | return; 32 | } 33 | 34 | let appId = null; 35 | // eslint-disable-next-line no-undef 36 | window.plugins.AppSettings.get( 37 | ['onesignalappid', 'universallink'], 38 | configs => { 39 | const universalLink = configs.universallink; 40 | // cordova from fairmanager-cordova-plugin-universal-links 41 | window.cordova.plugins.UniversalLinks.subscribe(null, eventData => { 42 | console.debug(`cordovaRedirect ${universalLink} ${eventData.url}`); 43 | 44 | if (!eventData.url.includes(universalLink)) return; 45 | 46 | const redirectUrl = eventData.url.replace(universalLink, ''); 47 | if (redirectUrl) { 48 | const navigateTo = `${ 49 | !redirectUrl.startsWith('/') ? '/' : '' 50 | }${redirectUrl}`; 51 | console.debug(`navigateTo ${navigateTo}`); 52 | history.push(navigateTo); 53 | } 54 | }); 55 | 56 | appId = configs.onesignalappid; 57 | if (appId) { 58 | window.plugins.OneSignal.setLogLevel({logLevel: 4, visualLevel: 1}); 59 | 60 | const notificationOpenedCallback = notification => { 61 | console.debug('received notification', JSON.stringify(notification)); 62 | // TODO mobile readme: explain additionalData.route 63 | const route = notification && notification.payload && 64 | notification.payload.additionalData && 65 | notification.payload.additionalData.route; 66 | if (route) { 67 | goTo(route); 68 | } 69 | }; 70 | 71 | window.plugins.OneSignal.startInit(appId); 72 | window.plugins.OneSignal.handleNotificationOpened( 73 | notificationOpenedCallback 74 | ); 75 | window.plugins.OneSignal.getIds(ids => { 76 | currentPlayerId = ids.userId; 77 | }); 78 | window.plugins.OneSignal.endInit(); 79 | } 80 | }, 81 | error => { 82 | console.error( 83 | 'Error getting configuration from config.xml in Cordova', 84 | error 85 | ); 86 | } 87 | ); 88 | }); 89 | -------------------------------------------------------------------------------- /cordova/imports/infra/pwa-json.js: -------------------------------------------------------------------------------- 1 | import { 2 | getAppleItunesAppUrl, 3 | getGoolePlayAppUrl, 4 | getNativeStoresInfo, 5 | } from './native'; 6 | import { 7 | Colors, DESCRIPTION, 8 | LANGUAGE, 9 | LOGO_URL_WITHOUT_EXT, 10 | NAME, 11 | SHORT_NAME 12 | } from "./constants"; 13 | 14 | 15 | export const getPwaSettings = () => { 16 | const logo = LOGO_URL_WITHOUT_EXT; 17 | const nativeStoresInfo = getNativeStoresInfo(); 18 | const { 19 | appleItunesAppId, 20 | googlePlayAppId, 21 | nativeAppEnabled, 22 | oneSignalGcmSenderId, 23 | } = nativeStoresInfo; 24 | 25 | return { 26 | background_color: Colors.BACKGROUND, 27 | theme_color: Colors.PRIMARY, 28 | start_url: '/', 29 | display: 'standalone', 30 | orientation: 'portrait', 31 | lang: LANGUAGE, 32 | name: NAME, 33 | short_name: SHORT_NAME, 34 | description: DESCRIPTION, 35 | icons: [ 36 | { 37 | src: `${logo}_128.png`, 38 | type: 'image/png', 39 | sizes: '128x128', 40 | }, 41 | { 42 | src: `${logo}_152.png`, 43 | type: 'image/png', 44 | sizes: '152x152', 45 | }, 46 | { 47 | src: `${logo}_144.png`, 48 | type: 'image/png', 49 | sizes: '144x144', 50 | }, 51 | { 52 | src: `${logo}_192.png`, 53 | type: 'image/png', 54 | sizes: '192x192', 55 | }, 56 | { 57 | src: `${logo}_512.png`, 58 | type: 'image/png', 59 | sizes: '512x512', 60 | }, 61 | ].filter(icon => !!icon.src), 62 | gcm_sender_id: oneSignalGcmSenderId, 63 | prefer_related_applications: nativeAppEnabled, 64 | related_applications: [ 65 | nativeAppEnabled && 66 | googlePlayAppId && { 67 | platform: 'play', 68 | url: getGoolePlayAppUrl(nativeStoresInfo), 69 | id: googlePlayAppId, 70 | }, 71 | nativeAppEnabled && 72 | appleItunesAppId && { 73 | platform: 'itunes', 74 | url: getAppleItunesAppUrl(nativeStoresInfo), 75 | id: appleItunesAppId, 76 | }, 77 | ].filter(Boolean), 78 | }; 79 | }; 80 | 81 | export const pwaJson = (req, res) => { 82 | res.setHeader('Content-Type', 'javascript/json'); 83 | res.writeHead(200); 84 | 85 | // if you have multiple apps using the same backend you can customize here 86 | // the color, name, description, etc using the req.headers 87 | const pwa = getPwaSettings(); 88 | 89 | res.end(JSON.stringify(pwa)); 90 | }; 91 | -------------------------------------------------------------------------------- /cordova/imports/infra/rest.js: -------------------------------------------------------------------------------- 1 | import { Meteor } from "meteor/meteor"; 2 | import { WebApp } from 'meteor/webapp'; 3 | import express from 'express'; 4 | import bodyParser from 'body-parser'; 5 | import { pwaJson } from "./pwa-json"; 6 | import { appleAppSiteAssociation } from "./apple-app-site-association"; 7 | 8 | Meteor.startup(() => { 9 | const app = express(); 10 | app.use(bodyParser.json()); 11 | app.get('/pwa.json', Meteor.bindEnvironment(pwaJson)); 12 | app.get( 13 | '/apple-app-site-association', 14 | Meteor.bindEnvironment(appleAppSiteAssociation) 15 | ); 16 | 17 | WebApp.connectHandlers.use(app); 18 | }); 19 | -------------------------------------------------------------------------------- /cordova/imports/infra/sendPush.js: -------------------------------------------------------------------------------- 1 | import { Meteor } from 'meteor/meteor'; 2 | import request from 'request'; 3 | 4 | import {ONE_SIGNAL_APP_ID, ONE_SIGNAL_REST_API_KEY} from "./native"; 5 | 6 | // TODO mobile send push example 7 | export const sendPush = ({ heading, content, playersIds, data = {} }) => 8 | new Promise((resolve, reject) => { 9 | const options = { 10 | uri: 'https://onesignal.com/api/v1/notifications', 11 | headers: { 12 | 'Content-Type': 'application/json; charset=utf-8', 13 | Authorization: `Basic ${ONE_SIGNAL_REST_API_KEY}`, 14 | }, 15 | body: JSON.stringify({ 16 | ...(heading ? { headings: { en: heading } } : {}), 17 | contents: { en: content }, 18 | include_player_ids: playersIds, 19 | app_id: ONE_SIGNAL_APP_ID, 20 | data, 21 | web_url: Meteor.absoluteUrl(data.route), 22 | }), 23 | }; 24 | 25 | request.post(options, (error, response, body) => { 26 | if (error) reject(error); 27 | resolve({ 28 | response: JSON.parse(body), 29 | }); 30 | }); 31 | }); 32 | -------------------------------------------------------------------------------- /cordova/imports/infra/serviceWorkerInit.js: -------------------------------------------------------------------------------- 1 | const iOS = () => { 2 | const iDevices = [ 3 | 'iPad Simulator', 4 | 'iPhone Simulator', 5 | 'iPod Simulator', 6 | 'iPad', 7 | 'iPhone', 8 | 'iPod', 9 | ]; 10 | 11 | return !!navigator.platform && iDevices.indexOf(navigator.platform) !== -1; 12 | }; 13 | 14 | const register = () => { 15 | if (!('serviceWorker' in navigator)) { 16 | console.log('serviceWorker is not in navigator!'); 17 | return; 18 | } 19 | if (iOS()) { 20 | console.log('iOS device then not register sw (was with error)!'); 21 | return; 22 | } 23 | navigator.serviceWorker 24 | .register('/sw.js') 25 | 26 | .then(() => { 27 | console.log('serviceWorker registered with success!'); 28 | }) 29 | .catch(error => console.error('Error registering serviceWorker!', error)); 30 | }; 31 | 32 | register(); 33 | -------------------------------------------------------------------------------- /cordova/imports/methods/createUser.js: -------------------------------------------------------------------------------- 1 | import {Meteor} from 'meteor/meteor'; 2 | 3 | Meteor.methods({ 4 | createUser({playerId}) { 5 | this.unblock(); 6 | if (Meteor.isClient || !this.userId || !playerId) return null; 7 | 8 | Meteor.users.update(this.userId, {$addToSet: {playersIds: playerId}}); 9 | }, 10 | }); 11 | -------------------------------------------------------------------------------- /cordova/imports/ui/App.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import {Hello} from './Hello'; 3 | import {Info} from './Info'; 4 | import {User} from "./User"; 5 | 6 | export const App = () => ( 7 |
8 |

Welcome to Meteor!

9 | 10 | 11 | 12 |
13 | ); 14 | -------------------------------------------------------------------------------- /cordova/imports/ui/Hello.js: -------------------------------------------------------------------------------- 1 | import React, { useState } from 'react'; 2 | 3 | export const Hello = () => { 4 | const [counter, setCounter] = useState(0); 5 | 6 | const increment = () => { 7 | setCounter(counter + 1); 8 | }; 9 | 10 | return ( 11 |
12 | 13 |

You've pressed the button {counter} times.

14 |
15 | ); 16 | }; 17 | -------------------------------------------------------------------------------- /cordova/imports/ui/Info.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { useTracker } from 'meteor/react-meteor-data'; 3 | import { LinksCollection } from '/imports/collections/links'; 4 | 5 | export const Info = () => { 6 | const links = useTracker(() => { 7 | return LinksCollection.find().fetch(); 8 | }); 9 | 10 | return ( 11 |
12 |

Learn Meteor!

13 | 18 |
19 | ); 20 | }; 21 | -------------------------------------------------------------------------------- /cordova/imports/ui/User.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import {Accounts} from "meteor/accounts-base"; 3 | import {Meteor} from "meteor/meteor"; 4 | import {useTracker} from 'meteor/react-meteor-data'; 5 | 6 | const USERNAME = 'test@mobile.meteorapp.com'; 7 | const PASSWORD = '123456'; 8 | 9 | export const User = () => { 10 | const user = useTracker(() => Meteor.user()); 11 | const createUser = () => { 12 | Accounts.createUser( 13 | { 14 | username: USERNAME, 15 | email: USERNAME, 16 | password: PASSWORD, 17 | }, 18 | error => { 19 | if (error) { 20 | console.error(`Error creating user ${USERNAME}`, error); 21 | return; 22 | } 23 | 24 | console.log(`${USERNAME} created`); 25 | } 26 | ); 27 | }; 28 | 29 | const loginUser = () => { 30 | Meteor.loginWithPassword( 31 | USERNAME, 32 | PASSWORD, 33 | error => { 34 | if (!error) { 35 | console.log(`User authenticated ${USERNAME}`); 36 | return; 37 | } 38 | 39 | if (error.error === 403) { 40 | console.warn(`User not found`, error); 41 | return; 42 | } 43 | 44 | console.error(`Error authenticating user ${USERNAME}`, error); 45 | } 46 | ); 47 | }; 48 | 49 | const logoutUser = () => { 50 | Meteor.logout(() => console.log(`User logged out ${USERNAME}`)); 51 | }; 52 | 53 | return ( 54 |
55 | {!user && <> 56 | 57 | 58 | } 59 | {user && <> 60 | 61 | } 62 |
63 | ); 64 | }; 65 | -------------------------------------------------------------------------------- /cordova/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "cordova", 3 | "private": true, 4 | "scripts": { 5 | "start": "meteor run --settings private/env/dev/settings.json", 6 | "start-production": "meteor run --settings private/env/production/settings.json", 7 | "visualize": "meteor --production --extra-packages bundle-visualizer" 8 | }, 9 | "dependencies": { 10 | "@babel/runtime": "^7.8.4", 11 | "bcrypt": "^4.0.1", 12 | "body-parser": "^1.19.0", 13 | "express": "^4.17.1", 14 | "meteor-node-stubs": "^1.0.0", 15 | "react": "^16.13.1", 16 | "react-dom": "^16.13.1", 17 | "request": "^2.88.2" 18 | }, 19 | "meteor": { 20 | "mainModule": { 21 | "client": "client/main", 22 | "server": "server/main.js" 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /cordova/private/env/production/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "public": { 3 | "native": { 4 | "appleItunesAppId": "2441947344", 5 | "appleTeamId": "XR7QCJTCL9", 6 | "appleBundleId": "com.meteorapp.mobile", 7 | "googlePlayAppId": "com.meteorapp.mobile", 8 | "oneSignalAppId": "a4a5axxx-59f2-493f-abdb-efce7b0c8ef6", 9 | "oneSignalRestApiKey": "XXXwMDI5MWEtNzE3MC00ZGEzLWIyNzAtNzgzYzg5NmU5ZWVj" 10 | } 11 | } 12 | } -------------------------------------------------------------------------------- /cordova/private/jenkins.groovy: -------------------------------------------------------------------------------- 1 | // Use this file as a template for a Job definition using Job DSL Jenkins Plugin https://plugins.jenkins.io/job-dsl/ 2 | def generatedBy = "Generated by jenkins.groovy at ${new Date()}" 3 | def organization = "yourorg" 4 | def project = "yourapp" 5 | 6 | // You need to have a MacOS machine configured in your Nodes in Jenkins with this label 7 | def machineLabel = "macosx" 8 | 9 | def yourKeychainPassword = "yourpass" 10 | 11 | def gitProjectUrl = "git@github.com:${organization}/${project}.git" 12 | def branchName = "main" 13 | 14 | def channel = "#${project}-alerts" 15 | 16 | job("build-native") { 17 | label(machineLabel) 18 | description generatedBy 19 | scm { 20 | git(gitProjectUrl, branchName) 21 | } 22 | triggers { 23 | scm(trigger) 24 | } 25 | steps { 26 | shell(""" 27 | ${installYarn} 28 | cd private/native-app/${environment} 29 | APP_ID=com.meteorapp.mobile ./build.sh 30 | APP_ID=com.meteorapp.mobile ./publish-android.sh 31 | FL_UNLOCK_KEYCHAIN_PASSWORD=${yourKeychainPassword} ./publish-ios.sh 32 | """) 33 | } 34 | configure { 35 | it / 'publishers' / 'jenkins.plugins.slack.SlackNotifier'(plugin: "slack@2.3") { 36 | room(channel) 37 | notifySuccess(true) 38 | notifyFailure(true) 39 | notifyBackToNormal(true) 40 | notifyRepeatedFailure(true) 41 | } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /cordova/private/native-app/production/build.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # fill the data here 4 | env=production 5 | appName=Mobile 6 | buildFolder=meteor-mobile-build-production 7 | host=https://mobile.meteorapp.com 8 | pathToAndroidKeyStore=/Users/filipe/Documents/meteor/ws/mobile/keystore 9 | androidPassword=asdWEQdsaD 10 | keystoreAlias=$APP_ID 11 | 12 | # build 13 | cd ../../../ 14 | rm -rf .meteor/local/cordova-build 15 | rm -rf ../../$buildFolder 16 | echo building app pointing to $host 17 | METEOR_DISABLE_OPTIMISTIC_CACHING=1 LANG=en_US.UTF-8 MOBILE_APP_ID=$APP_ID meteor build ../../$buildFolder --server=$host --mobile-settings private/env/$env/settings.json 18 | 19 | cd ../../$buildFolder 20 | 21 | # open xcode 22 | open ios/project/$appName.xcworkspace 23 | 24 | # sign android 25 | cd android/project/app/build/outputs/bundle/release 26 | rm -rf ~/app-release.aab 27 | echo 'Executing: jarsigner' 28 | jarsigner -verbose -sigalg SHA256withRSA -digestalg SHA-256 -keystore $pathToAndroidKeyStore --storepass $androidPassword app-release.aab $keystoreAlias 29 | cp app-release.aab ~/app-release.aab 30 | -------------------------------------------------------------------------------- /cordova/private/native-app/production/publish-android.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | authFileAndroid=~/android_auth.json 4 | 5 | fastlane supply --aab ~/app-release.aab --json_key $authFileAndroid --package_name $APP_ID 6 | -------------------------------------------------------------------------------- /cordova/private/native-app/production/publish-ios.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # fill the data here 4 | fastlaneApplePassword=yourpass 5 | appleUsername=yourusername 6 | applePassword=yourpassword 7 | 8 | # testflight:true 9 | FASTLANE_APPLE_APPLICATION_SPECIFIC_PASSWORD=$fastlaneApplePassword FL_UNLOCK_KEYCHAIN_SET_DEFAULT=true bundle exec fastlane --verbose ios appstore username:$appleUsername password:$applePassword 10 | -------------------------------------------------------------------------------- /cordova/public/sw.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable */ 2 | const HTMLToCache = '/'; 3 | const version = 'MSW V0.3'; 4 | 5 | self.addEventListener('install', event => { 6 | event.waitUntil( 7 | caches.open(version).then(cache => { 8 | cache.add(HTMLToCache).then(self.skipWaiting()); 9 | }) 10 | ); 11 | }); 12 | 13 | self.addEventListener('activate', event => { 14 | event.waitUntil( 15 | caches 16 | .keys() 17 | .then(cacheNames => 18 | Promise.all( 19 | cacheNames.map(cacheName => { 20 | if (version !== cacheName) return caches.delete(cacheName); 21 | }) 22 | ) 23 | ) 24 | .then(self.clients.claim()) 25 | ); 26 | }); 27 | 28 | self.addEventListener('fetch', event => { 29 | const requestToFetch = event.request.clone(); 30 | event.respondWith( 31 | caches.match(event.request.clone()).then(cached => { 32 | // We don't return cached HTML (except if fetch failed) 33 | if (cached) { 34 | const resourceType = cached.headers.get('content-type'); 35 | // We only return non css/js/html cached response e.g images 36 | if (!hasHash(event.request.url) && !/text\/html/.test(resourceType)) { 37 | return cached; 38 | } 39 | 40 | // If the CSS/JS didn't change since it's been cached, return the cached version 41 | if ( 42 | hasHash(event.request.url) && 43 | hasSameHash(event.request.url, cached.url) 44 | ) { 45 | return cached; 46 | } 47 | } 48 | return fetch(requestToFetch) 49 | .then(response => { 50 | const clonedResponse = response.clone(); 51 | const contentType = clonedResponse.headers.get('content-type'); 52 | 53 | if ( 54 | !clonedResponse || 55 | clonedResponse.status !== 200 || 56 | clonedResponse.type !== 'basic' || 57 | /\/sockjs\//.test(event.request.url) 58 | ) { 59 | return response; 60 | } 61 | 62 | if (/html/.test(contentType)) { 63 | caches 64 | .open(version) 65 | .then(cache => cache.put(HTMLToCache, clonedResponse)); 66 | } else { 67 | // Delete old version of a file 68 | if (hasHash(event.request.url)) { 69 | caches.open(version).then(cache => 70 | cache.keys().then(keys => 71 | keys.forEach(asset => { 72 | if ( 73 | new RegExp(removeHash(event.request.url)).test( 74 | removeHash(asset.url) 75 | ) 76 | ) { 77 | cache.delete(asset); 78 | } 79 | }) 80 | ) 81 | ); 82 | } 83 | 84 | caches 85 | .open(version) 86 | .then(cache => cache.put(event.request, clonedResponse)); 87 | } 88 | return response; 89 | }) 90 | .catch(() => { 91 | if (hasHash(event.request.url)) 92 | return caches.match(event.request.url); 93 | else if (!/\/sockjs\//.test(event.request.url)) 94 | // If the request URL hasn't been served from cache and isn't sockjs we suppose it's HTML 95 | return caches.match(HTMLToCache); 96 | // Only for sockjs 97 | return new Response('No connection to the server', { 98 | status: 503, 99 | statusText: 'No connection to the server', 100 | headers: new Headers({ 'Content-Type': 'text/plain' }), 101 | }); 102 | }); 103 | }) 104 | ); 105 | }); 106 | 107 | function removeHash(element) { 108 | if (typeof element === 'string') return element.split('?hash=')[0]; 109 | } 110 | 111 | function hasHash(element) { 112 | if (typeof element === 'string') return /\?hash=.*/.test(element); 113 | } 114 | 115 | function hasSameHash(firstUrl, secondUrl) { 116 | if (typeof firstUrl === 'string' && typeof secondUrl === 'string') { 117 | return /\?hash=(.*)/.exec(firstUrl)[1] === /\?hash=(.*)/.exec(secondUrl)[1]; 118 | } 119 | } 120 | 121 | // Service worker created by Ilan Schemoul alias NitroBAY as a specific Service Worker for Meteor 122 | // Please see https://github.com/NitroBAY/meteor-service-worker for the official project source 123 | -------------------------------------------------------------------------------- /cordova/server/main.js: -------------------------------------------------------------------------------- 1 | import '../imports/infra/meta-tags'; 2 | import '../imports/infra/rest'; 3 | import '../imports/infra/addPlayerId'; 4 | import '../imports/infra/database-seed'; -------------------------------------------------------------------------------- /nft-marketplace/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | 3 | node_modules 4 | .env 5 | coverage 6 | coverage.json 7 | typechain 8 | 9 | #Hardhat files 10 | cache 11 | artifacts 12 | -------------------------------------------------------------------------------- /nft-marketplace/.meteor/.finished-upgraders: -------------------------------------------------------------------------------- 1 | # This file contains information which helps Meteor properly upgrade your 2 | # app when you run 'meteor update'. You should check it into version control 3 | # with your project. 4 | 5 | notices-for-0.9.0 6 | notices-for-0.9.1 7 | 0.9.4-platform-file 8 | notices-for-facebook-graph-api-2 9 | 1.2.0-standard-minifiers-package 10 | 1.2.0-meteor-platform-split 11 | 1.2.0-cordova-changes 12 | 1.2.0-breaking-changes 13 | 1.3.0-split-minifiers-package 14 | 1.4.0-remove-old-dev-bundle-link 15 | 1.4.1-add-shell-server-package 16 | 1.4.3-split-account-service-packages 17 | 1.5-add-dynamic-import-package 18 | 1.7-split-underscore-from-meteor-base 19 | 1.8.3-split-jquery-from-blaze 20 | -------------------------------------------------------------------------------- /nft-marketplace/.meteor/.gitignore: -------------------------------------------------------------------------------- 1 | local 2 | -------------------------------------------------------------------------------- /nft-marketplace/.meteor/.id: -------------------------------------------------------------------------------- 1 | # This file contains a token that is unique to your project. 2 | # Check it into your repository along with the rest of this directory. 3 | # It can be used for purposes such as: 4 | # - ensuring you don't accidentally deploy one app on top of another 5 | # - providing package authors with aggregated statistics 6 | 7 | xv5ft06lky7c.xir3icty4q9c 8 | -------------------------------------------------------------------------------- /nft-marketplace/.meteor/packages: -------------------------------------------------------------------------------- 1 | # Meteor packages used by this project, one per line. 2 | # Check this file (and the other files in this directory) into your repository. 3 | # 4 | # 'meteor add' and 'meteor remove' will edit this file for you, 5 | # but you can also edit it by hand. 6 | 7 | meteor-base@1.5.1 # Packages every Meteor app needs to have 8 | mobile-experience@1.1.0 # Packages for a great mobile UX 9 | mongo@1.15.0 # The database Meteor supports right now 10 | reactive-var@1.0.11 # Reactive variable for tracker 11 | 12 | standard-minifier-css@1.8.1 # CSS minifier run for production mode 13 | standard-minifier-js@2.8.0 # JS minifier run for production mode 14 | es5-shim@4.8.0 # ECMAScript 5 compatibility for older browsers 15 | ecmascript@0.16.2 # Enable ECMAScript2015+ syntax in app code 16 | typescript@4.5.4 # Enable TypeScript syntax in .ts and .tsx modules 17 | shell-server@0.5.0 # Server-side component of the `meteor shell` command 18 | hot-module-replacement@0.5.1 # Update client in development without reloading the page 19 | 20 | static-html@1.3.2 # Define static page content in .html files 21 | react-meteor-data # React higher-order component for reactively tracking Meteor data 22 | -------------------------------------------------------------------------------- /nft-marketplace/.meteor/platforms: -------------------------------------------------------------------------------- 1 | server 2 | browser 3 | -------------------------------------------------------------------------------- /nft-marketplace/.meteor/release: -------------------------------------------------------------------------------- 1 | METEOR@2.7.2 2 | -------------------------------------------------------------------------------- /nft-marketplace/.meteor/versions: -------------------------------------------------------------------------------- 1 | allow-deny@1.1.1 2 | autoupdate@1.8.0 3 | babel-compiler@7.9.0 4 | babel-runtime@1.5.0 5 | base64@1.0.12 6 | binary-heap@1.0.11 7 | blaze-tools@1.1.3 8 | boilerplate-generator@1.7.1 9 | caching-compiler@1.2.2 10 | caching-html-compiler@1.2.1 11 | callback-hook@1.4.0 12 | check@1.3.1 13 | ddp@1.4.0 14 | ddp-client@2.5.0 15 | ddp-common@1.4.0 16 | ddp-server@2.5.0 17 | diff-sequence@1.1.1 18 | dynamic-import@0.7.2 19 | ecmascript@0.16.2 20 | ecmascript-runtime@0.8.0 21 | ecmascript-runtime-client@0.12.1 22 | ecmascript-runtime-server@0.11.0 23 | ejson@1.1.2 24 | es5-shim@4.8.0 25 | fetch@0.1.1 26 | geojson-utils@1.0.10 27 | hot-code-push@1.0.4 28 | hot-module-replacement@0.5.1 29 | html-tools@1.1.3 30 | htmljs@1.1.1 31 | id-map@1.1.1 32 | inter-process-messaging@0.1.1 33 | launch-screen@1.3.0 34 | logging@1.3.1 35 | meteor@1.10.0 36 | meteor-base@1.5.1 37 | minifier-css@1.6.0 38 | minifier-js@2.7.4 39 | minimongo@1.8.0 40 | mobile-experience@1.1.0 41 | mobile-status-bar@1.1.0 42 | modern-browsers@0.1.8 43 | modules@0.18.0 44 | modules-runtime@0.13.0 45 | modules-runtime-hot@0.14.0 46 | mongo@1.15.0 47 | mongo-decimal@0.1.3 48 | mongo-dev-server@1.1.0 49 | mongo-id@1.0.8 50 | npm-mongo@4.3.1 51 | ordered-dict@1.1.0 52 | promise@0.12.0 53 | random@1.2.0 54 | react-fast-refresh@0.2.3 55 | react-meteor-data@2.4.0 56 | reactive-var@1.0.11 57 | reload@1.3.1 58 | retry@1.1.0 59 | routepolicy@1.1.1 60 | shell-server@0.5.0 61 | socket-stream-client@0.5.0 62 | spacebars-compiler@1.3.1 63 | standard-minifier-css@1.8.1 64 | standard-minifier-js@2.8.0 65 | static-html@1.3.2 66 | templating-tools@1.2.2 67 | tracker@1.2.0 68 | typescript@4.5.4 69 | underscore@1.0.10 70 | webapp@1.13.1 71 | webapp-hashing@1.1.0 72 | -------------------------------------------------------------------------------- /nft-marketplace/README.md: -------------------------------------------------------------------------------- 1 | # NFT Marketplace 2 | 3 | This is from Nader's tutorial, but with Meteor. You can check the original tutorial here: https://dev.to/edge-and-node/building-scalable-full-stack-apps-on-ethereum-with-polygon-2cfb 4 | 5 | To run it locally, you will need to open two terminals. 6 | 7 | But first, you need to clone the project and run a `meteor npm install` to install all the dependencies. 8 | 9 | In terminal #1, you will run the following command: 10 | 11 | `npx hardhat node` 12 | 13 | The command above will give you 20 accounts with 10000 ETH each, that you can add to your Metamask and test the application locally. 14 | 15 | In terminal #2, you will then run the following commands: 16 | 17 | ``` 18 | npx hardhat run scripts/deploy.js --network localhost 19 | meteor 20 | ``` 21 | 22 | The command above will deploy the contract and run the Meteor application. 23 | 24 | ## Adding a wallet to MetaMask 25 | 26 | The `npx hardhat node` command will give you 20 accounts for you to test locally. To add one of these accounts to your Metamask, you will need to copy one of the private keys hardhat gave you. 27 | 28 | Then you will make sure you are in the localhost network, like in the screenshot below: 29 | 30 | ![metamask network](https://user-images.githubusercontent.com/41165990/170504915-dfe5e75b-f4d2-423f-90a7-d856af49a6a2.png) 31 | 32 | After that, you will click in the top right icon to open a menu, where you will click on Import Account, like in the image below: 33 | 34 | ![metamask wallet 1](https://user-images.githubusercontent.com/41165990/170505136-75fbd41b-af46-4d54-8d0a-bd15eacd2765.png) 35 | 36 | Then you will paste your private key and click Import. 37 | 38 | ## Possible issues when testing locally 39 | 40 | If you're getting errors like "Nonce too high" when trying to add an NFT or doing any kind of transaction in the app, you can do the following steps: 41 | 42 | 1. Access the top right menu like you did in the last section 43 | 2. Go to Settings and then Advanced 44 | 3. Click on Reset Accounts 45 | 46 | ## How to test our deployed version 47 | 48 | You can check our deployed version using this link: https://meteor-nft-marketplace.meteorapp.com 49 | 50 | To use this version you will need to add the Mumbai Testnet to your Metamask. You can do it by following the screenshots from Nader's tutorial. You will go to Metamask settings: 51 | 52 | ![1](https://user-images.githubusercontent.com/41165990/171486860-3f06f3ea-1915-48c2-9cb8-7b58b66c4127.png) 53 | 54 | Then Networks and then Add Network. 55 | 56 | ![2](https://user-images.githubusercontent.com/41165990/171486872-855eca67-a453-4cc3-945e-16a8774c1edb.png) 57 | 58 | After that, you will add the following info from Polygon [docs](https://docs.polygon.technology/docs/develop/network-details/network/): 59 | 60 | Network Name: Mumbai TestNet 61 | 62 | New RPC URL: https://rpc-mumbai.maticvigil.com 63 | 64 | Chain ID: 80001 65 | 66 | Currency Symbol: Matic 67 | 68 | Click save and then you should be able to switch to this new network and use it. You will need some testnet Matic tokens, but you can get them [here](https://faucet.matic.network/) 69 | 70 | ## Screenshots of the application 71 | 72 | ![Screenshot 2022-05-25 at 11-23-41 Dummy Page](https://user-images.githubusercontent.com/41165990/170509257-e4adabaa-c0d4-4d4d-9fb5-4a4e851f365e.png) 73 | 74 | ![Screenshot 2022-06-28 at 23-51-54 Dummy Page](https://user-images.githubusercontent.com/41165990/176348036-67f4d3fd-8eba-4cde-bacb-c14abecef9ed.png) 75 | 76 | ![Screenshot 2022-06-28 at 23-52-15 Dummy Page](https://user-images.githubusercontent.com/41165990/176348065-05ef0658-3366-4eca-bbf8-db729b057b19.png) 77 | 78 | ![Screenshot 2022-06-28 at 23-53-22 Dummy Page](https://user-images.githubusercontent.com/41165990/176348085-3896af2b-2e36-41d1-9df5-e1e7de7c7d98.png) 79 | 80 | ![Screenshot 2022-06-28 at 23-54-11 Dummy Page](https://user-images.githubusercontent.com/41165990/176348099-baadb92b-9a8b-4db0-ae47-ccce00e02625.png) 81 | -------------------------------------------------------------------------------- /nft-marketplace/app/ui/App.jsx: -------------------------------------------------------------------------------- 1 | import React, { useEffect, useState} from 'react'; 2 | import { Outlet } from 'react-router-dom'; 3 | import { NavBar } from "./common/NavBar"; 4 | import { CheckAccount } from "./common/CheckAccount"; 5 | import { Footer } from "./common/Footer"; 6 | 7 | export const App = () => { 8 | const [connection, setConnection] = useState(false); 9 | 10 | if (window.ethereum !== undefined) { 11 | useEffect(() => { 12 | window.ethereum.on("accountsChanged", accounts => { 13 | if (accounts.length > 0) setConnection(true); 14 | else setConnection(false); 15 | }); 16 | 17 | CheckAccount().then((accounts) => { 18 | if (accounts.length > 0) setConnection(true); 19 | else setConnection(false); 20 | }) 21 | }, []); 22 | 23 | return ( 24 |
25 | 26 |
27 | 28 |
29 |
30 |
31 | ); 32 | } else { 33 | return ( 34 |
35 |

You need Metamask installed to use this store.

36 | Metamask logo 37 |
38 | ); 39 | } 40 | }; 41 | -------------------------------------------------------------------------------- /nft-marketplace/app/ui/ConnectPage.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { Button } from "./components/Button"; 3 | import { ConnectAccount } from "./common/ConnectAccount"; 4 | import { useNavigate, useOutletContext } from "react-router-dom"; 5 | import { RoutePaths } from "./common/RoutePaths"; 6 | 7 | export default function ConnectPage() { 8 | const navigate = useNavigate(); 9 | const [connection, setConnection] = useOutletContext(); 10 | 11 | return ( 12 |
13 |

Connect with your MetaMask wallet

14 |

You need an Ethereum wallet to use this store.

15 | Metamask logo 16 |
29 | ) 30 | } 31 | -------------------------------------------------------------------------------- /nft-marketplace/app/ui/common/CategoryOptions.jsx: -------------------------------------------------------------------------------- 1 | export const CategoryOptions = [ 2 | { label: "All", value: "all" }, 3 | { label: "Owned", value: "owned" }, 4 | { label: "For Sale", value: "for-sale" }, 5 | ]; 6 | -------------------------------------------------------------------------------- /nft-marketplace/app/ui/common/CheckAccount.jsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { ethers } from "ethers"; 3 | 4 | export const CheckAccount = () => { 5 | const provider = new ethers.providers.Web3Provider( 6 | window.ethereum 7 | ); 8 | 9 | return provider.listAccounts(); 10 | } 11 | 12 | -------------------------------------------------------------------------------- /nft-marketplace/app/ui/common/ConnectAccount.jsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import Web3Modal from "web3modal"; 3 | 4 | export const ConnectAccount = async () => { 5 | const web3Modal = new Web3Modal({ 6 | network: "mainnet", 7 | cacheProvider: true, 8 | }); 9 | 10 | return await web3Modal.connect(); 11 | } 12 | 13 | -------------------------------------------------------------------------------- /nft-marketplace/app/ui/common/CurrentAccount.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { ethers } from "ethers"; 3 | 4 | export const CurrentAccount = () => { 5 | const provider = new ethers.providers.Web3Provider(window.ethereum); 6 | 7 | return provider.provider.selectedAddress; 8 | } 9 | -------------------------------------------------------------------------------- /nft-marketplace/app/ui/common/Footer.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | export const Footer = () => { 4 | const currentYear = new Date().getFullYear(); 5 | 6 | return ( 7 |
8 |
9 |

{`© 2018 - ${currentYear} Ozone Networks, Inc`}

10 | 11 |
12 | Privacy Policy 13 | | 14 | Terms of Service 15 |
16 |
17 |
18 | ) 19 | } 20 | -------------------------------------------------------------------------------- /nft-marketplace/app/ui/common/NavBar.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { Link } from "react-router-dom"; 3 | import { RoutePaths } from "./RoutePaths"; 4 | import { Disclosure } from '@headlessui/react'; 5 | import { MenuIcon, XIcon } from '@heroicons/react/outline'; 6 | import { CurrentAccount } from './CurrentAccount'; 7 | 8 | const navigation = [ 9 | { name: 'Explore', href: RoutePaths.ROOT }, 10 | { name: 'Create', href: RoutePaths.SELL_NFT }, 11 | ]; 12 | 13 | export const NavBar = ({ connection }) => { 14 | const currentAccount = CurrentAccount(); 15 | 16 | return ( 17 | 18 | {({ open }) => ( 19 | <> 20 |
21 |
22 |
23 |
24 | Meteor NFT 25 |
26 |
27 |
28 | {navigation.map((item) => ( 29 | 30 | {item.name} 31 | 32 | ))} 33 | 34 |
35 | 36 | {connection ? ( 37 | 38 | Profile avatar 39 | Account 40 | 41 | ) : ( 42 | 43 | Connect 44 | 45 | )} 46 |
47 |
48 |
49 | 50 |
51 | {/* Mobile menu button */} 52 | 53 | Open main menu 54 | {open ? ( 55 | 60 |
61 |
62 |
63 | 64 | {/* Mobile menu items */} 65 | 66 |
67 | {navigation.map((item) => ( 68 | 74 | {item.name} 75 | 76 | ))} 77 | 78 | {connection ? ( 79 | 84 | Profile avatar 85 | Account 86 | 87 | ) : ( 88 | 93 | Connect 94 | 95 | )} 96 |
97 |
98 | 99 | )} 100 |
101 | ) 102 | } 103 | -------------------------------------------------------------------------------- /nft-marketplace/app/ui/common/RoutePaths.jsx: -------------------------------------------------------------------------------- 1 | export const RoutePaths = { 2 | ROOT: '/', 3 | SELL_NFT: '/sell-nft', 4 | CONNECT: '/connect', 5 | DETAILS: '/details', 6 | ACCOUNT: '/account', 7 | }; 8 | -------------------------------------------------------------------------------- /nft-marketplace/app/ui/common/Routes.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { BrowserRouter, Routes as ReactRoutes, Route } from 'react-router-dom'; 3 | import { RoutePaths } from './RoutePaths'; 4 | import { App } from "../App"; 5 | 6 | const HomePage = React.lazy(() => import('../HomePage')); 7 | const SellNftPage = React.lazy(() => import('../SellNftPage')); 8 | const ConnectPage = React.lazy(() => import('../ConnectPage')); 9 | const DetailsPage = React.lazy(() => import('../DetailsPage')); 10 | const AccountPage = React.lazy(() => import('../AccountPage')); 11 | 12 | export const Routes = () => ( 13 | 14 | 15 | }> 16 | } /> 17 | } /> 18 | } /> 19 | } /> 20 | } /> 21 | 22 | 23 | 24 | ); 25 | -------------------------------------------------------------------------------- /nft-marketplace/app/ui/common/SortOptions.jsx: -------------------------------------------------------------------------------- 1 | export const SortOptions = [ 2 | { label: "Oldest Added", value: "oldest" }, 3 | { label: "Newest Added", value: "newest" }, 4 | { label: "Price: Low to High", value: "price-low" }, 5 | { label: "Price: High to Low", value: "price-high" }, 6 | ]; 7 | -------------------------------------------------------------------------------- /nft-marketplace/app/ui/components/Button.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | export const Button = ({ 4 | children, 5 | className = '', 6 | text = null, 7 | type = 'primary', 8 | onClick = () => ({}), 9 | startIcon = null, 10 | endIcon = null, 11 | disabled = false, 12 | }) => { 13 | const btnTypes = { 14 | primary: 'py-3.5 px-4 bg-dodger text-white border-none', // Full background 15 | secondary: `py-3.5 px-4 bg-transparent text-dodger border-2 border-dodger ${ 16 | !disabled 17 | ? 'hover:bg-dodger hover:text-white hover:border-transparent' 18 | : '' 19 | }`, // Outline 20 | tertiary: 'py-3.5 px-4 bg-transparent text-dodger border-none', // Transparent 21 | danger: `py-3.5 px-4 bg-transparent text-vermilion border-2 border-vermilion ${ 22 | !disabled 23 | ? 'hover:bg-vermilion hover:text-white hover:border-transparent' 24 | : '' 25 | }`, // Red outline 26 | }; 27 | 28 | return ( 29 | 40 | ); 41 | }; 42 | -------------------------------------------------------------------------------- /nft-marketplace/app/ui/components/Card.jsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { useNavigate } from "react-router-dom"; 3 | import { RoutePaths } from "../common/RoutePaths"; 4 | 5 | export const Card = ({ 6 | children, 7 | className = '', 8 | itemImg = null, 9 | itemName = null, 10 | itemPrice = null, 11 | itemId = null, 12 | badge = '', 13 | }) => { 14 | const navigate = useNavigate(); 15 | const badgeBackgroundColor = (badge === "owned") ? "bg-burst" : "bg-dodger"; 16 | 17 | return ( 18 |
navigate(`${RoutePaths.DETAILS}/${itemId}`)}> 19 |
20 | {badge && ( 21 |

{badge}

22 | )} 23 | 24 |
25 |
26 |
27 |

{itemName}

28 |

{itemPrice} ETH

29 |
30 |

#{itemId}

31 |
32 |
33 | ); 34 | } 35 | -------------------------------------------------------------------------------- /nft-marketplace/app/ui/components/Fields/InputField.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { useField } from './useField'; 3 | 4 | export const InputField = ({ 5 | classNameContainer, 6 | textArea, 7 | inputClasses, 8 | label, 9 | disabled, 10 | name = '', 11 | placeholder = '', 12 | onChange, 13 | value, 14 | ...props 15 | }) => { 16 | const { handleChange, active } = useField({ 17 | onChange, 18 | value, 19 | label, 20 | }); 21 | return ( 22 |
23 |
24 | {textArea ? ( 25 |