├── .deploy ├── docker-compose.yml └── nginx-proxy-compose.yml ├── .github └── workflows │ ├── README.md │ ├── build.yml │ └── release.yml ├── .gitignore ├── .vscode ├── launch.json └── tasks.json ├── NuGet.Config ├── README.md ├── TechStacks.ServiceInterface ├── Admin │ ├── AdminServices.cs │ ├── DummyTypesService.cs │ ├── EmailServices.cs │ ├── NotificationServices.Utils.cs │ └── NotificationServices.cs ├── AppFeatureFlags.cs ├── Auth │ └── DiscourseAuthProvider.cs ├── ClientRoutesService.cs ├── CustomAuthUserSession.cs ├── Data │ └── ApplicationDbContext.cs ├── DataModel │ ├── EmailTemplate.cs │ ├── Notification.cs │ ├── SubscribePost.cs │ └── SubscriptionPost.cs ├── EmailServices.cs ├── HelloService.cs ├── Html │ └── AppScriptMethods.cs ├── IMarkdownProvider.cs ├── ITwitterUpdates.cs ├── ImgurExtensions.cs ├── Messaging │ └── BackgroundAdminServices.cs ├── Notifications │ ├── EmailProvider.cs │ └── TwitterUpdates.cs ├── OrganizationServices.cs ├── PostPublicServices.cs ├── PostServices.cs ├── PostServicesBase.cs ├── PostUserServices.cs ├── PreRenderService.cs ├── SessionInfoServices.cs ├── SubscriptionServices.cs ├── TechExtensions.cs ├── TechStackQueries.cs ├── TechStacks.ServiceInterface.csproj ├── TechnologyServices.cs ├── TechnologyServicesAdmin.cs ├── TechnologyStackServices.cs ├── TechnologyStackServicesAdmin.cs ├── UserFavoriteServices.cs ├── UserStackServices.cs └── Validations │ ├── OrganizationValidators.cs │ ├── PostValidators.cs │ ├── TechStackValidators.cs │ ├── TechValidators.cs │ └── ValidatorUtils.cs ├── TechStacks.ServiceModel ├── Admin.cs ├── App.cs ├── Hello.cs ├── Organizations.cs ├── Posts.cs ├── Tags.cs ├── TechStacks.ServiceModel.csproj ├── Technologies.cs ├── TechnologyStacks.cs ├── Types │ ├── Organizations.cs │ ├── PageStats.cs │ ├── Posts.cs │ ├── TechnologyStack.cs │ └── UserActivity.cs └── Users.cs ├── TechStacks.Tests ├── AdminTasks.cs ├── DbTasksBase.cs ├── DummyData.cs ├── IntegrationTests.cs ├── MigrationTasks.cs ├── Seeds.cs ├── TechStacks.Tests.csproj ├── TestHosts.cs ├── UnitTests.cs ├── UpdateAdminTasks.cs ├── appsettings.txt └── servicestack-forum.json ├── TechStacks.sln ├── TechStacks.sln.sources ├── TechStacks ├── .editorconfig ├── .eslintignore ├── .eslintrc.js ├── App_Data │ ├── App.json │ └── key-7f431195-db42-4e64-b957-08ab5ed23024.xml ├── Areas │ └── Identity │ │ └── Pages │ │ ├── Account │ │ ├── AccessDenied.cshtml │ │ ├── AccessDenied.cshtml.cs │ │ ├── ConfirmEmail.cshtml │ │ ├── ConfirmEmail.cshtml.cs │ │ ├── ConfirmEmailChange.cshtml │ │ ├── ConfirmEmailChange.cshtml.cs │ │ ├── ExternalLogin.cshtml │ │ ├── ExternalLogin.cshtml.cs │ │ ├── ForgotPassword.cshtml │ │ ├── ForgotPassword.cshtml.cs │ │ ├── ForgotPasswordConfirmation.cshtml │ │ ├── ForgotPasswordConfirmation.cshtml.cs │ │ ├── Lockout.cshtml │ │ ├── Lockout.cshtml.cs │ │ ├── Login.cshtml │ │ ├── Login.cshtml.cs │ │ ├── LoginWith2fa.cshtml │ │ ├── LoginWith2fa.cshtml.cs │ │ ├── LoginWithRecoveryCode.cshtml │ │ ├── LoginWithRecoveryCode.cshtml.cs │ │ ├── Logout.cshtml │ │ ├── Logout.cshtml.cs │ │ ├── Manage │ │ │ ├── ChangePassword.cshtml │ │ │ ├── ChangePassword.cshtml.cs │ │ │ ├── DeletePersonalData.cshtml │ │ │ ├── DeletePersonalData.cshtml.cs │ │ │ ├── Disable2fa.cshtml │ │ │ ├── Disable2fa.cshtml.cs │ │ │ ├── DownloadPersonalData.cshtml │ │ │ ├── DownloadPersonalData.cshtml.cs │ │ │ ├── Email.cshtml │ │ │ ├── Email.cshtml.cs │ │ │ ├── EnableAuthenticator.cshtml │ │ │ ├── EnableAuthenticator.cshtml.cs │ │ │ ├── ExternalLogins.cshtml │ │ │ ├── ExternalLogins.cshtml.cs │ │ │ ├── GenerateRecoveryCodes.cshtml │ │ │ ├── GenerateRecoveryCodes.cshtml.cs │ │ │ ├── Index.cshtml │ │ │ ├── Index.cshtml.cs │ │ │ ├── ManageNavPages.cs │ │ │ ├── PersonalData.cshtml │ │ │ ├── PersonalData.cshtml.cs │ │ │ ├── ResetAuthenticator.cshtml │ │ │ ├── ResetAuthenticator.cshtml.cs │ │ │ ├── SetPassword.cshtml │ │ │ ├── SetPassword.cshtml.cs │ │ │ ├── ShowRecoveryCodes.cshtml │ │ │ ├── ShowRecoveryCodes.cshtml.cs │ │ │ ├── TwoFactorAuthentication.cshtml │ │ │ ├── TwoFactorAuthentication.cshtml.cs │ │ │ ├── _Layout.cshtml │ │ │ ├── _ManageNav.cshtml │ │ │ ├── _StatusMessage.cshtml │ │ │ ├── _ViewImports.cshtml │ │ │ └── _ViewStart.cshtml │ │ ├── Register.cshtml │ │ ├── Register.cshtml.cs │ │ ├── RegisterConfirmation.cshtml │ │ ├── RegisterConfirmation.cshtml.cs │ │ ├── ResendEmailConfirmation.cshtml │ │ ├── ResendEmailConfirmation.cshtml.cs │ │ ├── ResetPassword.cshtml │ │ ├── ResetPassword.cshtml.cs │ │ ├── ResetPasswordConfirmation.cshtml │ │ ├── ResetPasswordConfirmation.cshtml.cs │ │ ├── _StatusMessage.cshtml │ │ └── _ViewImports.cshtml │ │ ├── _ValidationScriptsPartial.cshtml │ │ ├── _ViewImports.cshtml │ │ └── _ViewStart.cshtml ├── Configure.AppHost.cs ├── Configure.Auth.cs ├── Configure.Cors.cs ├── Configure.Db.Migrations.cs ├── Configure.Markdown.cs ├── Configure.Mq.cs ├── Configure.RequestLogs.cs ├── Css.cs ├── IdentityComponentsEndpointRouteBuilderExtensions.cs ├── Migrations │ ├── 20240119030601_CreateIdentitySchema.Designer.cs │ ├── 20240119030601_CreateIdentitySchema.cs │ ├── ApplicationDbContextModelSnapshot.cs │ └── Migration1000.cs ├── Pages │ ├── Shared │ │ ├── AlertError.cshtml │ │ ├── AlertInfo.cshtml │ │ ├── AlertWarning.cshtml │ │ ├── Footer.cshtml │ │ ├── Forbidden.cshtml │ │ ├── Header.cshtml │ │ └── _Layout.cshtml │ ├── _ViewImports.cshtml │ └── _ViewStart.cshtml ├── Program.cs ├── Properties │ └── launchSettings.json ├── README.md ├── TechStacks.csproj ├── appsettings.json ├── deploy.bat ├── deploy.sh ├── emails │ ├── _layout.html │ ├── comment-report.html │ ├── post-new.html │ └── post-report.html ├── npm-shrinkwrap.json ├── nuxt.config.js ├── package.json ├── scripts │ ├── package-lock.json │ ├── package.json │ ├── prerender.js │ └── server │ │ ├── install.txt │ │ ├── nginx │ │ ├── techstacks.io │ │ └── techstacks.netcore.io │ │ └── supervisord │ │ ├── web-prerender.conf │ │ └── web-techstacks.conf ├── src │ ├── assets │ │ ├── README.md │ │ └── css │ │ │ ├── gfm.css │ │ │ ├── styles.css │ │ │ └── typography.css │ ├── components │ │ ├── CategoryEdit.vue │ │ ├── CommentEdit.vue │ │ ├── DebugInfo.vue │ │ ├── FileInput.vue │ │ ├── LabelEdit.vue │ │ ├── MemberEdit.vue │ │ ├── MembersInfo.vue │ │ ├── NewsPosts.vue │ │ ├── OrganizationAdd.vue │ │ ├── OrganizationEdit.vue │ │ ├── OrganizationInfo.vue │ │ ├── PostAlerts.vue │ │ ├── PostComment.vue │ │ ├── PostComments.vue │ │ ├── PostEdit.vue │ │ ├── PostInfo.vue │ │ ├── PostsList.vue │ │ ├── README.md │ │ ├── ReportDialog.vue │ │ ├── Shortcuts.vue │ │ ├── TechStackEdit.vue │ │ ├── TechnologyComments.vue │ │ ├── TechnologyEdit.vue │ │ └── TechnologyPost.vue │ ├── layouts │ │ ├── README.md │ │ └── default.vue │ ├── middleware │ │ ├── README.md │ │ └── routes.js │ ├── pages │ │ ├── README.md │ │ ├── _slug │ │ │ ├── _category.vue │ │ │ └── index.vue │ │ ├── comments │ │ │ └── _postid │ │ │ │ └── _id.vue │ │ ├── favorites │ │ │ └── index.vue │ │ ├── index.vue │ │ ├── login │ │ │ └── _provider.vue │ │ ├── news │ │ │ └── index.vue │ │ ├── organizations │ │ │ ├── _slug │ │ │ │ └── index.vue │ │ │ └── index.vue │ │ ├── posts │ │ │ └── _id │ │ │ │ └── _postslug.vue │ │ ├── stacks │ │ │ ├── _slug │ │ │ │ ├── edit.vue │ │ │ │ └── index.vue │ │ │ ├── index.vue │ │ │ └── new.vue │ │ ├── tech │ │ │ ├── _slug │ │ │ │ ├── edit.vue │ │ │ │ └── index.vue │ │ │ ├── index.vue │ │ │ └── new.vue │ │ ├── top │ │ │ └── index.vue │ │ └── users │ │ │ └── _id.vue │ ├── plugins │ │ ├── README.md │ │ ├── ga.js │ │ ├── nuxt-client-init.js │ │ └── vuetify.js │ ├── shared │ │ ├── dtos.js │ │ ├── dtos.ts │ │ ├── gateway.js │ │ ├── post.js │ │ ├── routes.js │ │ └── utils.js │ ├── static │ │ ├── Identity │ │ │ └── lib │ │ │ │ └── jquery-validation-unobtrusive │ │ │ │ └── jquery.validate.unobtrusive.js │ │ ├── README.md │ │ ├── _redirects │ │ ├── css │ │ │ ├── app.css │ │ │ └── typography.css │ │ ├── favicon.ico │ │ ├── googled0ec8ee6ceb21aeb.html │ │ ├── images │ │ │ └── emoji │ │ │ │ └── emoji_one │ │ │ │ ├── blush.png │ │ │ │ ├── confounded.png │ │ │ │ ├── confused.png │ │ │ │ ├── crazy_face.png │ │ │ │ ├── cry.png │ │ │ │ ├── disappointed.png │ │ │ │ ├── disappointed_relieved.png │ │ │ │ ├── dizzy_face.png │ │ │ │ ├── drooling_face.png │ │ │ │ ├── exploding_head.png │ │ │ │ ├── expressionless.png │ │ │ │ ├── eyes.png │ │ │ │ ├── face_with_head_bandage.png │ │ │ │ ├── face_with_monocle.png │ │ │ │ ├── face_with_raised_eyebrow.png │ │ │ │ ├── face_with_rolling_eyes.png │ │ │ │ ├── face_with_symbols_over_mouth.png │ │ │ │ ├── face_with_thermometer.png │ │ │ │ ├── fearful.png │ │ │ │ ├── flushed.png │ │ │ │ ├── frowning.png │ │ │ │ ├── frowning2.png │ │ │ │ ├── frowning_face.png │ │ │ │ ├── gift_heart.png │ │ │ │ ├── grimacing.png │ │ │ │ ├── grin.png │ │ │ │ ├── grinning.png │ │ │ │ ├── hand.png │ │ │ │ ├── hand_splayed.png │ │ │ │ ├── heart_eyes.png │ │ │ │ ├── hearts.png │ │ │ │ ├── metal.png │ │ │ │ ├── muscle.png │ │ │ │ ├── nerd.png │ │ │ │ ├── neutral_face.png │ │ │ │ ├── ok_hand.png │ │ │ │ ├── open_mouth.png │ │ │ │ ├── pensive.png │ │ │ │ ├── persevere.png │ │ │ │ ├── point_down.png │ │ │ │ ├── point_left.png │ │ │ │ ├── point_right.png │ │ │ │ ├── point_up.png │ │ │ │ ├── point_up_2.png │ │ │ │ ├── relaxed.png │ │ │ │ ├── relieved.png │ │ │ │ ├── rocket.png │ │ │ │ ├── rofl.png │ │ │ │ ├── roll_eyes.png │ │ │ │ ├── satisfied.png │ │ │ │ ├── scream.png │ │ │ │ ├── shushing_face.png │ │ │ │ ├── sign_of_the_horns.png │ │ │ │ ├── sleeping.png │ │ │ │ ├── sleepy.png │ │ │ │ ├── slight_frown.png │ │ │ │ ├── slight_smile.png │ │ │ │ ├── slightly_frowning_face.png │ │ │ │ ├── slightly_smiling.png │ │ │ │ ├── slightly_smiling_face.png │ │ │ │ ├── smile.png │ │ │ │ ├── smiley.png │ │ │ │ ├── smirk.png │ │ │ │ ├── sob.png │ │ │ │ ├── stuck_out_tongue.png │ │ │ │ ├── stuck_out_tongue_closed_eyes.png │ │ │ │ ├── stuck_out_tongue_winking_eye.png │ │ │ │ ├── sweat.png │ │ │ │ ├── sweat_smile.png │ │ │ │ ├── thumbsdown.png │ │ │ │ ├── thumbsup.png │ │ │ │ ├── unamused.png │ │ │ │ ├── wink.png │ │ │ │ └── yum.png │ │ ├── img │ │ │ ├── appstore-badge.png │ │ │ ├── csharp-logo.svg │ │ │ ├── en_app_rgb_wo_60.png │ │ │ ├── github.svg │ │ │ ├── java-logo.svg │ │ │ ├── kotlin-logo.svg │ │ │ ├── loading.svg │ │ │ ├── logo-text.svg │ │ │ ├── logo-white.svg │ │ │ ├── logo.svg │ │ │ ├── no-profile64.png │ │ │ ├── onebox │ │ │ │ └── github-16.png │ │ │ ├── shortcuts.png │ │ │ ├── swift-logo.svg │ │ │ ├── twitter.svg │ │ │ └── v.png │ │ ├── lib │ │ │ ├── js │ │ │ │ └── jquery.js │ │ │ └── mjs │ │ │ │ ├── servicestack-client.min.mjs │ │ │ │ └── servicestack-client.mjs │ │ ├── static-layout.htm │ │ ├── static-post.htm │ │ └── static.htm │ └── store │ │ ├── README.md │ │ └── index.js ├── tailwind.config.js ├── tailwind.input.css └── wwwroot │ ├── .nojekyll │ ├── 200.html │ ├── App.json │ ├── Identity │ └── lib │ │ └── jquery-validation-unobtrusive │ │ └── jquery.validate.unobtrusive.js │ ├── README.md │ ├── _nuxt │ ├── LICENSES │ ├── app.0fd03b6df8cebed4d025.js │ ├── app.9aa4d5a0fb474d57a1cf8593c77bf2b5.css │ ├── img │ │ ├── appstore-badge.4deb278.png │ │ ├── csharp-logo.f207120.svg │ │ ├── en_app_rgb_wo_60.0483be5.png │ │ ├── java-logo.842e0e6.svg │ │ ├── kotlin-logo.9443e55.svg │ │ ├── loading.118a471.svg │ │ ├── logo-text.eeff532.svg │ │ └── swift-logo.c896e09.svg │ ├── layouts_default.ce6f84234777fec81641.js │ ├── manifest.08e587a7cf311c1fa8e1.js │ ├── pages__slug__category.6bf256781f988abecbc0.js │ ├── pages__slug_index.5ad441153d863e9ae73c.js │ ├── pages_comments__postid__id.f1b77c13afcb85754f11.js │ ├── pages_favorites_index.b0dde4b6f68e9c3bc89c.js │ ├── pages_index.558651a5709dfb7cf396.js │ ├── pages_login__provider.15cd6e5d7ff51b974a8e.js │ ├── pages_news_index.609abf2a0eef603ed934.js │ ├── pages_organizations__slug_index.b19168500d15eb7b7fd9.js │ ├── pages_organizations_index.a6c08bf7e470c654695f.js │ ├── pages_posts__id__postslug.c088fe3a663537875e85.js │ ├── pages_stacks__slug_edit.b81c34a2dc48cb60bd94.js │ ├── pages_stacks__slug_index.656a06329acf6a4df662.js │ ├── pages_stacks_index.429626d2d7bb97bd6710.js │ ├── pages_stacks_new.63bea6d3da034e1e49bc.js │ ├── pages_tech__slug_edit.1604b038278618fbf65f.js │ ├── pages_tech__slug_index.a64865b2bb12651ea0e0.js │ ├── pages_tech_index.c2c864334289eb15d1e0.js │ ├── pages_tech_new.d51307eb41fdb140b168.js │ ├── pages_top_index.0ddbe9f590092ff1798b.js │ ├── pages_users__id.c77b9a6e50a08ce8555a.js │ ├── vendor.08e39e69a83773e7ec038e85b22130f0.css │ └── vendor.2ff088b82f935d3f723e.js │ ├── _redirects │ ├── css │ ├── app.css │ └── typography.css │ ├── favicon.ico │ ├── favorites │ └── index.html │ ├── googled0ec8ee6ceb21aeb.html │ ├── images │ └── emoji │ │ └── emoji_one │ │ ├── blush.png │ │ ├── confounded.png │ │ ├── confused.png │ │ ├── crazy_face.png │ │ ├── cry.png │ │ ├── disappointed.png │ │ ├── disappointed_relieved.png │ │ ├── dizzy_face.png │ │ ├── drooling_face.png │ │ ├── exploding_head.png │ │ ├── expressionless.png │ │ ├── eyes.png │ │ ├── face_with_head_bandage.png │ │ ├── face_with_monocle.png │ │ ├── face_with_raised_eyebrow.png │ │ ├── face_with_rolling_eyes.png │ │ ├── face_with_symbols_over_mouth.png │ │ ├── face_with_thermometer.png │ │ ├── fearful.png │ │ ├── flushed.png │ │ ├── frowning.png │ │ ├── frowning2.png │ │ ├── frowning_face.png │ │ ├── gift_heart.png │ │ ├── grimacing.png │ │ ├── grin.png │ │ ├── grinning.png │ │ ├── hand.png │ │ ├── hand_splayed.png │ │ ├── heart_eyes.png │ │ ├── hearts.png │ │ ├── metal.png │ │ ├── muscle.png │ │ ├── nerd.png │ │ ├── neutral_face.png │ │ ├── ok_hand.png │ │ ├── open_mouth.png │ │ ├── pensive.png │ │ ├── persevere.png │ │ ├── point_down.png │ │ ├── point_left.png │ │ ├── point_right.png │ │ ├── point_up.png │ │ ├── point_up_2.png │ │ ├── relaxed.png │ │ ├── relieved.png │ │ ├── rocket.png │ │ ├── rofl.png │ │ ├── roll_eyes.png │ │ ├── satisfied.png │ │ ├── scream.png │ │ ├── shushing_face.png │ │ ├── sign_of_the_horns.png │ │ ├── sleeping.png │ │ ├── sleepy.png │ │ ├── slight_frown.png │ │ ├── slight_smile.png │ │ ├── slightly_frowning_face.png │ │ ├── slightly_smiling.png │ │ ├── slightly_smiling_face.png │ │ ├── smile.png │ │ ├── smiley.png │ │ ├── smirk.png │ │ ├── sob.png │ │ ├── stuck_out_tongue.png │ │ ├── stuck_out_tongue_closed_eyes.png │ │ ├── stuck_out_tongue_winking_eye.png │ │ ├── sweat.png │ │ ├── sweat_smile.png │ │ ├── thumbsdown.png │ │ ├── thumbsup.png │ │ ├── unamused.png │ │ ├── wink.png │ │ └── yum.png │ ├── img │ ├── appstore-badge.png │ ├── csharp-logo.svg │ ├── en_app_rgb_wo_60.png │ ├── github.svg │ ├── java-logo.svg │ ├── kotlin-logo.svg │ ├── loading.svg │ ├── logo-text.svg │ ├── logo-white.svg │ ├── logo.svg │ ├── no-profile64.png │ ├── onebox │ │ └── github-16.png │ ├── shortcuts.png │ ├── swift-logo.svg │ ├── twitter.svg │ └── v.png │ ├── index.html │ ├── lib │ ├── js │ │ └── jquery.js │ └── mjs │ │ ├── servicestack-client.min.mjs │ │ └── servicestack-client.mjs │ ├── news │ └── index.html │ ├── organizations │ └── index.html │ ├── stacks │ ├── index.html │ └── new │ │ └── index.html │ ├── static-layout.htm │ ├── static-post.htm │ ├── static.htm │ ├── tech │ ├── index.html │ └── new │ │ └── index.html │ └── top │ └── index.html └── license.txt /.deploy/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: "3.9" 2 | services: 3 | app: 4 | image: ghcr.io/${IMAGE_REPO}:${RELEASE_VERSION} 5 | restart: always 6 | network_mode: bridge 7 | ports: 8 | - "8080" 9 | container_name: ${APP_NAME}_app 10 | environment: 11 | WS_HOST: ws://${HOST_DOMAIN} 12 | WS_PORT: 80 13 | VIRTUAL_HOST: ${HOST_DOMAIN} 14 | VIRTUAL_PORT: 8080 # New default ASP.NET port -> https://learn.microsoft.com/en-us/dotnet/core/compatibility/containers/8.0/aspnet-port 15 | LETSENCRYPT_HOST: ${HOST_DOMAIN} 16 | LETSENCRYPT_EMAIL: ${LETSENCRYPT_EMAIL} 17 | FORUMS_DB: ${FORUMS_DB} 18 | GH_CLIENT_ID: ${GH_CLIENT_ID} 19 | GH_CLIENT_SECRET: ${GH_CLIENT_SECRET} 20 | TECHSTACKS_DB: ${TECHSTACKS_DB} 21 | TECHSTACKS_SMTP_USER: ${TECHSTACKS_SMTP_USER} 22 | TECHSTACKS_SMTP_PASS: ${TECHSTACKS_SMTP_PASS} 23 | LC_ALL: "en_US.UTF-8" 24 | LANG: "en_US.UTF-8" 25 | volumes: 26 | - app-mydb:/app/App_Data 27 | 28 | app-migration: 29 | image: ghcr.io/${IMAGE_REPO}:${RELEASE_VERSION} 30 | restart: "no" 31 | container_name: ${APP_NAME}_app_migration 32 | profiles: 33 | - migration 34 | command: --AppTasks=migrate 35 | volumes: 36 | - app-mydb:/app/App_Data 37 | 38 | # networks: 39 | # default: 40 | # external: true 41 | # name: nginx 42 | 43 | volumes: 44 | app-mydb: 45 | -------------------------------------------------------------------------------- /.deploy/nginx-proxy-compose.yml: -------------------------------------------------------------------------------- 1 | version: "3.9" 2 | 3 | services: 4 | nginx-proxy: 5 | image: nginxproxy/nginx-proxy 6 | container_name: nginx-proxy 7 | restart: always 8 | ports: 9 | - "80:80" 10 | - "443:443" 11 | volumes: 12 | - conf:/etc/nginx/conf.d 13 | - vhost:/etc/nginx/vhost.d 14 | - html:/usr/share/nginx/html 15 | - dhparam:/etc/nginx/dhparam 16 | - certs:/etc/nginx/certs:ro 17 | - /var/run/docker.sock:/tmp/docker.sock:ro 18 | labels: 19 | - "com.github.jrcs.letsencrypt_nginx_proxy_companion.nginx_proxy" 20 | 21 | letsencrypt: 22 | image: nginxproxy/acme-companion:2.2 23 | container_name: nginx-proxy-le 24 | restart: always 25 | depends_on: 26 | - "nginx-proxy" 27 | environment: 28 | - DEFAULT_EMAIL=you@example.com 29 | volumes: 30 | - certs:/etc/nginx/certs:rw 31 | - acme:/etc/acme.sh 32 | - vhost:/etc/nginx/vhost.d 33 | - html:/usr/share/nginx/html 34 | - /var/run/docker.sock:/var/run/docker.sock:ro 35 | 36 | networks: 37 | default: 38 | name: nginx 39 | 40 | volumes: 41 | conf: 42 | vhost: 43 | html: 44 | dhparam: 45 | certs: 46 | acme: -------------------------------------------------------------------------------- /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | name: Build 2 | 3 | on: 4 | pull_request: {} 5 | push: 6 | branches: 7 | - '**' # matches every branch 8 | 9 | jobs: 10 | build: 11 | runs-on: ubuntu-22.04 12 | steps: 13 | - name: checkout 14 | uses: actions/checkout@v3 15 | 16 | - name: Setup dotnet 17 | uses: actions/setup-dotnet@v3 18 | with: 19 | dotnet-version: '8.0' 20 | 21 | - name: build 22 | run: dotnet build 23 | working-directory: . -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | // Use IntelliSense to learn about possible attributes. 3 | // Hover to view descriptions of existing attributes. 4 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 5 | "version": "0.2.0", 6 | "configurations": [ 7 | 8 | { 9 | "name": ".NET Core Launch (console)", 10 | "type": "coreclr", 11 | "request": "launch", 12 | "preLaunchTask": "build", 13 | "program": "${workspaceFolder}/TechStacks/bin/Debug/netcoreapp2.0/TechStacks.dll", 14 | "args": [], 15 | "cwd": "${workspaceFolder}/TechStacks", 16 | "console": "internalConsole", 17 | "stopAtEntry": false, 18 | "internalConsoleOptions": "openOnSessionStart", 19 | "env": { 20 | "ASPNETCORE_ENVIRONMENT": "Development", 21 | "ASPNETCORE_URLS": "http://*:16325/" 22 | } 23 | }, 24 | { 25 | "name": ".NET Core Launch (web)", 26 | "type": "coreclr", 27 | "request": "launch", 28 | "preLaunchTask": "build", 29 | "program": "${workspaceFolder}/TechStacks/bin/Debug/netcoreapp2.0/TechStacks.dll", 30 | "args": [], 31 | "cwd": "${workspaceFolder}/TechStacks", 32 | "stopAtEntry": false, 33 | "internalConsoleOptions": "openOnSessionStart", 34 | "launchBrowser": { 35 | "enabled": true, 36 | "args": "${auto-detect-url}", 37 | "windows": { 38 | "command": "cmd.exe", 39 | "args": "/C start ${auto-detect-url}" 40 | }, 41 | "osx": { 42 | "command": "open" 43 | }, 44 | "linux": { 45 | "command": "xdg-open" 46 | } 47 | }, 48 | "env": { 49 | "ASPNETCORE_ENVIRONMENT": "Development", 50 | "ASPNETCORE_URLS": "http://*:16325/" 51 | }, 52 | "sourceFileMap": { 53 | "/Views": "${workspaceFolder}/Views" 54 | } 55 | }, 56 | { 57 | "name": ".NET Core Attach", 58 | "type": "coreclr", 59 | "request": "attach", 60 | "processId": "${command:pickProcess}" 61 | } 62 | ] 63 | } -------------------------------------------------------------------------------- /.vscode/tasks.json: -------------------------------------------------------------------------------- 1 | { 2 | // See https://go.microsoft.com/fwlink/?LinkId=733558 3 | // for the documentation about the tasks.json format 4 | "version": "2.0.0", 5 | "tasks": [ 6 | { 7 | "label": "build", 8 | "command": "dotnet build", 9 | "type": "shell", 10 | "group": "build", 11 | "presentation": { 12 | "reveal": "silent" 13 | }, 14 | "problemMatcher": "$msCompile" 15 | } 16 | ] 17 | } -------------------------------------------------------------------------------- /NuGet.Config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /TechStacks.ServiceInterface/Admin/DummyTypesService.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using ServiceStack; 3 | using TechStacks.ServiceModel.Types; 4 | 5 | namespace TechStacks.ServiceInterface.Admin; 6 | 7 | public class DummyTypes 8 | { 9 | public List Post { get; set; } 10 | } 11 | 12 | public class DummyTypesService : Service 13 | { 14 | public object Any(DummyTypes request) => request; 15 | } -------------------------------------------------------------------------------- /TechStacks.ServiceInterface/AppFeatureFlags.cs: -------------------------------------------------------------------------------- 1 | using ServiceStack.Configuration; 2 | 3 | namespace TechStacks.ServiceInterface; 4 | 5 | public static class AppFeatureFlags 6 | { 7 | public static bool EnableTwitterUpdates(this IAppSettings appSettings) 8 | { 9 | return appSettings.Get("EnableTwitterUpdates", true); 10 | } 11 | } -------------------------------------------------------------------------------- /TechStacks.ServiceInterface/ClientRoutesService.cs: -------------------------------------------------------------------------------- 1 | using ServiceStack; 2 | using ServiceStack.DataAnnotations; 3 | using ServiceStack.Script; 4 | 5 | namespace TechStacks.ServiceInterface; 6 | 7 | [Exclude(Feature.Metadata)] 8 | // [FallbackRoute("/{*PathInfo}", Matches = "AcceptsHtml")] 9 | public class FallbackForClientRoutes 10 | { 11 | public string PathInfo { get; set; } 12 | public ResponseStatus ResponseStatus { get; set; } 13 | } 14 | 15 | [Route("/ping")] 16 | public class Ping : IGet {} 17 | 18 | public class ClientRoutesService : Service 19 | { 20 | //Return index.html for unmatched requests so routing is handled on client 21 | public object Any(FallbackForClientRoutes request) 22 | { 23 | return Request.PathInfo == "/" 24 | ? Request.GetPageResult("/static") 25 | : Request.PathInfo.StartsWith("/p/") 26 | ? Request.GetPageResult("/static-post") 27 | : new HttpResult(VirtualFileSources.GetFile("index.html")); 28 | } 29 | 30 | public object Any(Ping request) => "OK"; 31 | } 32 | 33 | //Client Routes to generate urls in sitemap.xml 34 | [Route("/tech")] 35 | public class ClientAllTechnologies {} 36 | 37 | [Route("/tech/{Slug}")] 38 | public class ClientTechnology 39 | { 40 | public string Slug { get; set; } 41 | } 42 | 43 | [Route("/stacks")] 44 | public class ClientAllTechnologyStacks { } 45 | 46 | [Route("/stacks/{Slug}")] 47 | public class ClientTechnologyStack 48 | { 49 | public string Slug { get; set; } 50 | } 51 | 52 | [Route("/users/{UserName}")] 53 | public class ClientUser 54 | { 55 | public string UserName { get; set; } 56 | } -------------------------------------------------------------------------------- /TechStacks.ServiceInterface/CustomAuthUserSession.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Security.Claims; 4 | using System.Threading.Tasks; 5 | using Microsoft.AspNetCore.Identity; 6 | using Microsoft.Extensions.Options; 7 | using ServiceStack; 8 | using ServiceStack.Auth; 9 | using TechStacks.Data; 10 | 11 | namespace TechStacks.ServiceInterface; 12 | 13 | public class CustomUserSession : AuthUserSession 14 | { 15 | public string GithubProfileUrl { get; set; } 16 | } 17 | 18 | public class AdditionalUserClaimsPrincipalFactory( 19 | UserManager userManager, 20 | RoleManager roleManager, 21 | IOptions optionsAccessor) 22 | : UserClaimsPrincipalFactory(userManager, roleManager, optionsAccessor) 23 | { 24 | public override async Task CreateAsync(ApplicationUser user) 25 | { 26 | var principal = await base.CreateAsync(user); 27 | var identity = (ClaimsIdentity)principal.Identity!; 28 | 29 | var claims = new List(); 30 | if (user.ProfileUrl != null) 31 | claims.Add(new Claim(JwtClaimTypes.Picture, user.ProfileUrl)); 32 | 33 | identity.AddClaims(claims); 34 | return principal; 35 | } 36 | } 37 | 38 | public class CustomUserAuth : UserAuth 39 | { 40 | public string DefaultProfileUrl { get; set; } 41 | 42 | public string IpAddress { get; set; } 43 | 44 | public string RefSource { get; set; } 45 | 46 | public string RefUrn { get; set; } 47 | 48 | public DateTime? Banned { get; set; } 49 | 50 | public string BannedBy { get; set; } 51 | 52 | public string Notes { get; set; } 53 | 54 | public DateTime? DisableEmails { get; set; } 55 | 56 | public string CreatedBy { get; set; } 57 | } 58 | -------------------------------------------------------------------------------- /TechStacks.ServiceInterface/DataModel/EmailTemplate.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using ServiceStack.DataAnnotations; 3 | 4 | namespace TechStacks.ServiceInterface.DataModel; 5 | 6 | public class EmailTemplate 7 | { 8 | [AutoIncrement] 9 | public long Id { get; set; } 10 | 11 | public string TemplatePath { get; set; } 12 | 13 | public string ToEmail { get; set; } 14 | public string ToName { get; set; } 15 | public int[] ToUserIds { get; set; } 16 | 17 | public string FromEmail { get; set; } 18 | public string FromName { get; set; } 19 | 20 | public string CcEmail { get; set; } 21 | public string CcName { get; set; } 22 | 23 | public string Subject { get; set; } 24 | 25 | public string Body { get; set; } 26 | 27 | public string BodyHtml { get; set; } 28 | 29 | public DateTime Created { get; set; } 30 | } -------------------------------------------------------------------------------- /TechStacks.ServiceInterface/DataModel/Notification.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using ServiceStack.DataAnnotations; 3 | 4 | namespace TechStacks.ServiceInterface.DataModel; 5 | 6 | public class Notification 7 | { 8 | [AutoIncrement] 9 | public long Id { get; set; } 10 | 11 | public string Event { get; set; } 12 | 13 | public long RefId { get; set; } 14 | 15 | public string RefType { get; set; } 16 | 17 | public string RefUrn { get; set; } 18 | 19 | [PgSqlTextArray] 20 | public string[] Operations { get; set; } 21 | 22 | [PgSqlIntArray] 23 | public int[] UserIds { get; set; } 24 | 25 | [PgSqlIntArray] 26 | public int[] EmailedUserIds { get; set; } 27 | 28 | public long? EmailTemplateId { get; set; } 29 | 30 | public DateTime Created { get; set; } 31 | 32 | public DateTime? Started { get; set; } 33 | 34 | public DateTime? Completed { get; set; } 35 | 36 | public DateTime? Failed { get; set; } 37 | 38 | public string Error { get; set; } 39 | 40 | public string Notes { get; set; } 41 | } -------------------------------------------------------------------------------- /TechStacks.ServiceInterface/DataModel/SubscribePost.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using ServiceStack.DataAnnotations; 3 | 4 | namespace TechStacks.ServiceInterface.DataModel; 5 | 6 | public class SubscribePost 7 | { 8 | [AutoIncrement] 9 | public long Id { get; set; } 10 | 11 | [Index] 12 | public long PostId { get; set; } 13 | 14 | [Index] 15 | public int UserId { get; set; } 16 | 17 | public string UserName { get; set; } 18 | 19 | [Index] 20 | public long OrganizationId { get; set; } 21 | 22 | public DateTime? LastSynced { get; set; } 23 | 24 | public DateTime Created { get; set; } 25 | } -------------------------------------------------------------------------------- /TechStacks.ServiceInterface/DataModel/SubscriptionPost.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using ServiceStack.DataAnnotations; 3 | 4 | namespace TechStacks.ServiceInterface.DataModel; 5 | 6 | /// 7 | /// Task to send notifications to all subscribers 8 | /// 9 | public class SubscriptionPost 10 | { 11 | [AutoIncrement] 12 | public long Id { get; set; } //= PostId 13 | 14 | [Index] 15 | public int OrganizationId { get; set; } 16 | 17 | public DateTime Created { get; set; } 18 | 19 | public DateTime? Completed { get; set; } 20 | 21 | [PgSqlIntArray] 22 | public int[] NotifiedUserIds { get; set; } 23 | 24 | public int NotifyCount { get; set; } 25 | 26 | public long EmailTemplateId { get; set; } 27 | 28 | public DateTime? Failed { get; set; } 29 | 30 | public string Error { get; set; } 31 | 32 | public string Notes { get; set; } 33 | } -------------------------------------------------------------------------------- /TechStacks.ServiceInterface/HelloService.cs: -------------------------------------------------------------------------------- 1 | using ServiceStack; 2 | using TechStacks.ServiceModel; 3 | 4 | namespace TechStacks.ServiceInterface; 5 | 6 | public class HelloService : Service 7 | { 8 | public object Any(Hello request) => 9 | new HelloResponse { Result = $"Hello, {request.Name}!" }; 10 | } -------------------------------------------------------------------------------- /TechStacks.ServiceInterface/ITwitterUpdates.cs: -------------------------------------------------------------------------------- 1 | namespace TechStacks.ServiceInterface; 2 | 3 | public interface ITwitterUpdates 4 | { 5 | string BaseUrl { get; set; } 6 | string Tweet(string status); 7 | } -------------------------------------------------------------------------------- /TechStacks.ServiceInterface/Messaging/BackgroundAdminServices.cs: -------------------------------------------------------------------------------- 1 | using ServiceStack; 2 | using ServiceStack.Messaging; 3 | 4 | namespace TechStacks.ServiceInterface.Messaging; 5 | 6 | [Route("/mq/stop")] 7 | public class MqStop : IReturn {} 8 | 9 | [Route("/mq/start")] 10 | public class MqStart : IReturn {} 11 | 12 | [Route("/mq/stats")] 13 | public class MqStats : IReturn {} 14 | 15 | [Route("/mq/status")] 16 | public class MqStatus : IReturn {} 17 | 18 | public class BackgroundAdminServices : Service 19 | { 20 | public IMessageService MqService { get; set; } 21 | 22 | [RequiredRole("Admin")] 23 | public object Any(MqStart request) 24 | { 25 | MqService.Start(); 26 | return "OK"; 27 | } 28 | 29 | [RequiredRole("Admin")] 30 | public object Any(MqStop request) 31 | { 32 | MqService.Stop(); 33 | return "OK"; 34 | } 35 | 36 | public object Any(MqStats request) => MqService.GetStats(); 37 | 38 | [AddHeader(ContentType = MimeTypes.PlainText)] 39 | public object Any(MqStatus request) => MqService.GetStatsDescription(); 40 | } -------------------------------------------------------------------------------- /TechStacks.ServiceInterface/PreRenderService.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Threading.Tasks; 3 | using ServiceStack; 4 | using ServiceStack.OrmLite; 5 | using TechStacks.ServiceModel; 6 | 7 | namespace TechStacks.ServiceInterface; 8 | 9 | public class PreRenderService(IMarkdownProvider markdown) : PostServicesBase(markdown) 10 | { 11 | string GetPath() => Request.RawUrl.StartsWith("/prerender") 12 | ? Request.RawUrl.Substring("/prerender".Length) 13 | : Request.RawUrl; 14 | 15 | // [Authenticate] 16 | public async Task Put(StorePreRender request) 17 | { 18 | var user = GetUser(); 19 | 20 | var bytes = request.RequestStream.ReadFully(); 21 | 22 | var path = GetPath(); 23 | 24 | var updated = await Db.UpdateOnlyAsync(() => 25 | new PreRender { 26 | Data = bytes, 27 | ContentType = Request.ContentType, 28 | Modified = DateTime.Now, 29 | ModifiedBy = user.UserName, 30 | }, 31 | where:x => x.Path == path); 32 | 33 | if (updated == 0) 34 | { 35 | Db.Insert(new PreRender { 36 | Path = path, 37 | Data = bytes, 38 | ContentType = Request.ContentType, 39 | Created = DateTime.Now, 40 | CreatedBy = user.UserName, 41 | Modified = DateTime.Now, 42 | ModifiedBy = user.UserName, 43 | }); 44 | } 45 | } 46 | 47 | public async Task Get(GetPreRender request) 48 | { 49 | var path = GetPath(); 50 | var prerender = Db.SingleById(path); 51 | if (prerender == null) 52 | throw HttpError.NotFound(path); 53 | 54 | await Response.WriteBytesToResponse(prerender.Data, prerender.ContentType); 55 | } 56 | } -------------------------------------------------------------------------------- /TechStacks.ServiceInterface/SessionInfoServices.cs: -------------------------------------------------------------------------------- 1 | using System.Threading.Tasks; 2 | using ServiceStack; 3 | using TechStacks.ServiceModel; 4 | 5 | namespace TechStacks.ServiceInterface; 6 | 7 | public class SessionInfoServices : Service 8 | { 9 | public async Task Any(SessionInfo request) 10 | { 11 | var session = SessionAs(); 12 | var response = session.ConvertTo(); 13 | 14 | var userInfoTask = Gateway.SendAsync(new GetUserInfo { 15 | UserName = session.UserAuthName, 16 | }); 17 | 18 | var userOrgTask = Gateway.SendAsync(new GetUserOrganizations()); 19 | 20 | var userInfo = await userInfoTask; 21 | response.PopulateWith(userInfo); 22 | response.ProfileUrl ??= response.AvatarUrl; 23 | 24 | var userOrg = await userOrgTask; 25 | response.Members = userOrg.Members; 26 | response.MemberInvites = userOrg.MemberInvites; 27 | response.Subscriptions = userOrg.Subscriptions; 28 | 29 | return response; 30 | } 31 | } -------------------------------------------------------------------------------- /TechStacks.ServiceInterface/TechStackQueries.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Data; 3 | using System.Linq; 4 | using ServiceStack; 5 | using ServiceStack.OrmLite; 6 | using TechStacks.ServiceModel; 7 | using TechStacks.ServiceModel.Types; 8 | 9 | namespace TechStacks.ServiceInterface; 10 | 11 | public static class TechStackQueries 12 | { 13 | public static List GetTechStackDetails(this IDbConnection db, SqlExpression stackQuery) 14 | { 15 | //distinct 16 | var latestStacks = db.Select(stackQuery) 17 | .GroupBy(x => x.Id) 18 | .Select(x => x.First()) 19 | .ToList(); 20 | 21 | if (latestStacks.Count == 0) 22 | return []; 23 | 24 | var technologyChoices = 25 | db.LoadSelect(db.From() 26 | .Join() 27 | .Join() 28 | .Where(techChoice => 29 | Sql.In(techChoice.TechnologyStackId, latestStacks.Select(x => x.Id)) 30 | )); 31 | 32 | var stackDetails = latestStacks.Map(x => x.ConvertTo()); 33 | stackDetails.ForEach(stack => stack.TechnologyChoices = technologyChoices 34 | .Map(x => x.ToTechnologyInStack()) 35 | .Where(x => stack.Id == x.TechnologyStackId) 36 | .ToList()); 37 | 38 | return stackDetails; 39 | } 40 | } -------------------------------------------------------------------------------- /TechStacks.ServiceInterface/TechStacks.ServiceInterface.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | net8.0 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /TechStacks.ServiceInterface/Validations/OrganizationValidators.cs: -------------------------------------------------------------------------------- 1 | using ServiceStack; 2 | using ServiceStack.FluentValidation; 3 | using TechStacks.ServiceModel; 4 | 5 | namespace TechStacks.ServiceInterface.Validations; 6 | 7 | public class CreateOrganizationValidator : AbstractValidator 8 | { 9 | public CreateOrganizationValidator() 10 | { 11 | RuleSet(ApplyTo.Post, () => 12 | { 13 | RuleFor(x => x.Name).RequiredName(); 14 | RuleFor(x => x.Slug).RequiredSlug(); 15 | RuleFor(x => x.Description).OptionalDescription(); 16 | }); 17 | } 18 | } 19 | 20 | public class UpdateOrganizationValidator : AbstractValidator 21 | { 22 | public UpdateOrganizationValidator() 23 | { 24 | RuleSet(ApplyTo.Put, () => 25 | { 26 | RuleFor(x => x.Name).RequiredName(); 27 | RuleFor(x => x.Slug).RequiredSlug(); 28 | RuleFor(x => x.Description).OptionalDescription(); 29 | RuleFor(x => x.DeletePostsWithReportCount).GreaterThan(0); 30 | }); 31 | } 32 | } 33 | 34 | public class AddOrganizationCategoryValidator : AbstractValidator 35 | { 36 | public AddOrganizationCategoryValidator() => RuleSet(ApplyTo.Post, () => { 37 | RuleFor(x => x.Name).RequiredName(); 38 | RuleFor(x => x.Slug).RequiredSlug(); 39 | }); 40 | } 41 | 42 | public class UpdateOrganizationCategoryValidator : AbstractValidator 43 | { 44 | public UpdateOrganizationCategoryValidator() => RuleSet(ApplyTo.Put, () => { 45 | RuleFor(x => x.Name).RequiredName(); 46 | RuleFor(x => x.Slug).RequiredSlug(); 47 | }); 48 | } -------------------------------------------------------------------------------- /TechStacks.ServiceInterface/Validations/PostValidators.cs: -------------------------------------------------------------------------------- 1 | using ServiceStack; 2 | using ServiceStack.FluentValidation; 3 | using TechStacks.ServiceModel; 4 | using TechStacks.ServiceModel.Types; 5 | 6 | namespace TechStacks.ServiceInterface.Validations; 7 | 8 | public class CreatePostValidator : AbstractValidator 9 | { 10 | public CreatePostValidator() 11 | { 12 | RuleSet(ApplyTo.Post, () => 13 | { 14 | RuleFor(x => x.Title).RequiredTitle(); 15 | RuleFor(x => x.Url).OptionalUrl(); 16 | RuleFor(x => x.Content).OptionalContent(); 17 | 18 | RuleFor(x => x.Url) 19 | .NotEmpty() 20 | .When(x => string.IsNullOrEmpty(x.Content) && string.IsNullOrEmpty(x.ImageUrl) && Request.Files.Length == 0); 21 | 22 | RuleFor(x => x.OrganizationId) 23 | .GreaterThan(0) 24 | .When(x => x.OrganizationId == 0); 25 | 26 | RuleFor(x => x.TechnologyIds) 27 | .Must(x => x == null || x.Length <= 5) 28 | .WithMessage("Maximum of 5 technologies exceeded"); 29 | }); 30 | } 31 | } 32 | 33 | public class UpdatePostValidator : AbstractValidator 34 | { 35 | public UpdatePostValidator() 36 | { 37 | RuleSet(ApplyTo.Put, () => 38 | { 39 | RuleFor(x => x.Id).GreaterThan(0).WithMessage("Id Required"); 40 | RuleFor(x => x.Title).RequiredTitle(); 41 | RuleFor(x => x.Url).OptionalUrl(); 42 | RuleFor(x => x.Content).OptionalContent(); 43 | 44 | RuleFor(x => x.Url) 45 | .NotEmpty() 46 | .When(x => string.IsNullOrEmpty(x.Content) && string.IsNullOrEmpty(x.ImageUrl) && Request.Files.Length == 0); 47 | 48 | RuleFor(x => x.OrganizationId) 49 | .GreaterThan(0) 50 | .When(x => x.OrganizationId == 0); 51 | 52 | RuleFor(x => x.TechnologyIds) 53 | .Must(x => x == null || x.Length <= 5) 54 | .WithMessage("Maximum of 5 technologies exceeded"); 55 | }); 56 | } 57 | } 58 | 59 | public class PostCommentValidator : AbstractValidator 60 | { 61 | public PostCommentValidator() 62 | { 63 | RuleSet(ApplyTo.Put | ApplyTo.Post, () => 64 | { 65 | RuleFor(x => x.Id).GreaterThan(0).WithMessage("Id Required"); 66 | RuleFor(x => x.Content).OptionalContent(); 67 | }); 68 | } 69 | } -------------------------------------------------------------------------------- /TechStacks.ServiceInterface/Validations/TechStackValidators.cs: -------------------------------------------------------------------------------- 1 | using ServiceStack; 2 | using ServiceStack.FluentValidation; 3 | using TechStacks.ServiceModel; 4 | 5 | namespace TechStacks.ServiceInterface.Validations; 6 | 7 | public class CreateTechStackValidator : AbstractValidator 8 | { 9 | public CreateTechStackValidator() 10 | { 11 | RuleSet(ApplyTo.Post, () => 12 | { 13 | RuleFor(x => x.Name).RequiredName(); 14 | RuleFor(x => x.Slug).RequiredSlug(); 15 | RuleFor(x => x.VendorName).RequiredName(); 16 | RuleFor(x => x.AppUrl).RequiredUrl(); 17 | RuleFor(x => x.Description).RequiredDescription(); 18 | RuleFor(x => x.Details).OptionalContent(); 19 | }); 20 | } 21 | } 22 | 23 | public class UpdateTechStackValidator : AbstractValidator 24 | { 25 | public UpdateTechStackValidator() 26 | { 27 | RuleSet(ApplyTo.Put, () => 28 | { 29 | RuleFor(x => x.Id).GreaterThan(0); 30 | RuleFor(x => x.Name).RequiredName(); 31 | RuleFor(x => x.VendorName).RequiredName(); 32 | RuleFor(x => x.AppUrl).RequiredUrl(); 33 | RuleFor(x => x.Description).RequiredDescription(); 34 | RuleFor(x => x.Details).OptionalContent(); 35 | }); 36 | } 37 | } -------------------------------------------------------------------------------- /TechStacks.ServiceInterface/Validations/TechValidators.cs: -------------------------------------------------------------------------------- 1 | using ServiceStack; 2 | using ServiceStack.FluentValidation; 3 | using TechStacks.ServiceModel; 4 | 5 | namespace TechStacks.ServiceInterface.Validations; 6 | 7 | public class CreateTechValidator : AbstractValidator 8 | { 9 | public CreateTechValidator() 10 | { 11 | RuleSet(ApplyTo.Post, () => 12 | { 13 | RuleFor(x => x.Name).RequiredName(); 14 | RuleFor(x => x.Slug).RequiredSlug(); 15 | RuleFor(x => x.VendorName).RequiredName(); 16 | RuleFor(x => x.ProductUrl).RequiredUrl(); 17 | RuleFor(x => x.Description).RequiredDescription(); 18 | }); 19 | } 20 | } 21 | 22 | public class UpdateTechValidator : AbstractValidator 23 | { 24 | public UpdateTechValidator() 25 | { 26 | RuleSet(ApplyTo.Put, () => 27 | { 28 | RuleFor(x => x.Id).GreaterThan(0); 29 | RuleFor(x => x.Name).RequiredName(); 30 | RuleFor(x => x.VendorName).RequiredName(); 31 | RuleFor(x => x.ProductUrl).RequiredUrl(); 32 | RuleFor(x => x.Description).RequiredDescription(); 33 | }); 34 | } 35 | } -------------------------------------------------------------------------------- /TechStacks.ServiceModel/Admin.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using ServiceStack; 3 | using ServiceStack.DataAnnotations; 4 | 5 | namespace TechStacks.ServiceModel; 6 | 7 | [ExcludeMetadata] 8 | [Route("/notifications/{Id}/send")] 9 | public class SendNotification : IReturnVoid, IPost 10 | { 11 | public long Id { get; set; } 12 | } 13 | 14 | [ExcludeMetadata] 15 | [Route("/email/system")] 16 | public class SendSystemEmail : IReturnVoid, IPost 17 | { 18 | public string Subject { get; set; } 19 | public string Body { get; set; } 20 | } 21 | 22 | [ExcludeMetadata] 23 | [Route("/email/send")] 24 | public class SendEmail : IReturnVoid, IPost 25 | { 26 | public string To { get; set; } 27 | public string ToName { get; set; } 28 | public string Subject { get; set; } 29 | public string Body { get; set; } 30 | public string BodyHtml { get; set; } 31 | } 32 | 33 | [ExcludeMetadata] 34 | [Route("/notifications/retry-pending")] 35 | public class RetryPendingNotifications : IGet {} 36 | 37 | public class RetryPendingNotificationsResponse 38 | { 39 | public long[] ResentIds { get; set; } 40 | public ResponseStatus ResponseStatus { get; set; } 41 | } 42 | 43 | [Restrict(VisibleInternalOnly = true)] 44 | [Route("/tasks/hourly")] 45 | public class HourlyTask : IGet 46 | { 47 | public bool Force { get; set; } 48 | } 49 | 50 | public class HourlyTaskResponse : IMeta 51 | { 52 | public Dictionary Meta { get; set; } 53 | 54 | public ResponseStatus ResponseStatus { get; set; } 55 | } 56 | 57 | [Restrict(VisibleInternalOnly = true)] 58 | [Route("/cache/clear")] 59 | public class ClearCache : IReturn, IGet {} -------------------------------------------------------------------------------- /TechStacks.ServiceModel/Hello.cs: -------------------------------------------------------------------------------- 1 | using ServiceStack; 2 | 3 | namespace TechStacks.ServiceModel; 4 | 5 | [Route("/hello/{Name}")] 6 | public class Hello : IGet, IReturn 7 | { 8 | public string Name { get; set; } 9 | } 10 | 11 | public class HelloResponse 12 | { 13 | public string Result { get; set; } 14 | public ResponseStatus ResponseStatus { get; set; } 15 | } 16 | -------------------------------------------------------------------------------- /TechStacks.ServiceModel/Tags.cs: -------------------------------------------------------------------------------- 1 | namespace TechStacks.ServiceModel; 2 | 3 | public static class Tags 4 | { 5 | public const string AutoQuery = nameof(AutoQuery); 6 | public const string Organization = nameof(Organization); 7 | public const string Posts = nameof(Posts); 8 | public const string Tech = nameof(Tech); 9 | public const string TechStacks = nameof(TechStacks); 10 | public const string User = nameof(User); 11 | public const string Site = nameof(Site); 12 | } -------------------------------------------------------------------------------- /TechStacks.ServiceModel/TechStacks.ServiceModel.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | net8.0 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /TechStacks.ServiceModel/Types/PageStats.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace TechStacks.ServiceModel.Types; 4 | 5 | public class PageStats 6 | { 7 | public string Id { get; set; } 8 | 9 | public long ViewCount { get; set; } 10 | 11 | public long FavCount { get; set; } 12 | 13 | public long RefId { get; set; } 14 | 15 | public string RefType { get; set; } 16 | 17 | public string RefSlug { get; set; } 18 | 19 | public DateTime LastModified { get; set; } 20 | } 21 | 22 | public interface IRegisterStats 23 | { 24 | string GetStatsId(); 25 | } -------------------------------------------------------------------------------- /TechStacks.ServiceModel/Types/UserActivity.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using ServiceStack.DataAnnotations; 3 | 4 | namespace TechStacks.ServiceModel.Types; 5 | 6 | public class UserActivity 7 | { 8 | public int Id { get; set; } 9 | 10 | public string UserName { get; set; } 11 | 12 | [Default(0)] 13 | public int Karma { get; set; } 14 | 15 | [Default(0)] 16 | public int TechnologyCount { get; set; } 17 | 18 | [Default(0)] 19 | public int TechStacksCount { get; set; } 20 | 21 | [Default(0)] 22 | public int PostsCount { get; set; } 23 | 24 | [Default(0)] 25 | public int PostUpVotes { get; set; } 26 | 27 | [Default(0)] 28 | public int PostDownVotes { get; set; } 29 | 30 | [Default(0)] 31 | public int CommentUpVotes { get; set; } 32 | 33 | [Default(0)] 34 | public int CommentDownVotes { get; set; } 35 | 36 | [Default(0)] 37 | public int PostCommentsCount { get; set; } 38 | 39 | [Default(0)] 40 | public int PinnedCommentCount { get; set; } 41 | 42 | [Default(0)] 43 | public int PostReportCount { get; set; } 44 | 45 | [Default(0)] 46 | public int PostCommentReportCount { get; set; } 47 | 48 | public DateTime Created { get; set; } 49 | public DateTime Modified { get; set; } 50 | } 51 | 52 | public class UserFavoriteTechnologyStack 53 | { 54 | [AutoIncrement] 55 | public int Id { get; set; } 56 | 57 | public string UserId { get; set; } 58 | 59 | [References(typeof(TechnologyStack))] 60 | public int TechnologyStackId { get; set; } 61 | } 62 | 63 | public class UserFavoriteTechnology 64 | { 65 | [AutoIncrement] 66 | public int Id { get; set; } 67 | 68 | public string UserId { get; set; } 69 | 70 | [References(typeof(Technology))] 71 | public int TechnologyId { get; set; } 72 | } -------------------------------------------------------------------------------- /TechStacks.Tests/DbTasksBase.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using ServiceStack.Data; 3 | using ServiceStack.OrmLite; 4 | 5 | namespace TechStacks.Tests; 6 | 7 | public class DbTasksBase 8 | { 9 | public static OrmLiteConnectionFactory RegisterDialects(OrmLiteConnectionFactory factory) 10 | { 11 | factory.RegisterDialectProvider(nameof(PostgreSqlDialect), PostgreSqlDialect.Provider); 12 | return factory; 13 | } 14 | 15 | public readonly OrmLiteConnectionFactory dbFactory = RegisterDialects( 16 | new OrmLiteConnectionFactory( 17 | Environment.GetEnvironmentVariable("TECHSTACKS_DB"), 18 | PostgreSqlDialect.Provider)); 19 | } -------------------------------------------------------------------------------- /TechStacks.Tests/UnitTests.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | using System.Linq; 4 | using NUnit.Framework; 5 | using ServiceStack; 6 | using ServiceStack.Data; 7 | using ServiceStack.OrmLite; 8 | using ServiceStack.Testing; 9 | using ServiceStack.Text; 10 | using TechStacks.ServiceInterface; 11 | using TechStacks.ServiceModel; 12 | using TechStacks.ServiceModel.Types; 13 | 14 | namespace TechStacks.Tests; 15 | 16 | [TestFixture] 17 | public class UnitTests 18 | { 19 | private ServiceStackHost appHost; 20 | 21 | [OneTimeSetUp] 22 | public void Init() 23 | { 24 | appHost = new UnitTestHost(); 25 | var debugSettings = new FileInfo(@"~/../../../TechStacks/wwwroot_build/deploy/appsettings.license.txt".MapAbsolutePath()); 26 | Licensing.RegisterLicenseFromFileIfExists(debugSettings.FullName); 27 | appHost.Init(); 28 | } 29 | 30 | [OneTimeTearDown] 31 | public void TestFixtureTearDown() 32 | { 33 | appHost.Dispose(); 34 | } 35 | 36 | [SetUp] 37 | public void Setup() 38 | { 39 | var dbFactory = appHost.Resolve(); 40 | using var db = dbFactory.OpenDbConnection(); 41 | db.DropAndCreateTable(); 42 | db.DropAndCreateTable(); 43 | db.DropAndCreateTable(); 44 | db.DropAndCreateTable(); 45 | db.DropAndCreateTable(); 46 | 47 | SeedTestHost(); 48 | } 49 | 50 | [Test] 51 | public void Can_Get_Stacks() 52 | { 53 | var service = appHost.Resolve(); 54 | var response = (GetAllTechnologyStacksResponse)service.Get(new GetAllTechnologyStacks()); 55 | var dbFactory = appHost.Resolve(); 56 | using var db = dbFactory.OpenDbConnection(); 57 | 58 | var allStacks = db.Select().ToList(); 59 | Assert.That(allStacks.Count, Is.EqualTo(response.Results.Count)); 60 | } 61 | 62 | private void SeedTestHost() 63 | { 64 | Seeds.SeedApp(appHost.Resolve()); 65 | } 66 | 67 | [Test] 68 | public void Generate_AuthKey() 69 | { 70 | Convert.ToBase64String(AesUtils.CreateKey()).Print(); 71 | } 72 | } -------------------------------------------------------------------------------- /TechStacks.Tests/UpdateAdminTasks.cs: -------------------------------------------------------------------------------- 1 | using NUnit.Framework; 2 | using ServiceStack.Logging; 3 | using ServiceStack.OrmLite; 4 | using ServiceStack.Text; 5 | using TechStacks.ServiceModel.Types; 6 | 7 | namespace TechStacks.Tests; 8 | 9 | public class UpdateAdminTasks : DbTasksBase 10 | { 11 | static UpdateAdminTasks() => LogManager.LogFactory = new ConsoleLogFactory(debugEnabled: true); 12 | 13 | [Test] 14 | public void Update_FavCounts() 15 | { 16 | using var db = dbFactory.Open(); 17 | 18 | var faveTechStacks = db.Dictionary( 19 | db.From().GroupBy(x => x.TechnologyStackId) 20 | .OrderByDescending("COUNT") 21 | .Select(x => new { x.TechnologyStackId, Count = Sql.Count("*") })); 22 | 23 | faveTechStacks.PrintDump(); 24 | 25 | var result = db.ExecuteSql($@"UPDATE technology_stack SET fav_count=fav.count 26 | FROM (SELECT technology_stack_id, Count(*) AS Count FROM user_favorite_technology_stack GROUP BY technology_stack_id) as fav 27 | WHERE id = fav.technology_stack_id"); 28 | 29 | $"{result} rows updated".Print(); 30 | 31 | var faveTechs = db.Dictionary( 32 | db.From().GroupBy(x => x.TechnologyId) 33 | .OrderByDescending("COUNT") 34 | .Select(x => new { x.TechnologyId, Count = Sql.Count("*") })); 35 | 36 | faveTechs.PrintDump(); 37 | 38 | result = db.ExecuteSql(@"UPDATE technology SET fav_count=fav.count 39 | FROM (SELECT technology_id, Count(*) AS Count FROM user_favorite_technology GROUP BY technology_id) as fav 40 | WHERE id = fav.technology_id"); 41 | 42 | $"{result} rows updated".Print(); 43 | } 44 | 45 | [Test] 46 | public void Update_ViewCounts() 47 | { 48 | using var db = dbFactory.Open(); 49 | 50 | var result = db.ExecuteSql(@"UPDATE technology_stack SET view_count=v.view_count 51 | FROM (SELECT ref_slug, view_count FROM page_stats WHERE ref_type='stack') AS v 52 | WHERE v.ref_slug = slug"); 53 | 54 | result = db.ExecuteSql(@"UPDATE technology SET view_count=v.view_count 55 | FROM (SELECT ref_slug, view_count FROM page_stats WHERE ref_type='tech') AS v 56 | WHERE v.ref_slug = slug"); 57 | } 58 | 59 | } -------------------------------------------------------------------------------- /TechStacks.Tests/appsettings.txt: -------------------------------------------------------------------------------- 1 | # Release App Settings 2 | 3 | DebugMode false 4 | oauth.twitter.ConsumerKey nPNlccVzZGYX6fMq7HfFoO9Yr 5 | oauth.twitter.ConsumerSecret 0i11DERF5s4azDOzMmsIurUECWG3RUTqQ9hqNJpCe7tWwyZrxj 6 | oauth.github.Scopes user 7 | oauth.github.ClientId d8f0b22800ce2b358438 8 | oauth.github.ClientSecret e0ed94f5d6409591363ed43f91576e136ce2b8e2 9 | oauth.RedirectUrl https://techstacks.io 10 | oauth.CallbackUrl https://techstacks.io/auth/{0} 11 | OrmLite.Provider Postgres 12 | OrmLite.ConnectionString Server=apps.ct4ykeamwqkx.us-east-1.rds.amazonaws.com;Port=5432;User Id=test;Password=test;Database=techstacks;Pooling=true;MinPoolSize=0;MaxPoolSize=200 13 | Admins darren.j.reid@gmail.com,demis.bellot@gmail.com 14 | TwitterAdmins layoric,demisbellot 15 | WebStacks.ConsumerKey 7GVshAij2JfSRrOqg7CTg1jUN 16 | WebStacks.ConsumerSecret wBJFr7tOkXWXg1Gvwn49FtmikGtcocgrnacfRpVxgSkrsfBB0i 17 | WebStacks.AccessToken 2931572242-5gGFW9qEjVdTB3toCCTs1o0WyGADaLMvn0Ukq9N 18 | WebStacks.AccessSecret K2gLRScR3qQu9X5JOLInSgaiYIVhqaMtWNHI85jAKXqKa 19 | -------------------------------------------------------------------------------- /TechStacks/.editorconfig: -------------------------------------------------------------------------------- 1 | # editorconfig.org 2 | root = true 3 | 4 | [*] 5 | indent_size = 4 6 | indent_style = space 7 | end_of_line = lf 8 | charset = utf-8 9 | trim_trailing_whitespace = true 10 | insert_final_newline = true 11 | 12 | [*.md] 13 | trim_trailing_whitespace = false 14 | -------------------------------------------------------------------------------- /TechStacks/.eslintignore: -------------------------------------------------------------------------------- 1 | # js vendor file with import/require 2 | assets/** 3 | 4 | # static vendor file . use with nuxt.config.js script 5 | static/** 6 | 7 | # dependencies 8 | node_modules 9 | 10 | # Nuxt build 11 | .nuxt 12 | 13 | # Nuxt generate 14 | wwwroot -------------------------------------------------------------------------------- /TechStacks/.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | root: true, 3 | env: { 4 | browser: true, 5 | node: true 6 | }, 7 | parserOptions: { 8 | parser: 'babel-eslint' 9 | }, 10 | extends: [ 11 | // https://github.com/vuejs/eslint-plugin-vue#priority-a-essential-error-prevention 12 | // consider switching to `plugin:vue/strongly-recommended` or `plugin:vue/recommended` for stricter rules. 13 | 'plugin:vue/essential', 14 | ], 15 | // required to lint *.vue files 16 | plugins: [ 17 | 'vue' 18 | ], 19 | // add your custom rules here 20 | rules: {} 21 | } 22 | -------------------------------------------------------------------------------- /TechStacks/App_Data/key-7f431195-db42-4e64-b957-08ab5ed23024.xml: -------------------------------------------------------------------------------- 1 |  2 | 3 | 2024-01-20T09:46:03.3414751Z 4 | 2024-01-20T09:46:03.3372926Z 5 | 2024-04-19T09:46:03.3372926Z 6 | 7 | 8 | 9 | 10 | 11 | 12 | N5WIms/3DSTZvY2gT5Fzif9pGzgJRMSx5SCwBoyDzorNHL2k3LH183/OnPaWuMw4KvPBKPZ6wBr+JLS215DYlw== 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /TechStacks/Areas/Identity/Pages/Account/AccessDenied.cshtml: -------------------------------------------------------------------------------- 1 | @page 2 | @model AccessDeniedModel 3 | @{ 4 | ViewData["Title"] = "Access denied"; 5 | } 6 | 7 |
8 |
9 |

