├── .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 |
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 |
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 |
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 |
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 |
15 |
16 | This action only disables 2FA.
17 |
18 |
19 | Disabling 2FA does not change the keys used in authenticator apps. If you wish to change the key
20 | used in an authenticator app you should
21 | reset your authenticator keys.
22 |
23 |
24 |
25 |
26 |
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 | @login.ProviderDisplayName
18 |
19 | @if (Model.ShowRemoveButton)
20 | {
21 |
28 | }
29 | else
30 | {
31 | @:
32 | }
33 |
34 |
35 | }
36 |
37 |
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 |
15 |
16 | This action generates new recovery codes.
17 |
18 |
19 | If you lose your device and don't have the recovery codes you will lose access to your account.
20 |
21 |
22 | Generating new recovery codes does not change the keys used in authenticator apps. If you wish to change the key
23 | used in an authenticator app you should
24 | reset your authenticator keys.
25 |
26 |
27 |
28 |
29 |
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 |
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 |
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 |
13 |
14 | If you reset your authenticator key your authenticator app will not work until you reconfigure it.
15 |
16 |
17 | This process disables 2FA until you verify your authenticator app and will also reset your 2FA recovery codes.
18 | If you do not complete your authenticator app configuration you may lose access to your account.
19 |
20 |
21 |
22 |
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 |
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 |
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 |
7 | @Model
8 |
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 |
11 |
12 | @Html.Raw(Model)
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/TechStacks/Pages/Shared/AlertInfo.cshtml:
--------------------------------------------------------------------------------
1 | @page
2 | @model string
3 |
4 |
5 |
6 |
11 |
12 | @Html.Raw(Model)
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/TechStacks/Pages/Shared/AlertWarning.cshtml:
--------------------------------------------------------------------------------
1 | @page
2 | @model string
3 |
4 |
5 |
6 |
11 |
12 | @Html.Raw(Model)
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/TechStacks/Pages/Shared/Footer.cshtml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
A ServiceStack Project
5 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/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 |
12 | {{ comment.ContentHtml | raw }}
13 |
14 |
15 |
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}:
}}
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 |
12 | {{ post.ImageUrl | endIfEmpty | select: }}
13 |
14 | {{ post.ContentHtml | raw }}
15 |
16 | {{ post.Url | endIfEmpty | select: continue reading...
}}
17 |
18 |
19 |
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 |
2 |
3 | submitted
4 | {{fromNow(post.created)}}
5 | to {{ toLabel }}
6 |
7 | with
8 |
10 | {{ getTechnologySlug(techId) }}
11 |
12 |
13 |
14 |
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 |
2 |
3 |
4 |
5 |
12 |
--------------------------------------------------------------------------------
/TechStacks/src/pages/_slug/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
12 |
--------------------------------------------------------------------------------
/TechStacks/src/pages/comments/_postid/_id.vue:
--------------------------------------------------------------------------------
1 |
2 |
22 |
23 |
24 |
25 |
78 |
--------------------------------------------------------------------------------
/TechStacks/src/pages/organizations/_slug/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
14 |
--------------------------------------------------------------------------------
/TechStacks/src/pages/organizations/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Organizations
8 |
9 |
10 |
11 |
12 |
13 | {{ organization.name }}
14 |
15 |
16 |
17 | by @{{organization.userName}}
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 | New Organization
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
72 |
--------------------------------------------------------------------------------
/TechStacks/src/pages/posts/_id/_postslug.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
14 |
--------------------------------------------------------------------------------
/TechStacks/src/pages/stacks/_slug/edit.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | TechStack '{{slug}}' was not found
8 |
9 |
10 |
11 |
12 | View TechStacks
13 | Add TechStack
14 |
15 |
16 |
17 |
18 |
19 |
20 |
45 |
--------------------------------------------------------------------------------
/TechStacks/src/pages/stacks/new.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
14 |
--------------------------------------------------------------------------------
/TechStacks/src/pages/tech/_slug/edit.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Technology '{{slug}}' was not found
8 |
9 |
10 |
11 |
12 | View Technologies
13 | Add Technology
14 |
15 |
16 |
17 |
18 |
19 |
20 |
45 |
--------------------------------------------------------------------------------
/TechStacks/src/pages/tech/new.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
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 |
3 |
4 |
--------------------------------------------------------------------------------
/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 |
3 |
4 |
--------------------------------------------------------------------------------
/TechStacks/src/static/img/logo.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/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 |
3 |
4 |
--------------------------------------------------------------------------------
/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 |
3 |
4 |
--------------------------------------------------------------------------------
/TechStacks/wwwroot/img/logo.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/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.
--------------------------------------------------------------------------------
error_outline Comment was not found
20 | 21 |