How to configure docusaurus config keys conditionally? - conditional-statements

If a user needs to configure an optional docusaurus config key based on some condition, what is the best way to address it in docusaurus.config.js file? For example:
module.exports = {
/* If condition is true then */
showLastUpdateAuthor: true,
/* otherwise set it to false */
//Other config key value...
}
Here is what I tried and it worked. Is there a better way to handle this?
Insights via Spread Syntax discussed here.
const branch = require('child_process')
.execSync('git branch --show-current')
.toString().trim();
module.exports = {
...(branch != 'main') ? {showLastUpdateAuthor: true,}:{showLastUpdateAuthor: false,},
//Other config key value...
}

It worked. Any other better way?
const branch = require('child_process')
.execSync('git branch --show-current')
.toString().trim();
module.exports = {
...(branch != 'main') ? {showLastUpdateAuthor: true,}:{showLastUpdateAuthor: false,},
//Other config key value...
}

Related

How to hide some views only in production env Laravel

I am pretty new to Laravel. So I have a Laravel Vue app where i want to hide a view.blade only in my production environment and not on staging , i tried with the config file view but i didn't succeed.
Can anyone help me please ?
Thank you
One possible solution would be to use an if statement for the view. It's difficult to give a more contextual answer without more context.
example below:
<template>
<view v-if="inProduction"></view>
</template>
export default {
computed: {
inProduction(){
return process.env.NODE_ENV === "production";
}
}
}
You could do a conditional route middleware too so it just checks the config file (cached) for the env. Then you can send them anywhere you want if someone tried to hit that route.
If you're trying to hide a full route on certain env best way would be to create a Middleware like this:
<?php
namespace App\Http\Middleware;
use Closure;
use Illuminate\Http\Request;
class AppEnv
{
/**
* Handle an incoming request.
*
* #param \Illuminate\Http\Request $request
* #param \Closure(\Illuminate\Http\Request): (\Illuminate\Http\Response|\Illuminate\Http\RedirectResponse) $next
* #return \Illuminate\Http\Response|\Illuminate\Http\RedirectResponse
*/
public function handle(Request $request, Closure $next, $env)
{
if(config('app.env') == $env) {
return $next($request);
}
abort(404);
}
}
You'll have to register this middleware on the app/Http/Kernel $routeMiddleware array
Then you can use it like this:
Route::view('/', 'welcome')->middleware(['env:local'])
(Change local for the env where you want to show this route)

Getting language from browser doesn't work with SSR