@ViewData["Title"]

10 |

You do not have access to this resource.

11 |
12 |
13 | -------------------------------------------------------------------------------- /TechStacks/Areas/Identity/Pages/Account/AccessDenied.cshtml.cs: -------------------------------------------------------------------------------- 1 | // Licensed to the .NET Foundation under one or more agreements. 2 | // The .NET Foundation licenses this file to you under the MIT license. 3 | #nullable disable 4 | 5 | using Microsoft.AspNetCore.Mvc.RazorPages; 6 | 7 | namespace TechStacks.Areas.Identity.Pages.Account 8 | { 9 | /// 10 | /// This API supports the ASP.NET Core Identity default UI infrastructure and is not intended to be used 11 | /// directly from your code. This API may change or be removed in future releases. 12 | /// 13 | public class AccessDeniedModel : PageModel 14 | { 15 | /// 16 | /// This API supports the ASP.NET Core Identity default UI infrastructure and is not intended to be used 17 | /// directly from your code. This API may change or be removed in future releases. 18 | /// 19 | public void OnGet() 20 | { 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /TechStacks/Areas/Identity/Pages/Account/ConfirmEmail.cshtml: -------------------------------------------------------------------------------- 1 | @page 2 | @model ConfirmEmailModel 3 | @{ 4 | ViewData["Title"] = "Confirm email"; 5 | } 6 | 7 |
8 |
9 |

@ViewData["Title"]

10 |

Thank you for confirming your email.

11 |
12 |
13 | -------------------------------------------------------------------------------- /TechStacks/Areas/Identity/Pages/Account/ConfirmEmail.cshtml.cs: -------------------------------------------------------------------------------- 1 | // Licensed to the .NET Foundation under one or more agreements. 2 | // The .NET Foundation licenses this file to you under the MIT license. 3 | #nullable disable 4 | 5 | using System; 6 | using System.Linq; 7 | using System.Text; 8 | using System.Threading.Tasks; 9 | using Microsoft.AspNetCore.Authorization; 10 | using Microsoft.AspNetCore.Identity; 11 | using Microsoft.AspNetCore.Mvc; 12 | using Microsoft.AspNetCore.Mvc.RazorPages; 13 | using Microsoft.AspNetCore.WebUtilities; 14 | using TechStacks.Data; 15 | 16 | namespace TechStacks.Areas.Identity.Pages.Account 17 | { 18 | public class ConfirmEmailModel : PageModel 19 | { 20 | private readonly UserManager _userManager; 21 | 22 | public ConfirmEmailModel(UserManager userManager) 23 | { 24 | _userManager = userManager; 25 | } 26 | 27 | /// 28 | /// This API supports the ASP.NET Core Identity default UI infrastructure and is not intended to be used 29 | /// directly from your code. This API may change or be removed in future releases. 30 | /// 31 | [TempData] 32 | public string StatusMessage { get; set; } 33 | public async Task OnGetAsync(string userId, string code) 34 | { 35 | if (userId == null || code == null) 36 | { 37 | return RedirectToPage("/Index"); 38 | } 39 | 40 | var user = await _userManager.FindByIdAsync(userId); 41 | if (user == null) 42 | { 43 | return NotFound($"Unable to load user with ID '{userId}'."); 44 | } 45 | 46 | code = Encoding.UTF8.GetString(WebEncoders.Base64UrlDecode(code)); 47 | var result = await _userManager.ConfirmEmailAsync(user, code); 48 | StatusMessage = result.Succeeded ? "Thank you for confirming your email." : "Error confirming your email."; 49 | return Page(); 50 | } 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /TechStacks/Areas/Identity/Pages/Account/ConfirmEmailChange.cshtml: -------------------------------------------------------------------------------- 1 | @page 2 | @model ConfirmEmailChangeModel 3 | @{ 4 | ViewData["Title"] = "Confirm email change"; 5 | } 6 | 7 |
8 |
9 |