I have a website with multi language ['de', 'fr', 'it', 'en']
Current behaviour:
When I enter example.com without a previous session I am redirected to example.com/de (first value in the array)
Wanted behaviour:
I want to be redirected to the browser's language I have (in case there is none in session)
I have extended the service LanguageService to override the initialize() function as follows:
initialize(): void {
let value;
this.getActive()
.subscribe((val) => (value = val))
.unsubscribe();
if (value) {
// don't initialize, if there is already a value (i.e. retrieved from route or transferred from SSR)
return;
}
const languages = this.getLanguages();
const sessionLanguage = this.sessionStorageCustom && this.sessionStorageCustom.getItem('language');
if (sessionLanguage && languages?.includes(sessionLanguage)) {
this.setActive(sessionLanguage);
} else {
const browserLanguage = this.getBrowserLanguage();
if (browserLanguage && languages?.includes(browserLanguage)) {
this.setActive(browserLanguage);
}
}
}
Helpers:
private getLanguages(): string[] | null {
let languages = this.siteContextParamsService.getParamValues('language');
// Removing English from options
languages = languages.filter((l) => !(l.toLowerCase() === 'en'));
if (languages) return languages;
return null;
}
private getBrowserLanguage(): string | null {
let language = this.winRef.nativeWindow?.navigator.language;
if (language) {
language = language.slice(0, 2);
return language;
}
return null;
}
Constructor:
private sessionStorageCustom: Storage | undefined;
constructor(
protected store: Store<StateWithSiteContext>,
protected winRef: WindowRef,
protected config: SiteContextConfig,
protected siteContextParamsService: SiteContextParamsService
) {
super(store, winRef, config);
// cannot use default variable because it's private
this.sessionStorageCustom = winRef.sessionStorage;
}
On CSR everything works as expected but when in SSR I always go to the default language.
(Because on server side there is no browser's language. I assume.)
How can I force this code be executed at the client side? or what can I do to accomplish this?
By default the Spartacus siteContext will always default to the SSR transfer state if it is present before running the browser language logic.
I can see two solutions you could try:
You can remove the SSR transfer state. This way Spartacus will run your logic in browser every time. You can do it with:
state: {
ssrTransfer: {
keys: { [SITE_CONTEXT_FEATURE]: false },
},
},
This solution is not ideal because the SSR page will contain the default falback language which might not be the one the user is using so the page might flicker.
You can add custom logic in the LanguageService that will run only in the server and use the Accept-Language header to set the language. This header is set by the browser to let the server know what language the user wants. You can read this article which provides a great example on how to use this mechanism in Angular. The example is not in Spartacus but the same logic can be used.
One final thought, the Spartacus siteContext persistence will be updated in 4.0 to use the global state persistence mechanism.

How to skip value in config if it doesn't exist?

I am writing App, that need to read config at start. Some is not necessary for work.
class ParseConfig
{
string optionalkey;
//...
this()
{
this.optionalkey = config.getKey("key1");
}
//...
}
The problem that I need to find way to skip (do not try to find and parse) it if not exists and config. Now App try to parse config and show me error.
I found only one way - to wrap all in try-catch block, and if value can't be found in config in cantch block set it's to null.
What is the best way to do it?
I am using dini for config.
upd: (added example)
import std.stdio;
import std.path;
import std.file;
import dini;
void main()
{
string confpath = buildPath(getcwd, "config.ini");
if (!exists(confpath)) throw new Exception("ERROR: config.ini do not exists");
auto config = Ini.Parse(confpath);
try
{
string optionalkey;
if(config.getKey("optionalkey"))
{
optionalkey = config.getKey("optionalkey");
}
writeln(optionalkey); // nothing will shown, becouse exception
}
catch( Exception e)
{
writeln("Exception! :(");
writeln(e.msg);
}
}
Catching exception is one way, but it is not perfect (mainly if there will be many cases of optional configs). So better way is test if key exist:
class ParseConfig
{
string optionalkey;
//...
this()
{
this.optionalkey = config.hasKey("key1") ? config.getKey("key1") : "defaultValue";
}
//...
}
But ideal would be if dini has overload of getKey method so you can use something like this:
this.optionalkey = config.getKey("key1", "defaultValue");
But from sources I see it does not have it, but I plan to add it and make a PR.
UPDATE
PR: https://github.com/robik/DIni/pull/3
Wrote a pretty advanced ini file wrapper today which supports sections, comments, thread-safety, default values for reading, writing/reading using template values, entry checks etc.
You can get it here:
https://github.com/BaussProjects/baussini
Here is an example usage (example.d from the repo)
module main;
import baussini;
import std.stdio : writefln, readln;
void main() {
string fileName = "test.ini";
// Thread-safe instance, for a non thread-safe instance replace "true" with "false"
auto ini = new IniFile!(true)(fileName);
// Use open() for reading and close() for write. Both can be combined ...
if (!ini.exists()) {
ini.addSection("Root");
// Write way 1
ini.write!string("Root", "StringValue1", "Hello World!");
// Write way 2
ini.getSection("Root").write!int("IntValue1", 9001);
// Write way 3
ini.getSection("Root")
.write!string("StringValue2", "Hello Universe!")
.write!int("IntValue2", 1000000);
ini.close();
}
else {
ini.open();
// Read way 1
string stringValue1 = ini.read!string("Root", "StringValue1");
// Read way 2
int intValue1 = ini.getSection("Root").read!int("IntValue1");
// Read way 3
string stringValue2;
int intValue2;
ini.getSection("Root")
.read!string("StringValue2", stringValue2)
.read!int("IntValue2", intValue2);
writefln("%s is %s", "stringValue1", stringValue1);
writefln("%s is %s", "intValue1", intValue1);
writefln("%s is %s", "stringValue2", stringValue2);
writefln("%s is %s", "intValue2", intValue2);
readln();
}
}
In your case you could either use IniFile.hasKey or IniSection().hasKey()
Example:
// Check way 1
if (ini.hasKey("Root", "StringValue1")) {
// The section "Root" has an entry named "StringValue1"
}
// Check way 2
auto section = ini.getSection("Root");
if (section.hasKey("StringValue1")) {
// The section "Root" has an entry named "StringValue1"
}
You could also use default values.
string stringValue1 = ini.getSection("Root").read!string("StringValue1", "Default");
// stringValue1 will be "Default" if it doesn't exist within "Root"
The default value has to be a string input, but it will always convert the value of it to T.
Ex.
int defaultValue = ini.getSection("Root").read!int("IntValue3", "1000");
// defaultValue will be 1000 if it doesn't exist within "Root"
You can test if a key is present with hasKey
class ParseConfig
{
string optionalkey;
//...
this()
{
if (config.hasKey("key1"))
this.optionalkey = config.getKey("key1");
}
//...
}
assuming that we talk about the same dini

Prevent duplicate routes in express.js

Is there a nice way to prevent duplicate routes from being registered in express? I have a pretty large application with hundreds of routes across different files, and it gets difficult to know if I've already registered a certain route when I go to add a new one. For example, I'd like to throw an error when express gets to routes487.js:
File: routes1.js
var ctrl = require('../controllers/testctrl');
var auth = require('../libs/authentication');
module.exports = function (app) {
app.get('/hi', auth.getToken, ctrl.hi);
app.get('/there', auth.getToken, ctrl.there);
};
File: routes487.js
var ctrl = require('../controllers/testctrl487');
var auth = require('../libs/authentication');
module.exports = function (app) {
app.get('/hi', auth.getToken, ctrl.hi487);
};
You could try a custom solution by wrapping express methods with the validation. Consider the following modification to your express app:
// route-validation.js
module.exports = function (app) {
var existingRoutes = {}
, originalMethods = [];
// Returns true if the route is already registered.
function routeExists(verb, path) {
return existingRoutes[verb] &&
existingRoutes[verb].indexOf(path) > -1;
}
function registerRoute(verb, path) {
if (!existingRoutes[verb]) existingRoutes[verb] = [];
existingRoutes[verb].push(path);
}
// Return a new app method that will check repeated routes.
function validatedMethod(verb) {
return function() {
// If the route exists, app.VERB will throw.
if (routeExists(verb, arguments[0]) {
throw new Error("Can't register duplicate handler for path", arguments[0]);
}
// Otherwise, the route is saved and the original express method is called.
registerRoute(verb, arguments[0]);
originalMethods[verb].apply(app, arguments);
}
}
['get', 'post', 'put', 'delete', 'all'].forEach(function (verb) {
// Save original methods for internal use.
originalMethods[verb] = app[verb];
// Replace by our own route-validator methods.
app[verb] = validatedMethod(verb);
});
};
You just need to pass your app to this function after creation and duplicate route checking will be implemented. Note that you might need other "verbs" (OPTIONS, HEAD).
If you don't want to mess with express' methods (we don't know whether or how express itself or middleware modules will use them), you can use an intermediate layer (i.e., you actually wrap your app object instead of modifying its methods). I actually feel that would be a better solution, but I feel lazy to type it right now :)

Referencing to values in typesafe config

I have a config file:
app {
system {
action-type = "REST"
}
}
roles = [${app.system.action-type} "notifier"]
I want roles to have a value [ RESTnotifier ], but this approach gives me an exception. Any suggestions?
com.typesafe.config.ConfigException$NotResolved: need to Config#resolve() each config before using it, see the API docs for Config#resolve()
You need to explicitly call resolve on the Config instance if you are going to be using replacements in the config. A quick example showing this:
import com.typesafe.config.ConfigFactory
import collection.JavaConversions._
object ConfigExample extends App{
val cfgString = """
app {
system {
action-type = "REST"
}
}
roles = [${app.system.action-type}"notifier"]
"""
val cfg = ConfigFactory.parseString(cfgString).resolve()
println(cfg.getStringList("roles").toList)
}
Note the explicit call to resolve. That should fix your issue.