@ViewData["Title"]

10 | 11 |
12 |
13 | -------------------------------------------------------------------------------- /TechStacks/Areas/Identity/Pages/Account/ExternalLogin.cshtml: -------------------------------------------------------------------------------- 1 | @page 2 | @model ExternalLoginModel 3 | @{ 4 | ViewData["Title"] = "Register"; 5 | } 6 | 7 |
8 |
9 |

@ViewData["Title"]

10 |

Associate your @Model.ProviderDisplayName account.

11 |
12 | 13 | @await Html.PartialAsync("AlertInfo", $@"You've successfully authenticated with {Model.ProviderDisplayName}. 14 | Please enter an email address for this site below and click the Register button to finish 15 | logging in.") 16 | 17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 | 25 |
26 | 27 |
28 |

29 |
30 |
31 |
32 | 33 |
34 |
35 |
36 |
37 |
38 |
39 | 40 | @section Scripts { 41 | 42 | } 43 | -------------------------------------------------------------------------------- /TechStacks/Areas/Identity/Pages/Account/ForgotPassword.cshtml: -------------------------------------------------------------------------------- 1 | @page 2 | @model ForgotPasswordModel 3 | @{ 4 | ViewData["Title"] = "Forgot your password?"; 5 | } 6 | 7 |
8 |
9 |

10 | @ViewData["Title"] 11 |

12 |
13 |
14 |
15 |
16 |
17 |
18 | 19 |
20 | 21 |
22 |

23 |
24 |
25 |
26 | 27 |
28 |
29 |
30 |
31 |
32 |
33 | 34 | @section Scripts { 35 | 36 | } 37 | -------------------------------------------------------------------------------- /TechStacks/Areas/Identity/Pages/Account/ForgotPasswordConfirmation.cshtml: -------------------------------------------------------------------------------- 1 | @page 2 | @model ForgotPasswordConfirmation 3 | @{ 4 | ViewData["Title"] = "Forgot password confirmation"; 5 | } 6 | 7 | 8 |
9 |
10 |

@ViewData["Title"]

11 |

Please check your email to reset your password.

12 |
13 |
14 | -------------------------------------------------------------------------------- /TechStacks/Areas/Identity/Pages/Account/ForgotPasswordConfirmation.cshtml.cs: -------------------------------------------------------------------------------- 1 | // Licensed to the .NET Foundation under one or more agreements. 2 | // The .NET Foundation licenses this file to you under the MIT license. 3 | #nullable disable 4 | 5 | using Microsoft.AspNetCore.Authorization; 6 | using Microsoft.AspNetCore.Mvc.RazorPages; 7 | 8 | namespace TechStacks.Areas.Identity.Pages.Account 9 | { 10 | /// 11 | /// This API supports the ASP.NET Core Identity default UI infrastructure and is not intended to be used 12 | /// directly from your code. This API may change or be removed in future releases. 13 | /// 14 | [AllowAnonymous] 15 | public class ForgotPasswordConfirmation : PageModel 16 | { 17 | /// 18 | /// This API supports the ASP.NET Core Identity default UI infrastructure and is not intended to be used 19 | /// directly from your code. This API may change or be removed in future releases. 20 | /// 21 | public void OnGet() 22 | { 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /TechStacks/Areas/Identity/Pages/Account/Lockout.cshtml: -------------------------------------------------------------------------------- 1 | @page 2 | @model LockoutModel 3 | @{ 4 | ViewData["Title"] = "Locked out"; 5 | } 6 | 7 |
8 |
9 |

@ViewData["Title"]

10 |

This account has been locked out, please try again later.

11 |
12 |
13 | -------------------------------------------------------------------------------- /TechStacks/Areas/Identity/Pages/Account/Lockout.cshtml.cs: -------------------------------------------------------------------------------- 1 | // Licensed to the .NET Foundation under one or more agreements. 2 | // The .NET Foundation licenses this file to you under the MIT license. 3 | #nullable disable 4 | 5 | using Microsoft.AspNetCore.Authorization; 6 | using Microsoft.AspNetCore.Mvc.RazorPages; 7 | 8 | namespace TechStacks.Areas.Identity.Pages.Account 9 | { 10 | /// 11 | /// This API supports the ASP.NET Core Identity default UI infrastructure and is not intended to be used 12 | /// directly from your code. This API may change or be removed in future releases. 13 | /// 14 | [AllowAnonymous] 15 | public class LockoutModel : PageModel 16 | { 17 | /// 18 | /// This API supports the ASP.NET Core Identity default UI infrastructure and is not intended to be used 19 | /// directly from your code. This API may change or be removed in future releases. 20 | /// 21 | public void OnGet() 22 | { 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /TechStacks/Areas/Identity/Pages/Account/LoginWithRecoveryCode.cshtml: -------------------------------------------------------------------------------- 1 | @page 2 | @model LoginWithRecoveryCodeModel 3 | @{ 4 | ViewData["Title"] = "Recovery code verification"; 5 | } 6 | 7 |
8 |

@ViewData["Title"]

9 | 10 |

11 | You have requested to log in with a recovery code. This login will not be remembered until you provide 12 | an authenticator app code at log in or disable 2FA and log in again. 13 |

14 |
15 |
16 |
17 | 18 |
19 |
20 | 21 |
22 | 23 |
24 | 25 |
26 |
27 | 28 |
29 |
30 |
31 |
32 |
33 |
34 | 35 | @section Scripts { 36 | 37 | } -------------------------------------------------------------------------------- /TechStacks/Areas/Identity/Pages/Account/Logout.cshtml: -------------------------------------------------------------------------------- 1 | @page 2 | @model LogoutModel 3 | @{ 4 | ViewData["Title"] = "Signed out"; 5 | } 6 | 7 |
8 |
9 |

@ViewData["Title"]

10 |

You have successfully signed out.

11 |
12 |
13 | -------------------------------------------------------------------------------- /TechStacks/Areas/Identity/Pages/Account/Logout.cshtml.cs: -------------------------------------------------------------------------------- 1 | // Licensed to the .NET Foundation under one or more agreements. 2 | // The .NET Foundation licenses this file to you under the MIT license. 3 | #nullable disable 4 | 5 | using System; 6 | using System.Threading.Tasks; 7 | using Microsoft.AspNetCore.Authorization; 8 | using Microsoft.AspNetCore.Identity; 9 | using Microsoft.AspNetCore.Mvc; 10 | using Microsoft.AspNetCore.Mvc.RazorPages; 11 | using Microsoft.Extensions.Logging; 12 | using TechStacks.Data; 13 | 14 | namespace TechStacks.Areas.Identity.Pages.Account 15 | { 16 | public class LogoutModel : PageModel 17 | { 18 | private readonly SignInManager _signInManager; 19 | private readonly ILogger _logger; 20 | 21 | public LogoutModel(SignInManager signInManager, ILogger logger) 22 | { 23 | _signInManager = signInManager; 24 | _logger = logger; 25 | } 26 | 27 | public async Task OnPost(string returnUrl = null) 28 | { 29 | await _signInManager.SignOutAsync(); 30 | _logger.LogInformation("User logged out."); 31 | if (returnUrl != null) 32 | { 33 | return LocalRedirect(returnUrl); 34 | } 35 | else 36 | { 37 | // This needs to be a redirect so that the browser performs a new 38 | // request and the identity for the user gets updated. 39 | return RedirectToPage(); 40 | } 41 | } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /TechStacks/Areas/Identity/Pages/Account/Manage/DeletePersonalData.cshtml: -------------------------------------------------------------------------------- 1 | @page 2 | @model DeletePersonalDataModel 3 | @{ 4 | ViewData["Title"] = "Delete Personal Data"; 5 | ViewData["ActivePage"] = ManageNavPages.PersonalData; 6 | } 7 | 8 |

@ViewData["Title"]

9 | 10 | @await Html.PartialAsync("AlertError", "Deleting this data permanently removes your account, and cannot be recovered.") 11 | 12 |
13 |
14 | 15 | @if (Model.RequirePassword) 16 | { 17 |
18 |
19 |
20 | 21 |
22 | 23 |
24 | 25 |
26 |
27 |
28 | 29 | } 30 |
31 | 32 |
33 |
34 |
35 | 36 | @section Scripts { 37 | 38 | } 39 | -------------------------------------------------------------------------------- /TechStacks/Areas/Identity/Pages/Account/Manage/Disable2fa.cshtml: -------------------------------------------------------------------------------- 1 | @page 2 | @model Disable2faModel 3 | @{ 4 | ViewData["Title"] = "Disable two-factor authentication (2FA)"; 5 | ViewData["ActivePage"] = ManageNavPages.TwoFactorAuthentication; 6 | } 7 | 8 | 9 | 10 |

11 | @ViewData["Title"] 12 |

13 | 14 | 24 | 25 |
26 |
27 | 28 |
29 |
30 | -------------------------------------------------------------------------------- /TechStacks/Areas/Identity/Pages/Account/Manage/DownloadPersonalData.cshtml: -------------------------------------------------------------------------------- 1 | @page 2 | @model DownloadPersonalDataModel 3 | @{ 4 | ViewData["Title"] = "Download Your Data"; 5 | ViewData["ActivePage"] = ManageNavPages.PersonalData; 6 | } 7 | 8 |

@ViewData["Title"]

9 | 10 | @section Scripts { 11 | 12 | } 13 | -------------------------------------------------------------------------------- /TechStacks/Areas/Identity/Pages/Account/Manage/ExternalLogins.cshtml: -------------------------------------------------------------------------------- 1 | @page 2 | @model ExternalLoginsModel 3 | @{ 4 | ViewData["Title"] = "Manage your external logins"; 5 | ViewData["ActivePage"] = ManageNavPages.ExternalLogins; 6 | } 7 | 8 | 9 | @if (Model.CurrentLogins?.Count > 0) 10 | { 11 |

Registered Logins

12 | 13 | 14 | @foreach (var login in Model.CurrentLogins) 15 | { 16 | 17 | 18 | 34 | 35 | } 36 | 37 |
@login.ProviderDisplayName 19 | @if (Model.ShowRemoveButton) 20 | { 21 |
22 |
23 | 24 | 25 | 26 |
27 |
28 | } 29 | else 30 | { 31 | @:   32 | } 33 |
38 | } 39 | @if (Model.OtherLogins?.Count > 0) 40 | { 41 |

Add another service to log in.

42 |
43 | 53 | } 54 | -------------------------------------------------------------------------------- /TechStacks/Areas/Identity/Pages/Account/Manage/GenerateRecoveryCodes.cshtml: -------------------------------------------------------------------------------- 1 | @page 2 | @model GenerateRecoveryCodesModel 3 | @{ 4 | ViewData["Title"] = "Generate two-factor authentication (2FA) recovery codes"; 5 | ViewData["ActivePage"] = ManageNavPages.TwoFactorAuthentication; 6 | } 7 | 8 | 9 | 10 |

11 | @ViewData["Title"] 12 |

13 | 14 | 27 | 28 |
29 |
30 | 31 |
32 |
33 | -------------------------------------------------------------------------------- /TechStacks/Areas/Identity/Pages/Account/Manage/Index.cshtml: -------------------------------------------------------------------------------- 1 | @page 2 | @model IndexModel 3 | @{ 4 | ViewData["Title"] = "Profile"; 5 | ViewData["ActivePage"] = ManageNavPages.Index; 6 | } 7 | 8 |
9 |
10 |

11 | @ViewData["Title"] 12 |

13 |
14 | @await Html.PartialAsync("_StatusMessage", Model.StatusMessage) 15 |
16 |
17 |
18 |
19 |
20 |
21 | 22 |
23 | 24 |
25 |
26 |
27 | 28 |
29 | 30 |
31 | 32 |
33 |
34 | 35 |
36 |
37 |
38 |
39 |
40 |
41 | 42 | @section Scripts { 43 | 44 | } 45 | -------------------------------------------------------------------------------- /TechStacks/Areas/Identity/Pages/Account/Manage/PersonalData.cshtml: -------------------------------------------------------------------------------- 1 | @page 2 | @model PersonalDataModel 3 | @{ 4 | ViewData["Title"] = "Personal Data"; 5 | ViewData["ActivePage"] = ManageNavPages.PersonalData; 6 | } 7 | 8 |

@ViewData["Title"]

9 | 10 |
11 |
12 |

Your account contains personal data that you have given us. This page allows you to download or delete that data.

13 |

14 | Deleting this data will permanently remove your account, and this cannot be recovered. 15 |

16 |
17 | 18 |
19 |

20 | Delete 21 |

22 |
23 |
24 | 25 | @section Scripts { 26 | 27 | } 28 | -------------------------------------------------------------------------------- /TechStacks/Areas/Identity/Pages/Account/Manage/PersonalData.cshtml.cs: -------------------------------------------------------------------------------- 1 | // Licensed to the .NET Foundation under one or more agreements. 2 | // The .NET Foundation licenses this file to you under the MIT license. 3 | using System; 4 | using System.Threading.Tasks; 5 | using Microsoft.AspNetCore.Identity; 6 | using Microsoft.AspNetCore.Mvc; 7 | using Microsoft.AspNetCore.Mvc.RazorPages; 8 | using Microsoft.Extensions.Logging; 9 | using TechStacks.Data; 10 | 11 | namespace TechStacks.Areas.Identity.Pages.Account.Manage 12 | { 13 | public class PersonalDataModel : PageModel 14 | { 15 | private readonly UserManager _userManager; 16 | private readonly ILogger _logger; 17 | 18 | public PersonalDataModel( 19 | UserManager userManager, 20 | ILogger logger) 21 | { 22 | _userManager = userManager; 23 | _logger = logger; 24 | } 25 | 26 | public async Task OnGet() 27 | { 28 | var user = await _userManager.GetUserAsync(User); 29 | if (user == null) 30 | { 31 | return NotFound($"Unable to load user with ID '{_userManager.GetUserId(User)}'."); 32 | } 33 | 34 | return Page(); 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /TechStacks/Areas/Identity/Pages/Account/Manage/ResetAuthenticator.cshtml: -------------------------------------------------------------------------------- 1 | @page 2 | @model ResetAuthenticatorModel 3 | @{ 4 | ViewData["Title"] = "Reset authenticator key"; 5 | ViewData["ActivePage"] = ManageNavPages.TwoFactorAuthentication; 6 | } 7 | 8 | 9 |

10 | @ViewData["Title"] 11 |

12 | 21 |
22 |
23 | 24 |
25 |
26 | -------------------------------------------------------------------------------- /TechStacks/Areas/Identity/Pages/Account/Manage/SetPassword.cshtml: -------------------------------------------------------------------------------- 1 | @page 2 | @model SetPasswordModel 3 | @{ 4 | ViewData["Title"] = "Set password"; 5 | ViewData["ActivePage"] = ManageNavPages.ChangePassword; 6 | } 7 | 8 |

Set your password

9 | 10 |
11 | 12 | 13 | @await Html.PartialAsync("AlertInfo", @"You do not have a local username/password for this site. 14 | Add a local account so you can log in without an external login.") 15 | 16 |
17 |
18 |
19 | 20 | 21 |
22 |
23 | 24 |
25 | 26 |
27 | 28 |
29 |
30 | 31 |
32 | 33 |
34 | 35 |
36 |
37 | 38 |
39 |
40 |
41 |
42 |
43 |
44 | 45 | 46 | @section Scripts { 47 | 48 | } 49 | -------------------------------------------------------------------------------- /TechStacks/Areas/Identity/Pages/Account/Manage/ShowRecoveryCodes.cshtml: -------------------------------------------------------------------------------- 1 | @page 2 | @model ShowRecoveryCodesModel 3 | @{ 4 | ViewData["Title"] = "Recovery codes"; 5 | ViewData["ActivePage"] = "TwoFactorAuthentication"; 6 | } 7 | 8 |

@ViewData["Title"]

9 |
10 | 11 | 12 |

13 | Put these codes in a safe place. 14 |

15 | @await Html.PartialAsync("AlertWarning", "If you lose your device and don't have the recovery codes you will lose access to your account.") 16 | 17 |
18 | @for (var row = 0; row < Model.RecoveryCodes.Length; row += 2) 19 | { 20 | @Model.RecoveryCodes[row] 21 | 22 |   23 | 24 | @Model.RecoveryCodes[row + 1] 25 | 26 |
27 | } 28 |
29 |
30 | -------------------------------------------------------------------------------- /TechStacks/Areas/Identity/Pages/Account/Manage/ShowRecoveryCodes.cshtml.cs: -------------------------------------------------------------------------------- 1 | // Licensed to the .NET Foundation under one or more agreements. 2 | // The .NET Foundation licenses this file to you under the MIT license. 3 | #nullable disable 4 | 5 | using Microsoft.AspNetCore.Identity; 6 | using Microsoft.AspNetCore.Mvc; 7 | using Microsoft.AspNetCore.Mvc.RazorPages; 8 | using Microsoft.Extensions.Logging; 9 | using TechStacks.Data; 10 | 11 | namespace TechStacks.Areas.Identity.Pages.Account.Manage 12 | { 13 | /// 14 | /// This API supports the ASP.NET Core Identity default UI infrastructure and is not intended to be used 15 | /// directly from your code. This API may change or be removed in future releases. 16 | /// 17 | public class ShowRecoveryCodesModel : PageModel 18 | { 19 | /// 20 | /// This API supports the ASP.NET Core Identity default UI infrastructure and is not intended to be used 21 | /// directly from your code. This API may change or be removed in future releases. 22 | /// 23 | [TempData] 24 | public string[] RecoveryCodes { get; set; } 25 | 26 | /// 27 | /// This API supports the ASP.NET Core Identity default UI infrastructure and is not intended to be used 28 | /// directly from your code. This API may change or be removed in future releases. 29 | /// 30 | [TempData] 31 | public string StatusMessage { get; set; } 32 | 33 | /// 34 | /// This API supports the ASP.NET Core Identity default UI infrastructure and is not intended to be used 35 | /// directly from your code. This API may change or be removed in future releases. 36 | /// 37 | public IActionResult OnGet() 38 | { 39 | if (RecoveryCodes == null || RecoveryCodes.Length == 0) 40 | { 41 | return RedirectToPage("./TwoFactorAuthentication"); 42 | } 43 | 44 | return Page(); 45 | } 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /TechStacks/Areas/Identity/Pages/Account/Manage/_Layout.cshtml: -------------------------------------------------------------------------------- 1 | @{ 2 | if (ViewData.TryGetValue("ParentLayout", out var parentLayout) && parentLayout != null) 3 | { 4 | Layout = parentLayout.ToString(); 5 | } 6 | else 7 | { 8 | // Layout = "/Areas/Identity/Pages/_Layout.cshtml"; 9 | Layout = "/Pages/Shared/_Layout.cshtml"; 10 | } 11 | } 12 | 13 |
14 |

Manage your account

15 |
16 | 17 |
18 |

Change your account settings

19 |
20 |
21 |
22 | @await Html.PartialAsync("_ManageNav") 23 |
24 |
25 | @RenderBody() 26 |
27 |
28 |
29 | 30 | @section Scripts { 31 | @await RenderSectionAsync("Scripts", required: false) 32 | } 33 | -------------------------------------------------------------------------------- /TechStacks/Areas/Identity/Pages/Account/Manage/_ManageNav.cshtml: -------------------------------------------------------------------------------- 1 | @using TechStacks.Data 2 | @inject SignInManager SignInManager 3 | @{ 4 | var hasExternalLogins = (await SignInManager.GetExternalAuthenticationSchemesAsync()).Any(); 5 | var navItemCss = "text-gray-600 dark:text-gray-300 hover:bg-gray-50 dark:hover:bg-gray-900 hover:text-gray-900 dark:hover:text-gray-50 group flex items-center px-4 py-2 text-base font-medium rounded-md mr-2 whitespace-nowrap"; 6 | } 7 | 8 | 31 | -------------------------------------------------------------------------------- /TechStacks/Areas/Identity/Pages/Account/Manage/_ViewImports.cshtml: -------------------------------------------------------------------------------- 1 | @using TechStacks.Areas.Identity.Pages.Account.Manage 2 | @using ServiceStack 3 | @using ServiceStack.Mvc 4 | -------------------------------------------------------------------------------- /TechStacks/Areas/Identity/Pages/Account/Manage/_ViewStart.cshtml: -------------------------------------------------------------------------------- 1 | @{ 2 | ViewData["ParentLayout"] = Layout; 3 | Layout = "_Layout.cshtml"; 4 | } -------------------------------------------------------------------------------- /TechStacks/Areas/Identity/Pages/Account/RegisterConfirmation.cshtml: -------------------------------------------------------------------------------- 1 | @page 2 | @model RegisterConfirmationModel 3 | @{ 4 | ViewData["Title"] = "Register confirmation"; 5 | } 6 | 7 |
8 |

Register confirmation

9 | 10 | @if (@Model.DisplayConfirmAccountLink) 11 | { 12 |

13 | This app does not currently have a real email sender registered, see 14 | these docs for how to configure a real email sender. 15 |

16 |

17 | Normally this would be emailed: 18 | Click here to confirm your account 19 |

20 | } 21 | else 22 | { 23 |

Please check your email to confirm your account.

24 | } 25 |
26 | -------------------------------------------------------------------------------- /TechStacks/Areas/Identity/Pages/Account/ResendEmailConfirmation.cshtml: -------------------------------------------------------------------------------- 1 | @page 2 | @model ResendEmailConfirmationModel 3 | @{ 4 | ViewData["Title"] = "Resend email confirmation"; 5 | } 6 | 7 |
8 |

Resend email confirmation

9 |

Enter your email.

10 | 11 |
12 | 13 |
14 |
15 | 16 |
17 | 18 |
19 | 20 |
21 |
22 | 23 |
24 |
25 |
26 |
27 | 28 | @section Scripts { 29 | 30 | } 31 | -------------------------------------------------------------------------------- /TechStacks/Areas/Identity/Pages/Account/ResetPasswordConfirmation.cshtml: -------------------------------------------------------------------------------- 1 | @page 2 | @model ResetPasswordConfirmationModel 3 | @{ 4 | ViewData["Title"] = "Reset password confirmation"; 5 | } 6 | 7 |
8 |
9 |

@ViewData["Title"]

10 |

11 | Your password has been reset. Please click here to log in. 12 |

13 |
14 |
15 | -------------------------------------------------------------------------------- /TechStacks/Areas/Identity/Pages/Account/ResetPasswordConfirmation.cshtml.cs: -------------------------------------------------------------------------------- 1 | // Licensed to the .NET Foundation under one or more agreements. 2 | // The .NET Foundation licenses this file to you under the MIT license. 3 | #nullable disable 4 | 5 | using Microsoft.AspNetCore.Authorization; 6 | using Microsoft.AspNetCore.Mvc.RazorPages; 7 | 8 | namespace TechStacks.Areas.Identity.Pages.Account 9 | { 10 | /// 11 | /// This API supports the ASP.NET Core Identity default UI infrastructure and is not intended to be used 12 | /// directly from your code. This API may change or be removed in future releases. 13 | /// 14 | [AllowAnonymous] 15 | public class ResetPasswordConfirmationModel : PageModel 16 | { 17 | /// 18 | /// This API supports the ASP.NET Core Identity default UI infrastructure and is not intended to be used 19 | /// directly from your code. This API may change or be removed in future releases. 20 | /// 21 | public void OnGet() 22 | { 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /TechStacks/Areas/Identity/Pages/Account/_StatusMessage.cshtml: -------------------------------------------------------------------------------- 1 | @model string 2 | 3 | @if (!string.IsNullOrEmpty(Model)) 4 | { 5 | var statusMessageClass = Model.StartsWith("Error") ? Css.AlertDanger : Css.AlertSuccess; 6 | 9 | } 10 | -------------------------------------------------------------------------------- /TechStacks/Areas/Identity/Pages/Account/_ViewImports.cshtml: -------------------------------------------------------------------------------- 1 | @using TechStacks.Areas.Identity.Pages.Account 2 | -------------------------------------------------------------------------------- /TechStacks/Areas/Identity/Pages/_ValidationScriptsPartial.cshtml: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 12 | 18 | 19 | -------------------------------------------------------------------------------- /TechStacks/Areas/Identity/Pages/_ViewImports.cshtml: -------------------------------------------------------------------------------- 1 | @using Microsoft.AspNetCore.Identity 2 | @using TechStacks.Areas.Identity 3 | @using TechStacks.Areas.Identity.Pages 4 | @addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers 5 | @using TechStacks.Data 6 | -------------------------------------------------------------------------------- /TechStacks/Areas/Identity/Pages/_ViewStart.cshtml: -------------------------------------------------------------------------------- 1 | 2 | @{ 3 | Layout = "/Pages/Shared/_Layout.cshtml"; 4 | } 5 | -------------------------------------------------------------------------------- /TechStacks/Configure.Cors.cs: -------------------------------------------------------------------------------- 1 | [assembly: HostingStartup(typeof(MyApp.ConfigureCors))] 2 | 3 | namespace MyApp; 4 | 5 | public class ConfigureCors : IHostingStartup 6 | { 7 | public void Configure(IWebHostBuilder builder) => builder 8 | .ConfigureServices(services => 9 | { 10 | services.AddCors(options => { 11 | options.AddDefaultPolicy(policy => { 12 | policy.WithOrigins([ 13 | "http://localhost:5000", "https://localhost:5001", "http://localhost:8080", 14 | "https://localhost:5173", "http://localhost:5173", 15 | "http://run.plnkr.co", "http://null.jsbin.com", 16 | ]) 17 | .AllowCredentials() 18 | .WithHeaders(["Content-Type", "Allow", "Authorization"]) 19 | .SetPreflightMaxAge(TimeSpan.FromHours(1)); 20 | }); 21 | }); 22 | services.AddTransient(); 23 | }); 24 | 25 | public class StartupFilter : IStartupFilter 26 | { 27 | public Action Configure(Action next) => app => 28 | { 29 | app.UseCors(); 30 | next(app); 31 | }; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /TechStacks/Configure.Markdown.cs: -------------------------------------------------------------------------------- 1 | #nullable enable 2 | using Markdig; 3 | using Markdig.Syntax; 4 | using Microsoft.AspNetCore.Mvc.Rendering; 5 | using ServiceStack; 6 | using ServiceStack.IO; 7 | using TechStacks.ServiceInterface; 8 | 9 | [assembly: HostingStartup(typeof(TechStacks.ConfigureSsg))] 10 | 11 | namespace TechStacks; 12 | 13 | public class ConfigureSsg : IHostingStartup 14 | { 15 | public void Configure(IWebHostBuilder builder) => builder 16 | .ConfigureServices(services => { 17 | services.AddSingleton(); 18 | }); 19 | } 20 | -------------------------------------------------------------------------------- /TechStacks/Configure.RequestLogs.cs: -------------------------------------------------------------------------------- 1 | using ServiceStack; 2 | using ServiceStack.Jobs; 3 | using ServiceStack.Web; 4 | 5 | [assembly: HostingStartup(typeof(AiServer.ConfigureRequestLogs))] 6 | 7 | namespace AiServer; 8 | 9 | public class ConfigureRequestLogs : IHostingStartup 10 | { 11 | public void Configure(IWebHostBuilder builder) => builder 12 | .ConfigureServices((context, services) => { 13 | 14 | services.AddPlugin(new RequestLogsFeature { 15 | RequestLogger = new SqliteRequestLogger(), 16 | // EnableResponseTracking = true, 17 | EnableRequestBodyTracking = true, 18 | EnableErrorTracking = true 19 | }); 20 | services.AddHostedService(); 21 | }); 22 | } 23 | 24 | public class RequestLogsHostedService(ILogger log, IRequestLogger requestLogger) : BackgroundService 25 | { 26 | protected override async Task ExecuteAsync(CancellationToken stoppingToken) 27 | { 28 | var dbRequestLogger = (SqliteRequestLogger)requestLogger; 29 | using var timer = new PeriodicTimer(TimeSpan.FromSeconds(3)); 30 | while (!stoppingToken.IsCancellationRequested && await timer.WaitForNextTickAsync(stoppingToken)) 31 | { 32 | dbRequestLogger.Tick(log); 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /TechStacks/Pages/Shared/AlertError.cshtml: -------------------------------------------------------------------------------- 1 | @page 2 | @model string 3 | 4 |
5 |
6 |
7 | 10 |
11 |
12 | @Html.Raw(Model) 13 |
14 |
15 |
16 | -------------------------------------------------------------------------------- /TechStacks/Pages/Shared/AlertInfo.cshtml: -------------------------------------------------------------------------------- 1 | @page 2 | @model string 3 | 4 |
5 |
6 |
7 | 10 |
11 |
12 | @Html.Raw(Model) 13 |
14 |
15 |
16 | -------------------------------------------------------------------------------- /TechStacks/Pages/Shared/AlertWarning.cshtml: -------------------------------------------------------------------------------- 1 | @page 2 | @model string 3 | 4 |
5 |
6 |
7 | 10 |
11 |
12 | @Html.Raw(Model) 13 |
14 |
15 |
16 | -------------------------------------------------------------------------------- /TechStacks/Pages/Shared/Footer.cshtml: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /TechStacks/Pages/Shared/Forbidden.cshtml: -------------------------------------------------------------------------------- 1 | @page 2 | @model string 3 | 4 | @{ 5 | ViewData["Title"] = "Forbidden"; 6 | } 7 | 8 |
9 |
10 |

403

11 |
12 |

You are not authorized to access this page.

13 |
@Model
14 |
15 |
16 |
17 | -------------------------------------------------------------------------------- /TechStacks/Pages/Shared/_Layout.cshtml: -------------------------------------------------------------------------------- 1 | @inherits Microsoft.AspNetCore.Mvc.Razor.RazorPage 2 | 3 | 4 | @{ 5 | var dev = HostContext.AppHost.IsDevelopmentEnvironment(); 6 | } 7 | 8 | 9 | 10 | 11 | @ViewData["Title"] - My App 12 | 13 | 14 | 15 | @Html.ImportMap(new() 16 | { 17 | ["@servicestack/client"] = ("/lib/mjs/servicestack-client.mjs", "/lib/mjs/servicestack-client.min.mjs"), 18 | }) 19 | @await RenderSectionAsync("head", required: false) 20 | 21 | 22 | @await Html.PartialAsync("Header") 23 | 24 |
25 |
26 | @RenderBody() 27 |
28 |
29 | 30 | @await Html.PartialAsync("Footer") 31 | 32 | 33 | 34 | 35 | 36 | 41 | 42 | 43 | @await RenderSectionAsync("Scripts", required: false) 44 | 45 | 46 | 47 | -------------------------------------------------------------------------------- /TechStacks/Pages/_ViewImports.cshtml: -------------------------------------------------------------------------------- 1 | @inherits ServiceStack.Mvc.RazorPage 2 | 3 | @using Microsoft.AspNetCore.Authorization 4 | @using ServiceStack 5 | @using ServiceStack.Mvc 6 | @using TechStacks 7 | @using TechStacks.ServiceModel 8 | @namespace TechStacks.Pages 9 | @addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers 10 | -------------------------------------------------------------------------------- /TechStacks/Pages/_ViewStart.cshtml: -------------------------------------------------------------------------------- 1 | @{ 2 | Layout = "_Layout"; 3 | } -------------------------------------------------------------------------------- /TechStacks/Properties/launchSettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "iisSettings": { 3 | "windowsAuthentication": false, 4 | "anonymousAuthentication": true, 5 | "iisExpress": { 6 | "applicationUrl": "https://localhost:5001/", 7 | "sslPort": 0 8 | } 9 | }, 10 | "profiles": { 11 | "IIS Express": { 12 | "commandName": "IISExpress", 13 | "launchBrowser": true, 14 | "environmentVariables": { 15 | "ASPNETCORE_ENVIRONMENT": "Development" 16 | } 17 | }, 18 | "TechStacks": { 19 | "commandName": "Project", 20 | "launchBrowser": true, 21 | "environmentVariables": { 22 | "ASPNETCORE_ENVIRONMENT": "Development" 23 | }, 24 | "applicationUrl": "https://localhost:5001/" 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /TechStacks/README.md: -------------------------------------------------------------------------------- 1 | # my-app 2 | 3 | > Nuxt.js project 4 | 5 | ## Build Setup 6 | 7 | ``` bash 8 | # install dependencies 9 | $ npm install # Or yarn install 10 | 11 | # serve with hot reload at localhost:3000 12 | $ npm run dev 13 | 14 | # build for production and launch server 15 | $ npm run build 16 | $ npm start 17 | 18 | # generate static project 19 | $ npm run generate 20 | ``` 21 | 22 | For detailed explanation on how things work, checkout the [Nuxt.js docs](https://github.com/nuxt/nuxt.js) -------------------------------------------------------------------------------- /TechStacks/appsettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "DetailedErrors": true, 3 | "Logging": { 4 | "LogLevel": { 5 | "Default": "Information", 6 | "Microsoft.AspNetCore": "Warning" 7 | } 8 | }, 9 | "PublicBaseUrl": "https://techstacks.io", 10 | "oauth.github.ClientId": "caa869a06686fe01ce36", 11 | "oauth.github.ClientSecret": "204c907f7df28443564fad0c2bef818077c8517f", 12 | "oauth.imgur.ClientId": "6c0323561c8d934", 13 | "oauth.imgur.ClientSecret": "88d14b5f2d7046021853d2725e938135e3b132ee", 14 | "Admins": [], 15 | "TwitterAdmins": [ "webstacks" ], 16 | "jwt.AuthKeyBase64": "7OrAw+Dc09cA9IimXvNf3ZFsHzD/iWE6AyPTYEhz17Y=", 17 | "smtp.Host": "email-smtp.us-east-1.amazonaws.com", 18 | "smtp.Port": 587, 19 | "smtp.Bcc": "techstacks@servicestack.net", 20 | "NotificationsFromEmail": "notifications@techstacks.io", 21 | "NotificationsCcEmail": "subscribed@noreply.techstacks.io", 22 | "SystemToEmail": "demis.bellot@gmail.com" 23 | } 24 | -------------------------------------------------------------------------------- /TechStacks/deploy.bat: -------------------------------------------------------------------------------- 1 | npm run deploy 2 | -------------------------------------------------------------------------------- /TechStacks/deploy.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | rsync -avz -e 'ssh' bin/Release/net6.0/publish/ deploy@ec2-34-232-4-72.compute-1.amazonaws.com:/home/deploy/apps/techstacks 3 | ssh deploy@ec2-34-232-4-72.compute-1.amazonaws.com "sudo supervisorctl restart app-techstacks" 4 | -------------------------------------------------------------------------------- /TechStacks/emails/comment-report.html: -------------------------------------------------------------------------------- 1 | {{ '{0}/comments/{1}/{2}' | fmt(baseUrl,comment.PostId,comment.Id) | assignTo: commentLink }} 2 | 3 |

4 | @{{ report.UserName }} reported this post as {{ report.FlagType }}: 5 | 6 | {{ report.ReportNotes | endIfEmpty | select:

{ it }
}} 7 |

8 | 9 | 10 | 11 | 14 | 15 |
12 | {{ comment.ContentHtml | raw }} 13 |
16 | 17 |

18 | This comment has been reported {{ comment.ReportCount }} time{{ 's' | if(notEquals(comment.ReportCount,1)) }} and 19 | {{ comment.Deleted | onlyIfNull | select: is Not Deleted. }} 20 | {{ comment.Deleted | endIfNull | select: was Deleted by {comment.DeletedBy}. }} 21 |

22 | 23 |

24 | —
25 | You are receiving this because you are a moderator for {{ organization.Name }}.
26 | You can view this comment on techstacks.io, or 27 | update your {{ organization.Name }} membership. 28 |

29 | -------------------------------------------------------------------------------- /TechStacks/emails/post-new.html: -------------------------------------------------------------------------------- 1 | {{ '{0}/posts/{1}/{2}' | fmt(baseUrl,post.Id,post.Slug) | assignTo: postLink }} 2 | 3 | {{ post.ImageUrl | endIfEmpty | select: }} 4 | 5 | {{ post.ContentHtml | raw }} 6 | 7 | {{ post.Content | endIfEmpty | use(post.Url) | endIfEmpty | select:

continue reading...

}} 8 | {{ post.Content | onlyIfEmpty | select:

New {post.Type} in {organization.Name}:

{post.Title}

}} 9 | 10 |

11 | —
12 | You are receiving this because you are subscribed to {{ organization.Name }}.
13 | You can view this on techstacks.io, or 14 | update your {{ organization.Name }} subscription. 15 |

16 | -------------------------------------------------------------------------------- /TechStacks/emails/post-report.html: -------------------------------------------------------------------------------- 1 | {{ '{0}/posts/{1}/{2}' | fmt(baseUrl,post.Id,post.Slug) | assignTo: postLink }} 2 | 3 |

4 | @{{ report.UserName }} reported this post as {{ report.FlagType }}: 5 | 6 | {{ report.ReportNotes | endIfEmpty | select:

{ it }
}} 7 |

8 | 9 | 10 | 11 | 18 | 19 |
12 | {{ post.ImageUrl | endIfEmpty | select: }} 13 | 14 | {{ post.ContentHtml | raw }} 15 | 16 | {{ post.Url | endIfEmpty | select:

continue reading...

}} 17 |
20 | 21 |

22 | This post has been reported {{ post.ReportCount }} time{{ 's' | if(notEquals(post.ReportCount,1)) }} and 23 | {{ post.Deleted | onlyIfNull | select: is Not Deleted. }} 24 | {{ post.Deleted | endIfNull | select: was Deleted by {post.DeletedBy}. }} 25 |

26 | 27 |

28 | —
29 | You are receiving this because you are a moderator for {{ organization.name }}.
30 | You can view this post on techstacks.io, or 31 | update your {{ organization.Name }} membership. 32 |

33 | -------------------------------------------------------------------------------- /TechStacks/nuxt.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | mode: 'spa', 3 | srcDir: 'src', 4 | generate: { 5 | dir: 'wwwroot', 6 | routes: [] 7 | }, 8 | plugins: [ 9 | '~/plugins/vuetify.js', 10 | { src: '~plugins/ga.js', ssr: false }, 11 | { src: '~/plugins/nuxt-client-init.js', ssr: false } 12 | ], 13 | router: { 14 | middleware: 'routes' 15 | }, 16 | modules: ['@nuxtjs/proxy'], 17 | proxy: { 18 | '/api': 'https://localhost:5001/', 19 | '/auth': 'https://localhost:5001/', 20 | '/users/*/avatar': 'https://localhost:5001/', 21 | }, 22 | css: ['~/assets/css/typography.css','~/assets/css/gfm.css','~/assets/css/styles.css'], 23 | /* 24 | ** Headers of the page 25 | */ 26 | head: { 27 | title: 'techstacks.io', 28 | meta: [ 29 | { charset: 'utf-8' }, 30 | { name: 'viewport', content: 'width=device-width, initial-scale=1' }, 31 | { hid: 'description', name: 'description', content: 'TechStacks lets you Discover the Hottest Technology Stacks of the most popular Startups and Apps using your favorite languages and technologies!' } 32 | ], 33 | link: [ 34 | { rel: 'icon', type: 'image/x-icon', href: '/favicon.ico' }, 35 | { rel: 'stylesheet', href: 'https://fonts.googleapis.com/css?family=Roboto:300,400,500,700|Material+Icons' } 36 | ] 37 | }, 38 | /* 39 | ** Customize the progress bar color 40 | */ 41 | loading: { color: '#3B8070' }, 42 | /* 43 | ** Build configuration 44 | */ 45 | build: { 46 | vendor: [ 47 | '~/plugins/vuetify.js' 48 | ], 49 | extractCSS: true, 50 | /* 51 | ** Run ESLint on save 52 | */ 53 | extend (config, { isDev, isClient }) { 54 | if (isDev && isClient) { 55 | config.module.rules.push({ 56 | enforce: 'pre', 57 | test: /\.(js|vue)$/, 58 | loader: 'eslint-loader', 59 | exclude: /(node_modules)/ 60 | }) 61 | } 62 | } 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /TechStacks/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "techstacks", 3 | "version": "1.0.0", 4 | "description": "ServiceStack Nuxt.js project", 5 | "private": true, 6 | "scripts": { 7 | "dev": "nuxt", 8 | "ui:dev": "npx tailwindcss@v3 -i ./tailwind.input.css -o ./wwwroot/css/app.css --watch", 9 | "ui:build": "npx tailwindcss@v3 -i ./tailwind.input.css -o ./wwwroot/css/app.css --minify", 10 | "dtos": "cd src/shared && x ts && tsc -m ES6 dtos.ts", 11 | "build": "shx cp wwwroot/css/app.css src/static/css/app.css && nuxt build", 12 | "publish": "nuxt build && dotnet publish -c Release", 13 | "deploy": "npm run publish && bash deploy.sh", 14 | "migrate": "dotnet run --AppTasks=migrate", 15 | "revert:last": "dotnet run --AppTasks=migrate.revert:last", 16 | "revert:all": "dotnet run --AppTasks=migrate.revert:all", 17 | "rerun:last": "npm run revert:last && npm run migrate", 18 | "lint": "eslint --ext .js,.vue .", 19 | "precommit": "npm run lint" 20 | }, 21 | "engines": { 22 | "node": ">=16.0.0 <17.0.0" 23 | }, 24 | "dependencies": { 25 | "@servicestack/client": "^2.0.17", 26 | "@servicestack/editor": "0.0.2", 27 | "@servicestack/images": "^1.0.0", 28 | "npm": "^9.2.0", 29 | "nuxt": "^1.4.5", 30 | "vuetify": "1.0" 31 | }, 32 | "devDependencies": { 33 | "@nuxtjs/proxy": "^1.3.3", 34 | "babel-eslint": "^8.2.3", 35 | "eslint": "^4.19.1", 36 | "eslint-friendly-formatter": "^4.0.1", 37 | "eslint-loader": "^2.0.0", 38 | "eslint-plugin-vue": "^4.7.1", 39 | "gulp": "^3.9.1", 40 | "shx": "^0.3.4", 41 | "typescript": "^4.9.4" 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /TechStacks/scripts/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "scripts", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "prerender.js", 6 | "scripts": { 7 | "prerender": "node prerender.js", 8 | "test": "echo \"Error: no test specified\" && exit 1" 9 | }, 10 | "author": "", 11 | "license": "ISC", 12 | "dependencies": { 13 | "delay": "^2.0.0", 14 | "node-fetch": "^2.1.1", 15 | "puppeteer": "^1.2.0" 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /TechStacks/scripts/server/install.txt: -------------------------------------------------------------------------------- 1 | # dotnet - https://www.microsoft.com/net/learn/get-started/linux/ubuntu16-04 2 | 3 | curl https://packages.microsoft.com/keys/microsoft.asc | gpg --dearmor > microsoft.gpg 4 | sudo mv microsoft.gpg /etc/apt/trusted.gpg.d/microsoft.gpg 5 | sudo sh -c 'echo "deb [arch=amd64] https://packages.microsoft.com/repos/microsoft-ubuntu-xenial-prod xenial main" > /etc/apt/sources.list.d/dotnetdev.list' 6 | 7 | sudo apt-get install apt-transport-https 8 | sudo apt-get update 9 | sudo apt-get install dotnet-sdk-2.1.101 10 | 11 | # node 12 | 13 | curl -sL https://deb.nodesource.com/setup_8.x | sudo -E bash - 14 | sudo apt-get install -y nodejs 15 | 16 | sudo apt-get install libpangocairo-1.0-0 libx11-xcb1 libxcomposite1 libxcursor1 libxdamage1 libxi6 libxtst6 libnss3 libcups2 libxss1 libxrandr2 libgconf2-4 libasound2 libatk1.0-0 libgtk-3-0 17 | 18 | # deploy.sh 19 | 20 | cd /home/deploy/apps/scripts/ 21 | npm install 22 | -------------------------------------------------------------------------------- /TechStacks/scripts/server/nginx/techstacks.netcore.io: -------------------------------------------------------------------------------- 1 | map $sent_http_content_type $expires { 2 | "text/html" epoch; 3 | "text/html; charset=utf-8" epoch; 4 | default off; 5 | } 6 | 7 | server { 8 | listen 80; 9 | server_name techstacks.netcore.io; 10 | 11 | gzip on; 12 | gzip_types text/plain application/xml text/css application/javascript; 13 | gzip_min_length 1000; 14 | 15 | 16 | location = /prerender { 17 | return 302 /prerender/; 18 | } 19 | 20 | location /prerender/ { 21 | proxy_pass http://localhost:7000/; 22 | proxy_http_version 1.1; 23 | proxy_set_header Upgrade $http_upgrade; 24 | proxy_set_header Connection keep-alive; 25 | proxy_cache_bypass $http_upgrade; 26 | proxy_set_header Host $host; 27 | proxy_set_header X-Real-IP $remote_addr; 28 | proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 29 | proxy_set_header X-Forwarded-Proto $scheme; 30 | proxy_buffering off; 31 | proxy_ignore_client_abort off; 32 | proxy_intercept_errors on; 33 | } 34 | 35 | location / { 36 | proxy_pass http://localhost:16325; 37 | proxy_http_version 1.1; 38 | 39 | proxy_redirect off; 40 | proxy_read_timeout 1m; 41 | proxy_connect_timeout 1m; 42 | 43 | proxy_set_header Upgrade $http_upgrade; 44 | proxy_set_header Connection keep-alive; 45 | proxy_cache_bypass $http_upgrade; 46 | proxy_set_header Host $host; 47 | proxy_set_header X-Real-IP $remote_addr; 48 | proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 49 | proxy_set_header X-Forwarded-Proto $scheme; 50 | proxy_buffering off; 51 | proxy_ignore_client_abort off; 52 | proxy_intercept_errors on; 53 | client_max_body_size 500m; 54 | } 55 | 56 | } 57 | -------------------------------------------------------------------------------- /TechStacks/scripts/server/supervisord/web-prerender.conf: -------------------------------------------------------------------------------- 1 | [program:web-prerender] 2 | command=node /home/deploy/apps/scripts/prerender.js 3 | autostart=true 4 | autorestart=true 5 | environment=NODE_ENV=production 6 | stderr_logfile=/var/log/prerender.err.log 7 | stdout_logfile=/var/log/prerender.out.log 8 | user=ubuntu 9 | stopsignal=INT 10 | -------------------------------------------------------------------------------- /TechStacks/scripts/server/supervisord/web-techstacks.conf: -------------------------------------------------------------------------------- 1 | [program:web-techstacks] 2 | command=/usr/bin/dotnet /home/deploy/apps/techstacks/TechStacks.dll 3 | directory=/home/deploy/apps/techstacks 4 | autostart=true 5 | autorestart=true 6 | stderr_logfile=/var/log/web-techstacks.err.log 7 | stdout_logfile=/var/log/web-techstacks.out.log 8 | environment=ASPNETCORE_ENVIRONMENT=Production,ASPNETCORE_URLS="http://*:16325/",SERVICESTACK_LICENSE="",FORUMS_DB="" 9 | user=deploy 10 | stopsignal=INT -------------------------------------------------------------------------------- /TechStacks/src/assets/README.md: -------------------------------------------------------------------------------- 1 | # ASSETS 2 | 3 | This directory contains your un-compiled assets such as LESS, SASS, or JavaScript. 4 | 5 | More information about the usage of this directory in the documentation: 6 | https://nuxtjs.org/guide/assets#webpacked 7 | 8 | **This directory is not required, you can delete it if you don't want to use it.** 9 | -------------------------------------------------------------------------------- /TechStacks/src/components/PostInfo.vue: -------------------------------------------------------------------------------- 1 | 15 | 16 | 61 | 62 | 69 | -------------------------------------------------------------------------------- /TechStacks/src/components/README.md: -------------------------------------------------------------------------------- 1 | # COMPONENTS 2 | 3 | The components directory contains your Vue.js Components. 4 | Nuxt.js doesn't supercharge these components. 5 | 6 | **This directory is not required, you can delete it if you don't want to use it.** 7 | -------------------------------------------------------------------------------- /TechStacks/src/layouts/README.md: -------------------------------------------------------------------------------- 1 | # LAYOUTS 2 | 3 | This directory contains your Application Layouts. 4 | 5 | More information about the usage of this directory in the documentation: 6 | https://nuxtjs.org/guide/views#layouts 7 | 8 | **This directory is not required, you can delete it if you don't want to use it.** 9 | -------------------------------------------------------------------------------- /TechStacks/src/middleware/README.md: -------------------------------------------------------------------------------- 1 | # MIDDLEWARE 2 | 3 | This directory contains your Application Middleware. 4 | The middleware lets you define custom function to be ran before rendering a page or a group of pages (layouts). 5 | 6 | More information about the usage of this directory in the documentation: 7 | https://nuxtjs.org/guide/routing#middleware 8 | 9 | **This directory is not required, you can delete it if you don't want to use it.** 10 | -------------------------------------------------------------------------------- /TechStacks/src/middleware/routes.js: -------------------------------------------------------------------------------- 1 | export default function(context) { 2 | const slug = context.params && context.params.slug; 3 | document.title = slug 4 | ? slug + ' - techstacks.io' 5 | : 'techstacks.io'; 6 | } -------------------------------------------------------------------------------- /TechStacks/src/pages/README.md: -------------------------------------------------------------------------------- 1 | # PAGES 2 | 3 | This directory contains your Application Views and Routes. 4 | The framework reads all the .vue files inside this directory and creates the router of your application. 5 | 6 | More information about the usage of this directory in the documentation: 7 | https://nuxtjs.org/guide/routing 8 | -------------------------------------------------------------------------------- /TechStacks/src/pages/_slug/_category.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 12 | -------------------------------------------------------------------------------- /TechStacks/src/pages/_slug/index.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 12 | -------------------------------------------------------------------------------- /TechStacks/src/pages/comments/_postid/_id.vue: -------------------------------------------------------------------------------- 1 | 23 | 24 | 25 | 78 | -------------------------------------------------------------------------------- /TechStacks/src/pages/organizations/_slug/index.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 14 | -------------------------------------------------------------------------------- /TechStacks/src/pages/organizations/index.vue: -------------------------------------------------------------------------------- 1 | 39 | 40 | 72 | -------------------------------------------------------------------------------- /TechStacks/src/pages/posts/_id/_postslug.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 14 | -------------------------------------------------------------------------------- /TechStacks/src/pages/stacks/_slug/edit.vue: -------------------------------------------------------------------------------- 1 | 19 | 20 | 45 | -------------------------------------------------------------------------------- /TechStacks/src/pages/stacks/new.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 14 | -------------------------------------------------------------------------------- /TechStacks/src/pages/tech/_slug/edit.vue: -------------------------------------------------------------------------------- 1 | 19 | 20 | 45 | -------------------------------------------------------------------------------- /TechStacks/src/pages/tech/new.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 14 | -------------------------------------------------------------------------------- /TechStacks/src/plugins/README.md: -------------------------------------------------------------------------------- 1 | # PLUGINS 2 | 3 | This directory contains your Javascript plugins that you want to run before instantiating the root vue.js application. 4 | 5 | More information about the usage of this directory in the documentation: 6 | https://nuxtjs.org/guide/plugins 7 | 8 | **This directory is not required, you can delete it if you don't want to use it.** 9 | -------------------------------------------------------------------------------- /TechStacks/src/plugins/ga.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable */ 2 | 3 | export default ({app}) => { 4 | /* 5 | ** Only run on client-side and only in production mode 6 | */ 7 | if (process.env.NODE_ENV !== 'production') return 8 | /* 9 | ** Include Google Analytics Script 10 | */ 11 | const gtag = (function (i, s, o, g, r, a, m) { 12 | i['GoogleTagObject'] = gtag; 13 | a = s.createElement(o), m = s.getElementsByTagName(o)[0]; 14 | a.async = 1; 15 | a.src = g; 16 | m.parentNode.insertBefore(a, m); 17 | i['dataLayer'] = i['dataLayer'] || []; 18 | function gtag(){i['dataLayer'].push(arguments)} 19 | return gtag 20 | })(window, document, 'script', 'https://www.googletagmanager.com/gtag/js?id=G-9EZHMS9ZM6'); 21 | /* 22 | ** Set the current page 23 | */ 24 | gtag('js', new Date()); 25 | gtag('config', 'G-9EZHMS9ZM6'); 26 | /* 27 | ** Every time the route changes (fired on initialization too) 28 | */ 29 | app.router.afterEach((to, from) => { 30 | /* 31 | ** We tell Google Analytics to add a `pageview` 32 | */ 33 | gtag('set', 'page', to.fullPath) 34 | gtag('send', 'pageview') 35 | }) 36 | } 37 | -------------------------------------------------------------------------------- /TechStacks/src/plugins/nuxt-client-init.js: -------------------------------------------------------------------------------- 1 | 2 | export default async ctx => { 3 | await ctx.store.dispatch("nuxtClientInit", ctx); 4 | }; 5 | -------------------------------------------------------------------------------- /TechStacks/src/plugins/vuetify.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import Vuetify from 'vuetify' 3 | import 'vuetify/dist/vuetify.css' 4 | 5 | Vue.use(Vuetify) 6 | -------------------------------------------------------------------------------- /TechStacks/src/shared/routes.js: -------------------------------------------------------------------------------- 1 | import { appendQueryString, queryString } from "@servicestack/client"; 2 | 3 | const hasQuery = (qs) => qs && Object.keys(qs).length > 0; 4 | 5 | const appendQuery = (route,qs) => hasQuery(qs) 6 | ? appendQueryString(route,qs) 7 | : route; 8 | 9 | export const routes = { 10 | formattingHelp: 'https://guides.github.com/features/mastering-markdown/', 11 | welcome: '/posts/5944/welcome', 12 | authGitHub: '/auth/github', 13 | authTwitter: '/auth/twitter', 14 | homeNews: '/', 15 | homeTop: '/top/', 16 | homeFavorites: '/favorites/', 17 | newStack: '/stacks/new', 18 | newTech: '/tech/new', 19 | homeTech: '/tech/', 20 | homeStacks: '/stacks/', 21 | newsTech: (slug) => `/?t=${slug}`, 22 | techTier: (tier) => `/tech?tier=${tier}`, 23 | organization: (slug) => `/organizations/${slug}`, 24 | organizationNews: (slug,qs=null) => appendQuery(`/${slug}`,qs), 25 | stack: (slug) => `/stacks/${slug}/`, 26 | editStack: (slug) => `/stacks/${slug}/edit`, 27 | tech: (slug) => `/tech/${slug}/`, 28 | editTech: (slug) => `/tech/${slug}/edit`, 29 | user: (userName) => `/users/${userName}`, 30 | userAvatar: (userId) => `/users/${userId}/avatar`, 31 | post: (postId, postSlug) => `/posts/${postId}/${postSlug}`, 32 | comment: (postId,commentId) => `/comments/${postId}/${commentId}`, 33 | techTag: (slug,organization) => organization ? `/?t=${slug}` : `/tech/${slug}`, 34 | sortOrderByField(sort) { 35 | return sort == 'new' 36 | ? '-created' 37 | : sort == 'top' 38 | ? '-points' 39 | : null; 40 | }, 41 | sort:(sort) => { 42 | const qs = queryString(location.href); 43 | if (qs['sort'] === sort) { 44 | delete qs['sort']; //toggle off 45 | } else { 46 | qs['sort'] = sort; 47 | } 48 | return appendQueryString(location.pathname, qs); 49 | }, 50 | sortClass:(sort) => { 51 | const qs = queryString(location.href); 52 | return qs['sort'] === sort 53 | ? 'active' 54 | : null; 55 | }, 56 | }; 57 | -------------------------------------------------------------------------------- /TechStacks/src/static/README.md: -------------------------------------------------------------------------------- 1 | # STATIC 2 | 3 | This directory contains your static files. 4 | Each file inside this directory is mapped to /. 5 | 6 | Example: /static/robots.txt is mapped as /robots.txt 7 | 8 | More information about the usage of this directory in the documentation: 9 | https://nuxtjs.org/guide/assets#static 10 | 11 | **This directory is not required, you can delete it if you don't want to use it.** 12 | -------------------------------------------------------------------------------- /TechStacks/src/static/_redirects: -------------------------------------------------------------------------------- 1 | /json/* http://techstacks.netcore.io/json/:splat 200 2 | /auth/* http://techstacks.netcore.io/auth/:splat 200 3 | /users/*/avatar http://techstacks.netcore.io/users/:splat/avatar 200 4 | /metadata http://techstacks.netcore.io/metadata 200 5 | /metadata/* http://techstacks.netcore.io/metadata/:splat 200 6 | /types/* http://techstacks.netcore.io/types/:splat 200 7 | /ss_admin/* http://techstacks.netcore.io/ss_admin/:splat 200 8 | /swagger-ui/* http://techstacks.netcore.io/swagger-ui/:splat 200 9 | /prerender/* http://prerender.netcore.io/:splat 200 10 | /:sitemap.xml http://techstacks.netcore.io/:sitemap.xml 200 11 | /* /index.html 200 12 | -------------------------------------------------------------------------------- /TechStacks/src/static/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NetCoreApps/TechStacks/007505205e86088cfdd246dcc92687fbb0186410/TechStacks/src/static/favicon.ico -------------------------------------------------------------------------------- /TechStacks/src/static/googled0ec8ee6ceb21aeb.html: -------------------------------------------------------------------------------- 1 | google-site-verification: googled0ec8ee6ceb21aeb.html -------------------------------------------------------------------------------- /TechStacks/src/static/images/emoji/emoji_one/blush.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NetCoreApps/TechStacks/007505205e86088cfdd246dcc92687fbb0186410/TechStacks/src/static/images/emoji/emoji_one/blush.png -------------------------------------------------------------------------------- /TechStacks/src/static/images/emoji/emoji_one/confounded.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NetCoreApps/TechStacks/007505205e86088cfdd246dcc92687fbb0186410/TechStacks/src/static/images/emoji/emoji_one/confounded.png -------------------------------------------------------------------------------- /TechStacks/src/static/images/emoji/emoji_one/confused.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NetCoreApps/TechStacks/007505205e86088cfdd246dcc92687fbb0186410/TechStacks/src/static/images/emoji/emoji_one/confused.png -------------------------------------------------------------------------------- /TechStacks/src/static/images/emoji/emoji_one/crazy_face.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NetCoreApps/TechStacks/007505205e86088cfdd246dcc92687fbb0186410/TechStacks/src/static/images/emoji/emoji_one/crazy_face.png -------------------------------------------------------------------------------- /TechStacks/src/static/images/emoji/emoji_one/cry.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NetCoreApps/TechStacks/007505205e86088cfdd246dcc92687fbb0186410/TechStacks/src/static/images/emoji/emoji_one/cry.png -------------------------------------------------------------------------------- /TechStacks/src/static/images/emoji/emoji_one/disappointed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NetCoreApps/TechStacks/007505205e86088cfdd246dcc92687fbb0186410/TechStacks/src/static/images/emoji/emoji_one/disappointed.png -------------------------------------------------------------------------------- /TechStacks/src/static/images/emoji/emoji_one/disappointed_relieved.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NetCoreApps/TechStacks/007505205e86088cfdd246dcc92687fbb0186410/TechStacks/src/static/images/emoji/emoji_one/disappointed_relieved.png -------------------------------------------------------------------------------- /TechStacks/src/static/images/emoji/emoji_one/dizzy_face.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NetCoreApps/TechStacks/007505205e86088cfdd246dcc92687fbb0186410/TechStacks/src/static/images/emoji/emoji_one/dizzy_face.png -------------------------------------------------------------------------------- /TechStacks/src/static/images/emoji/emoji_one/drooling_face.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NetCoreApps/TechStacks/007505205e86088cfdd246dcc92687fbb0186410/TechStacks/src/static/images/emoji/emoji_one/drooling_face.png -------------------------------------------------------------------------------- /TechStacks/src/static/images/emoji/emoji_one/exploding_head.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NetCoreApps/TechStacks/007505205e86088cfdd246dcc92687fbb0186410/TechStacks/src/static/images/emoji/emoji_one/exploding_head.png -------------------------------------------------------------------------------- /TechStacks/src/static/images/emoji/emoji_one/expressionless.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NetCoreApps/TechStacks/007505205e86088cfdd246dcc92687fbb0186410/TechStacks/src/static/images/emoji/emoji_one/expressionless.png -------------------------------------------------------------------------------- /TechStacks/src/static/images/emoji/emoji_one/eyes.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NetCoreApps/TechStacks/007505205e86088cfdd246dcc92687fbb0186410/TechStacks/src/static/images/emoji/emoji_one/eyes.png -------------------------------------------------------------------------------- /TechStacks/src/static/images/emoji/emoji_one/face_with_head_bandage.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NetCoreApps/TechStacks/007505205e86088cfdd246dcc92687fbb0186410/TechStacks/src/static/images/emoji/emoji_one/face_with_head_bandage.png -------------------------------------------------------------------------------- /TechStacks/src/static/images/emoji/emoji_one/face_with_monocle.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NetCoreApps/TechStacks/007505205e86088cfdd246dcc92687fbb0186410/TechStacks/src/static/images/emoji/emoji_one/face_with_monocle.png -------------------------------------------------------------------------------- /TechStacks/src/static/images/emoji/emoji_one/face_with_raised_eyebrow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NetCoreApps/TechStacks/007505205e86088cfdd246dcc92687fbb0186410/TechStacks/src/static/images/emoji/emoji_one/face_with_raised_eyebrow.png -------------------------------------------------------------------------------- /TechStacks/src/static/images/emoji/emoji_one/face_with_rolling_eyes.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NetCoreApps/TechStacks/007505205e86088cfdd246dcc92687fbb0186410/TechStacks/src/static/images/emoji/emoji_one/face_with_rolling_eyes.png -------------------------------------------------------------------------------- /TechStacks/src/static/images/emoji/emoji_one/face_with_symbols_over_mouth.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NetCoreApps/TechStacks/007505205e86088cfdd246dcc92687fbb0186410/TechStacks/src/static/images/emoji/emoji_one/face_with_symbols_over_mouth.png -------------------------------------------------------------------------------- /TechStacks/src/static/images/emoji/emoji_one/face_with_thermometer.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NetCoreApps/TechStacks/007505205e86088cfdd246dcc92687fbb0186410/TechStacks/src/static/images/emoji/emoji_one/face_with_thermometer.png -------------------------------------------------------------------------------- /TechStacks/src/static/images/emoji/emoji_one/fearful.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NetCoreApps/TechStacks/007505205e86088cfdd246dcc92687fbb0186410/TechStacks/src/static/images/emoji/emoji_one/fearful.png -------------------------------------------------------------------------------- /TechStacks/src/static/images/emoji/emoji_one/flushed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NetCoreApps/TechStacks/007505205e86088cfdd246dcc92687fbb0186410/TechStacks/src/static/images/emoji/emoji_one/flushed.png -------------------------------------------------------------------------------- /TechStacks/src/static/images/emoji/emoji_one/frowning.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NetCoreApps/TechStacks/007505205e86088cfdd246dcc92687fbb0186410/TechStacks/src/static/images/emoji/emoji_one/frowning.png -------------------------------------------------------------------------------- /TechStacks/src/static/images/emoji/emoji_one/frowning2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NetCoreApps/TechStacks/007505205e86088cfdd246dcc92687fbb0186410/TechStacks/src/static/images/emoji/emoji_one/frowning2.png -------------------------------------------------------------------------------- /TechStacks/src/static/images/emoji/emoji_one/frowning_face.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NetCoreApps/TechStacks/007505205e86088cfdd246dcc92687fbb0186410/TechStacks/src/static/images/emoji/emoji_one/frowning_face.png -------------------------------------------------------------------------------- /TechStacks/src/static/images/emoji/emoji_one/gift_heart.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NetCoreApps/TechStacks/007505205e86088cfdd246dcc92687fbb0186410/TechStacks/src/static/images/emoji/emoji_one/gift_heart.png -------------------------------------------------------------------------------- /TechStacks/src/static/images/emoji/emoji_one/grimacing.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NetCoreApps/TechStacks/007505205e86088cfdd246dcc92687fbb0186410/TechStacks/src/static/images/emoji/emoji_one/grimacing.png -------------------------------------------------------------------------------- /TechStacks/src/static/images/emoji/emoji_one/grin.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NetCoreApps/TechStacks/007505205e86088cfdd246dcc92687fbb0186410/TechStacks/src/static/images/emoji/emoji_one/grin.png -------------------------------------------------------------------------------- /TechStacks/src/static/images/emoji/emoji_one/grinning.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NetCoreApps/TechStacks/007505205e86088cfdd246dcc92687fbb0186410/TechStacks/src/static/images/emoji/emoji_one/grinning.png -------------------------------------------------------------------------------- /TechStacks/src/static/images/emoji/emoji_one/hand.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NetCoreApps/TechStacks/007505205e86088cfdd246dcc92687fbb0186410/TechStacks/src/static/images/emoji/emoji_one/hand.png -------------------------------------------------------------------------------- /TechStacks/src/static/images/emoji/emoji_one/hand_splayed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NetCoreApps/TechStacks/007505205e86088cfdd246dcc92687fbb0186410/TechStacks/src/static/images/emoji/emoji_one/hand_splayed.png -------------------------------------------------------------------------------- /TechStacks/src/static/images/emoji/emoji_one/heart_eyes.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NetCoreApps/TechStacks/007505205e86088cfdd246dcc92687fbb0186410/TechStacks/src/static/images/emoji/emoji_one/heart_eyes.png -------------------------------------------------------------------------------- /TechStacks/src/static/images/emoji/emoji_one/hearts.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NetCoreApps/TechStacks/007505205e86088cfdd246dcc92687fbb0186410/TechStacks/src/static/images/emoji/emoji_one/hearts.png -------------------------------------------------------------------------------- /TechStacks/src/static/images/emoji/emoji_one/metal.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NetCoreApps/TechStacks/007505205e86088cfdd246dcc92687fbb0186410/TechStacks/src/static/images/emoji/emoji_one/metal.png -------------------------------------------------------------------------------- /TechStacks/src/static/images/emoji/emoji_one/muscle.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NetCoreApps/TechStacks/007505205e86088cfdd246dcc92687fbb0186410/TechStacks/src/static/images/emoji/emoji_one/muscle.png -------------------------------------------------------------------------------- /TechStacks/src/static/images/emoji/emoji_one/nerd.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NetCoreApps/TechStacks/007505205e86088cfdd246dcc92687fbb0186410/TechStacks/src/static/images/emoji/emoji_one/nerd.png -------------------------------------------------------------------------------- /TechStacks/src/static/images/emoji/emoji_one/neutral_face.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NetCoreApps/TechStacks/007505205e86088cfdd246dcc92687fbb0186410/TechStacks/src/static/images/emoji/emoji_one/neutral_face.png -------------------------------------------------------------------------------- /TechStacks/src/static/images/emoji/emoji_one/ok_hand.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NetCoreApps/TechStacks/007505205e86088cfdd246dcc92687fbb0186410/TechStacks/src/static/images/emoji/emoji_one/ok_hand.png -------------------------------------------------------------------------------- /TechStacks/src/static/images/emoji/emoji_one/open_mouth.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NetCoreApps/TechStacks/007505205e86088cfdd246dcc92687fbb0186410/TechStacks/src/static/images/emoji/emoji_one/open_mouth.png -------------------------------------------------------------------------------- /TechStacks/src/static/images/emoji/emoji_one/pensive.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NetCoreApps/TechStacks/007505205e86088cfdd246dcc92687fbb0186410/TechStacks/src/static/images/emoji/emoji_one/pensive.png -------------------------------------------------------------------------------- /TechStacks/src/static/images/emoji/emoji_one/persevere.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NetCoreApps/TechStacks/007505205e86088cfdd246dcc92687fbb0186410/TechStacks/src/static/images/emoji/emoji_one/persevere.png -------------------------------------------------------------------------------- /TechStacks/src/static/images/emoji/emoji_one/point_down.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NetCoreApps/TechStacks/007505205e86088cfdd246dcc92687fbb0186410/TechStacks/src/static/images/emoji/emoji_one/point_down.png -------------------------------------------------------------------------------- /TechStacks/src/static/images/emoji/emoji_one/point_left.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NetCoreApps/TechStacks/007505205e86088cfdd246dcc92687fbb0186410/TechStacks/src/static/images/emoji/emoji_one/point_left.png -------------------------------------------------------------------------------- /TechStacks/src/static/images/emoji/emoji_one/point_right.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NetCoreApps/TechStacks/007505205e86088cfdd246dcc92687fbb0186410/TechStacks/src/static/images/emoji/emoji_one/point_right.png -------------------------------------------------------------------------------- /TechStacks/src/static/images/emoji/emoji_one/point_up.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NetCoreApps/TechStacks/007505205e86088cfdd246dcc92687fbb0186410/TechStacks/src/static/images/emoji/emoji_one/point_up.png -------------------------------------------------------------------------------- /TechStacks/src/static/images/emoji/emoji_one/point_up_2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NetCoreApps/TechStacks/007505205e86088cfdd246dcc92687fbb0186410/TechStacks/src/static/images/emoji/emoji_one/point_up_2.png -------------------------------------------------------------------------------- /TechStacks/src/static/images/emoji/emoji_one/relaxed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NetCoreApps/TechStacks/007505205e86088cfdd246dcc92687fbb0186410/TechStacks/src/static/images/emoji/emoji_one/relaxed.png -------------------------------------------------------------------------------- /TechStacks/src/static/images/emoji/emoji_one/relieved.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NetCoreApps/TechStacks/007505205e86088cfdd246dcc92687fbb0186410/TechStacks/src/static/images/emoji/emoji_one/relieved.png -------------------------------------------------------------------------------- /TechStacks/src/static/images/emoji/emoji_one/rocket.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NetCoreApps/TechStacks/007505205e86088cfdd246dcc92687fbb0186410/TechStacks/src/static/images/emoji/emoji_one/rocket.png -------------------------------------------------------------------------------- /TechStacks/src/static/images/emoji/emoji_one/rofl.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NetCoreApps/TechStacks/007505205e86088cfdd246dcc92687fbb0186410/TechStacks/src/static/images/emoji/emoji_one/rofl.png -------------------------------------------------------------------------------- /TechStacks/src/static/images/emoji/emoji_one/roll_eyes.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NetCoreApps/TechStacks/007505205e86088cfdd246dcc92687fbb0186410/TechStacks/src/static/images/emoji/emoji_one/roll_eyes.png -------------------------------------------------------------------------------- /TechStacks/src/static/images/emoji/emoji_one/satisfied.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NetCoreApps/TechStacks/007505205e86088cfdd246dcc92687fbb0186410/TechStacks/src/static/images/emoji/emoji_one/satisfied.png -------------------------------------------------------------------------------- /TechStacks/src/static/images/emoji/emoji_one/scream.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NetCoreApps/TechStacks/007505205e86088cfdd246dcc92687fbb0186410/TechStacks/src/static/images/emoji/emoji_one/scream.png -------------------------------------------------------------------------------- /TechStacks/src/static/images/emoji/emoji_one/shushing_face.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NetCoreApps/TechStacks/007505205e86088cfdd246dcc92687fbb0186410/TechStacks/src/static/images/emoji/emoji_one/shushing_face.png -------------------------------------------------------------------------------- /TechStacks/src/static/images/emoji/emoji_one/sign_of_the_horns.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NetCoreApps/TechStacks/007505205e86088cfdd246dcc92687fbb0186410/TechStacks/src/static/images/emoji/emoji_one/sign_of_the_horns.png -------------------------------------------------------------------------------- /TechStacks/src/static/images/emoji/emoji_one/sleeping.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NetCoreApps/TechStacks/007505205e86088cfdd246dcc92687fbb0186410/TechStacks/src/static/images/emoji/emoji_one/sleeping.png -------------------------------------------------------------------------------- /TechStacks/src/static/images/emoji/emoji_one/sleepy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NetCoreApps/TechStacks/007505205e86088cfdd246dcc92687fbb0186410/TechStacks/src/static/images/emoji/emoji_one/sleepy.png -------------------------------------------------------------------------------- /TechStacks/src/static/images/emoji/emoji_one/slight_frown.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NetCoreApps/TechStacks/007505205e86088cfdd246dcc92687fbb0186410/TechStacks/src/static/images/emoji/emoji_one/slight_frown.png -------------------------------------------------------------------------------- /TechStacks/src/static/images/emoji/emoji_one/slight_smile.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NetCoreApps/TechStacks/007505205e86088cfdd246dcc92687fbb0186410/TechStacks/src/static/images/emoji/emoji_one/slight_smile.png -------------------------------------------------------------------------------- /TechStacks/src/static/images/emoji/emoji_one/slightly_frowning_face.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NetCoreApps/TechStacks/007505205e86088cfdd246dcc92687fbb0186410/TechStacks/src/static/images/emoji/emoji_one/slightly_frowning_face.png -------------------------------------------------------------------------------- /TechStacks/src/static/images/emoji/emoji_one/slightly_smiling.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NetCoreApps/TechStacks/007505205e86088cfdd246dcc92687fbb0186410/TechStacks/src/static/images/emoji/emoji_one/slightly_smiling.png -------------------------------------------------------------------------------- /TechStacks/src/static/images/emoji/emoji_one/slightly_smiling_face.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NetCoreApps/TechStacks/007505205e86088cfdd246dcc92687fbb0186410/TechStacks/src/static/images/emoji/emoji_one/slightly_smiling_face.png -------------------------------------------------------------------------------- /TechStacks/src/static/images/emoji/emoji_one/smile.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NetCoreApps/TechStacks/007505205e86088cfdd246dcc92687fbb0186410/TechStacks/src/static/images/emoji/emoji_one/smile.png -------------------------------------------------------------------------------- /TechStacks/src/static/images/emoji/emoji_one/smiley.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NetCoreApps/TechStacks/007505205e86088cfdd246dcc92687fbb0186410/TechStacks/src/static/images/emoji/emoji_one/smiley.png -------------------------------------------------------------------------------- /TechStacks/src/static/images/emoji/emoji_one/smirk.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NetCoreApps/TechStacks/007505205e86088cfdd246dcc92687fbb0186410/TechStacks/src/static/images/emoji/emoji_one/smirk.png -------------------------------------------------------------------------------- /TechStacks/src/static/images/emoji/emoji_one/sob.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NetCoreApps/TechStacks/007505205e86088cfdd246dcc92687fbb0186410/TechStacks/src/static/images/emoji/emoji_one/sob.png -------------------------------------------------------------------------------- /TechStacks/src/static/images/emoji/emoji_one/stuck_out_tongue.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NetCoreApps/TechStacks/007505205e86088cfdd246dcc92687fbb0186410/TechStacks/src/static/images/emoji/emoji_one/stuck_out_tongue.png -------------------------------------------------------------------------------- /TechStacks/src/static/images/emoji/emoji_one/stuck_out_tongue_closed_eyes.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NetCoreApps/TechStacks/007505205e86088cfdd246dcc92687fbb0186410/TechStacks/src/static/images/emoji/emoji_one/stuck_out_tongue_closed_eyes.png -------------------------------------------------------------------------------- /TechStacks/src/static/images/emoji/emoji_one/stuck_out_tongue_winking_eye.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NetCoreApps/TechStacks/007505205e86088cfdd246dcc92687fbb0186410/TechStacks/src/static/images/emoji/emoji_one/stuck_out_tongue_winking_eye.png -------------------------------------------------------------------------------- /TechStacks/src/static/images/emoji/emoji_one/sweat.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NetCoreApps/TechStacks/007505205e86088cfdd246dcc92687fbb0186410/TechStacks/src/static/images/emoji/emoji_one/sweat.png -------------------------------------------------------------------------------- /TechStacks/src/static/images/emoji/emoji_one/sweat_smile.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NetCoreApps/TechStacks/007505205e86088cfdd246dcc92687fbb0186410/TechStacks/src/static/images/emoji/emoji_one/sweat_smile.png -------------------------------------------------------------------------------- /TechStacks/src/static/images/emoji/emoji_one/thumbsdown.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NetCoreApps/TechStacks/007505205e86088cfdd246dcc92687fbb0186410/TechStacks/src/static/images/emoji/emoji_one/thumbsdown.png -------------------------------------------------------------------------------- /TechStacks/src/static/images/emoji/emoji_one/thumbsup.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NetCoreApps/TechStacks/007505205e86088cfdd246dcc92687fbb0186410/TechStacks/src/static/images/emoji/emoji_one/thumbsup.png -------------------------------------------------------------------------------- /TechStacks/src/static/images/emoji/emoji_one/unamused.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NetCoreApps/TechStacks/007505205e86088cfdd246dcc92687fbb0186410/TechStacks/src/static/images/emoji/emoji_one/unamused.png -------------------------------------------------------------------------------- /TechStacks/src/static/images/emoji/emoji_one/wink.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NetCoreApps/TechStacks/007505205e86088cfdd246dcc92687fbb0186410/TechStacks/src/static/images/emoji/emoji_one/wink.png -------------------------------------------------------------------------------- /TechStacks/src/static/images/emoji/emoji_one/yum.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NetCoreApps/TechStacks/007505205e86088cfdd246dcc92687fbb0186410/TechStacks/src/static/images/emoji/emoji_one/yum.png -------------------------------------------------------------------------------- /TechStacks/src/static/img/appstore-badge.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NetCoreApps/TechStacks/007505205e86088cfdd246dcc92687fbb0186410/TechStacks/src/static/img/appstore-badge.png -------------------------------------------------------------------------------- /TechStacks/src/static/img/csharp-logo.svg: -------------------------------------------------------------------------------- 1 | 2 | 4 | 7 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /TechStacks/src/static/img/en_app_rgb_wo_60.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NetCoreApps/TechStacks/007505205e86088cfdd246dcc92687fbb0186410/TechStacks/src/static/img/en_app_rgb_wo_60.png -------------------------------------------------------------------------------- /TechStacks/src/static/img/github.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /TechStacks/src/static/img/loading.svg: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /TechStacks/src/static/img/logo-white.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /TechStacks/src/static/img/logo.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /TechStacks/src/static/img/no-profile64.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NetCoreApps/TechStacks/007505205e86088cfdd246dcc92687fbb0186410/TechStacks/src/static/img/no-profile64.png -------------------------------------------------------------------------------- /TechStacks/src/static/img/onebox/github-16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NetCoreApps/TechStacks/007505205e86088cfdd246dcc92687fbb0186410/TechStacks/src/static/img/onebox/github-16.png -------------------------------------------------------------------------------- /TechStacks/src/static/img/shortcuts.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NetCoreApps/TechStacks/007505205e86088cfdd246dcc92687fbb0186410/TechStacks/src/static/img/shortcuts.png -------------------------------------------------------------------------------- /TechStacks/src/static/img/twitter.svg: -------------------------------------------------------------------------------- 1 | 3 | 7 | 8 | 9 | 10 | 11 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /TechStacks/src/static/img/v.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NetCoreApps/TechStacks/007505205e86088cfdd246dcc92687fbb0186410/TechStacks/src/static/img/v.png -------------------------------------------------------------------------------- /TechStacks/src/store/README.md: -------------------------------------------------------------------------------- 1 | # STORE 2 | 3 | This directory contains your Vuex Store files. 4 | Vuex Store option is implemented in the Nuxt.js framework. 5 | Creating a index.js file in this directory activate the option in the framework automatically. 6 | 7 | More information about the usage of this directory in the documentation: 8 | https://nuxtjs.org/guide/vuex-store 9 | 10 | **This directory is not required, you can delete it if you don't want to use it.** 11 | -------------------------------------------------------------------------------- /TechStacks/tailwind.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | content: ["./Pages/**/*.{html,js,mjs,md,cshtml,razor}","./Areas/**/*.{html,js,mjs,md,cshtml,razor}", "./Css.cs"], 3 | darkMode: 'class', 4 | theme: { 5 | extend: { 6 | colors: { 7 | 'accent-1': '#FAFAFA', 8 | 'accent-2': '#EAEAEA', 9 | danger: 'rgb(153 27 27)', 10 | success: 'rgb(22 101 52)', 11 | }, 12 | }, 13 | }, 14 | plugins: [], 15 | } 16 | -------------------------------------------------------------------------------- /TechStacks/wwwroot/.nojekyll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NetCoreApps/TechStacks/007505205e86088cfdd246dcc92687fbb0186410/TechStacks/wwwroot/.nojekyll -------------------------------------------------------------------------------- /TechStacks/wwwroot/README.md: -------------------------------------------------------------------------------- 1 | # STATIC 2 | 3 | This directory contains your static files. 4 | Each file inside this directory is mapped to /. 5 | 6 | Example: /static/robots.txt is mapped as /robots.txt 7 | 8 | More information about the usage of this directory in the documentation: 9 | https://nuxtjs.org/guide/assets#static 10 | 11 | **This directory is not required, you can delete it if you don't want to use it.** 12 | -------------------------------------------------------------------------------- /TechStacks/wwwroot/_nuxt/LICENSES: -------------------------------------------------------------------------------- 1 | /*! 2 | * Vue.js v2.7.14 3 | * (c) 2014-2022 Evan You 4 | * Released under the MIT License. 5 | */ 6 | 7 | /*! 8 | * The buffer module from node.js, for the browser. 9 | * 10 | * @author Feross Aboukhadijeh 11 | * @license MIT 12 | */ 13 | 14 | /*! 15 | * vuex v3.6.2 16 | * (c) 2021 Evan You 17 | * @license MIT 18 | */ 19 | 20 | /*! 21 | * @overview es6-promise - a tiny implementation of Promises/A+. 22 | * @copyright Copyright (c) 2014 Yehuda Katz, Tom Dale, Stefan Penner and contributors (Conversion to ES6 API by Jake Archibald) 23 | * @license Licensed under MIT license 24 | * See https://raw.githubusercontent.com/stefanpenner/es6-promise/master/LICENSE 25 | * @version v4.2.8+1e68dce6 26 | */ 27 | 28 | /** 29 | * vue-meta v1.6.0 30 | * (c) 2019 Declan de Wet & Sébastien Chopin (@Atinux) 31 | * @license MIT 32 | */ 33 | 34 | /* 35 | object-assign 36 | (c) Sindre Sorhus 37 | @license MIT 38 | */ 39 | 40 | /*! ieee754. BSD-3-Clause License. Feross Aboukhadijeh */ 41 | -------------------------------------------------------------------------------- /TechStacks/wwwroot/_nuxt/img/appstore-badge.4deb278.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NetCoreApps/TechStacks/007505205e86088cfdd246dcc92687fbb0186410/TechStacks/wwwroot/_nuxt/img/appstore-badge.4deb278.png -------------------------------------------------------------------------------- /TechStacks/wwwroot/_nuxt/img/csharp-logo.f207120.svg: -------------------------------------------------------------------------------- 1 | 2 | 4 | 7 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /TechStacks/wwwroot/_nuxt/img/en_app_rgb_wo_60.0483be5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NetCoreApps/TechStacks/007505205e86088cfdd246dcc92687fbb0186410/TechStacks/wwwroot/_nuxt/img/en_app_rgb_wo_60.0483be5.png -------------------------------------------------------------------------------- /TechStacks/wwwroot/_nuxt/img/loading.118a471.svg: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /TechStacks/wwwroot/_nuxt/manifest.08e587a7cf311c1fa8e1.js: -------------------------------------------------------------------------------- 1 | !function(e){var n=window.webpackJsonp;window.webpackJsonp=function(t,o,s){for(var c,_,i,d=0,f=[];d 2 | 4 | 7 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /TechStacks/wwwroot/img/en_app_rgb_wo_60.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NetCoreApps/TechStacks/007505205e86088cfdd246dcc92687fbb0186410/TechStacks/wwwroot/img/en_app_rgb_wo_60.png -------------------------------------------------------------------------------- /TechStacks/wwwroot/img/github.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /TechStacks/wwwroot/img/loading.svg: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /TechStacks/wwwroot/img/logo-white.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /TechStacks/wwwroot/img/logo.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /TechStacks/wwwroot/img/no-profile64.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NetCoreApps/TechStacks/007505205e86088cfdd246dcc92687fbb0186410/TechStacks/wwwroot/img/no-profile64.png -------------------------------------------------------------------------------- /TechStacks/wwwroot/img/onebox/github-16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NetCoreApps/TechStacks/007505205e86088cfdd246dcc92687fbb0186410/TechStacks/wwwroot/img/onebox/github-16.png -------------------------------------------------------------------------------- /TechStacks/wwwroot/img/shortcuts.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NetCoreApps/TechStacks/007505205e86088cfdd246dcc92687fbb0186410/TechStacks/wwwroot/img/shortcuts.png -------------------------------------------------------------------------------- /TechStacks/wwwroot/img/twitter.svg: -------------------------------------------------------------------------------- 1 | 3 | 7 | 8 | 9 | 10 | 11 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /TechStacks/wwwroot/img/v.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NetCoreApps/TechStacks/007505205e86088cfdd246dcc92687fbb0186410/TechStacks/wwwroot/img/v.png -------------------------------------------------------------------------------- /license.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) 2007-2013, Demis Bellot, ServiceStack. 2 | https://servicestack.net 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without 6 | modification, are permitted provided that the following conditions are met: 7 | * Redistributions of source code must retain the above copyright 8 | notice, this list of conditions and the following disclaimer. 9 | * Redistributions in binary form must reproduce the above copyright 10 | notice, this list of conditions and the following disclaimer in the 11 | documentation and/or other materials provided with the distribution. 12 | * Neither the name of the ServiceStack nor the 13 | names of its contributors may be used to endorse or promote products 14 | derived from this software without specific prior written permission. 15 | 16 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 17 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 18 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 19 | DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY 20 | DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 21 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 22 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 23 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 25 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. --------------------------------------------------------------------------------