How to get DNN to create a sitemap links for custom modules? - dotnetnuke

We have a DNN website with custom modules which uses Ajax to load Grid Items.
How can I get DNN to create a sitemap for these links as well? I am currently using an external program but would like DNN to generate these sitemaps automatically with all our links.
The site is: https://www.parrot.co.za

You would typically do this by creating a SiteMap provider for your module.
You can find a working example in my DNNSimpleArticle module on GitHub
public class Sitemap : SitemapProvider
{
public override List<SitemapUrl> GetUrls(int portalId, PortalSettings ps, string version)
{
var listOfUrls = new List<SitemapUrl>();
foreach (Article ai in ArticleController.GetAllArticles(portalId))
{
var pageUrl = new SitemapUrl
{
Url =
ArticleController.GetArticleLink(ai.TabID, ai.ArticleId),
Priority = (float)0.5,
LastModified = ai.LastModifiedOnDate,
ChangeFrequency = SitemapChangeFrequency.Daily
};
listOfUrls.Add(pageUrl);
}
return listOfUrls;
}
}
and then you need to register the sitemap with DNN in the .DNN file used during the module's installation
<component type="Config">
<config>
<configFile>web.config</configFile>
<install>
<configuration>
<nodes>
<node path="/configuration/dotnetnuke/sitemap/providers" action="update" key="name" collision="overwrite">
<add name="DNNSimpleArticleSiteMapProvider" type="Christoc.Modules.dnnsimplearticle.Providers.Sitemap.Sitemap, DNNSimpleArticle" providerPath="~\DesktopModules\dnnsimplearticle\Providers\Sitemap\" />
</node>
</nodes>
</configuration>
</install>
<uninstall>
<configuration>
<nodes />
</configuration>
</uninstall>
</config>
</component>

Related

Is there a way to avoid X-Frame-Options in a CEF Windows Chromium Desktop App?

I created a simple app using the suggested "app init", then I dropped a pre-compiled ReactApp in place.
The app has a browser within it that uses an IFrame to host the navigated pages, but in some pages, it issues the following error:
Refused to display 'https://www.theverge.com/' in a frame because it set 'X-Frame-Options' to 'sameorigin'.", source: http://localhost:5000/#/
https://content-security-policy.com/
The page above has a series of ways to how this could be avoided, and Chromium has a flag that could help, where it disables security and as many suggested in other posts and questions, that may help with this issue.
Beyond those, there is the possibility of writing a reverse-proxy that could potentially take care of this.
Either way what I need to know is if there is a way to achieve that through parameters within the "app" tool, something like:
app --unsecure
app publish --unsecure
app publish-exe --unsecure
Thank you
I've tried a number of different options inclusing using a Custom .NET Core Desktop Apps that adds the disable-web-security switch which used to work:
static int Main(string[] args)
{
var host = new WebHostBuilder()
.UseKestrel()
.UseContentRoot(Directory.GetCurrentDirectory())
.UseStartup<Startup>()
.UseUrls("http://localhost:5000/")
.Build();
host.StartAsync();
var config = new CefConfig(Debug)
{
Args = args,
StartUrl = startUrl,
HideConsoleWindow = false,
OnBeforeCommandLineProcessing = (processType, commandLine) => {
commandLine.AppendSwitch("disable-web-security");
}
};
return CefPlatformWindows.Start(config);
}
But no longer does so appears this security restriction is now embedded inside of Blink.
Using a Proxy to Remove Headers
The only solution I could get to work is to use a proxy that calls the internal .NET Core server which proxies the downstream URL but ignoring the X-Frame-Options header.
This is easy to do using ServiceStack's Proxy Feature where you can register a proxy to https://www.theverge.com that strips the X-Frame-Options header with:
Plugins.Add(new ProxyFeature(
matchingRequests: req => req.PathInfo.StartsWith("/theverge"),
resolveUrl: req => $"https://www.theverge.com" + req.RawUrl.Replace("/theverge", "/")) {
IgnoreResponseHeaders = {
"X-Frame-Options"
}
});
This will let you embed The Verge in your App with:
<iframe src="/theverge" style="width:100%; height:800px;" frameborder="0"></iframe>
Which will render TheVerge in an iframe as expected:
Working Demo
You can find a working example of this in ServiceStack.CefGlue.Win64.AspNetCore:
Startup.cs
public class Startup
{
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
app.UseServiceStack(new AppHost());
app.Run(context =>
{
context.Response.Redirect("/metadata");
return Task.FromResult(0);
});
}
}
public class AppHost : AppHostBase
{
public AppHost() : base("MyApp", typeof(MyServices).Assembly) { }
public override void Configure(Container container)
{
Plugins.Add(new SharpPagesFeature());
Plugins.Add(new ProxyFeature(
matchingRequests: req => req.PathInfo.StartsWith("/theverge"),
resolveUrl: req => "https://www.theverge.com" +
req.RawUrl.Replace("/theverge", "/")) {
IgnoreResponseHeaders = {
"X-Frame-Options"
}
});
}
}
[Route("/hello")]
public class Hello : IReturn<HelloResponse>
{
public string Name { get; set; }
}
public class HelloResponse
{
public string Result { get; set; }
}
public class MyServices : Service
{
public object Any(Hello request) =>
new HelloResponse { Result = $"Hello, {request.Name}!" };
}
ServiceStack.CefGlue.Win64.AspNetCore.csproj
<PackageReference Include="Microsoft.AspNetCore.Server.Kestrel" Version="2.*" />
<PackageReference Include="ServiceStack.CefGlue.Win64" Version="5.*" />
<PackageReference Include="ServiceStack" Version="5.*" />
<PackageReference Include="ServiceStack.CefGlue" Version="5.*" />
<PackageReference Include="ServiceStack.CefGlue.Win64" Version="5.*" />
<PackageReference Include="WinApi" Version="4.0.0" />
You'll also need to copy CEF binaries from the ServiceStack.CefGlue.Win64 NuGet package with:
<ItemGroup>
<Content Include="locales\*.*">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</Content>
<Content Include="swiftshader\*.*">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</Content>
<Content Include="*.pak">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</Content>
<Content Include="*.lib">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</Content>
<Content Include="*.dat">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</Content>
<Content Include="*.dll">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</Content>
<Content Include="*.bin">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</Content>
<Content Include="*.exe">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</Content>
</ItemGroup>
<Target Name="CopyLinkedContentFiles" BeforeTargets="Build">
<Copy SourceFiles="%(Content.Identity)"
DestinationFiles="$(OutputPath)\%(Content.Link)"
SkipUnchangedFiles="true"
OverwriteReadOnlyFiles="true" />
</Target>
index.html
<!DOCTYPE html>
<html lang="en">
<body>
<h1>X-Frame-Options Proxy Test</h1>
<iframe src="/theverge" style="width:100%; height:800px;" frameborder="0"></iframe>
</body>
</html>

What's wrong with my connection string (can not access it through ConfiguratioManager)?

I'm trying to connect to Azure SQL, but I get error The underlying provider failed on Open
I discovered that I have put connection string in the wrong app.config - moved it to the executable project's app.config, but still the same result
When I check ConfigurationManager.ConnectionStrings["AzureDatabase"] it returns null. And when I try to connect it just uses default SQLExpress.
When I check build folder of my executable application - there is an <app_name>.exe.config file with "AzureDatabase". I'm stuck on where to search from here
This is my DbContext class
[DbConfigurationType(typeof(AzureDbConfiguration))]
public class ProductDbContext : DbContext
{
//Db sets
static MyContext()
{
//I don't want to change database from code
Database.SetInitializer<MyContext>(null);
}
public MyContext() : base("AzureDatabase") //this is my connectionstring
{
}
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
//some mappings
}
}
This is AzureDbConfiguration
public class AzureDbConfiguration : DbConfiguration
{
public AzureDbConfiguration()
{
SetExecutionStrategy("System.Data.SqlClient", () => new SqlAzureExecutionStrategy(2, TimeSpan.FromSeconds(10)));
}
}
This is my app.config file
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<configSections>
<!-- For more information on Entity Framework configuration, visit http://go.microsoft.com/fwlink/?LinkID=237468 -->
<section name="entityFramework" type="System.Data.Entity.Internal.ConfigFile.EntityFrameworkSection, EntityFramework, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" requirePermission="false" />
</configSections>
<connectionStrings>
<add name="AzureDatabase"
connectionString="Server=tcp:xxx.database.windows.net,1433;Initial Catalog=xxx;Persist Security Info=False;User ID=xxxx;Password=xxxxx;MultipleActiveResultSets=False;Encrypt=True;TrustServerCertificate=False;Connection Timeout=30;" providerName="System.Data.SqlClient"/>
</connectionStrings>
<entityFramework>
<defaultConnectionFactory type="System.Data.Entity.Infrastructure.LocalDbConnectionFactory, EntityFramework">
<parameters>
<parameter value="mssqllocaldb" />
</parameters>
</defaultConnectionFactory>
<providers>
<provider invariantName="System.Data.SqlClient" type="System.Data.Entity.SqlServer.SqlProviderServices, EntityFramework.SqlServer" />
</providers>
</entityFramework>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5.2" />
</startup>
</configuration>
Any ideas on what's wrong here?
It turns out the problem was that I was trying to work with app.config from Class library (I was trying to create an integration tests)
One of potential solutions is to create a separate settings file for Class library. You can read about it in this StackOverflow post

CakePHP3 plugin test Class 'Cake\TestSuite\IntegrationTestCase' not found

I'm new using this framework and I've found a problem at the moment of testing a plugin.
PHP Fatal error: Class 'Cake\TestSuite\IntegrationTestCase' not found in /var/www/MyApp/plugins/MyPlugin/tests/TestCase/Controller/UsersControllerTest.php on line 11
Running the main application works well, but I have the same problem with all the test's classes of the plugin.
The head of the test's classes is similar to:
<?php
namespace MyPlugin\Test\TestCase\Controller;
use Cake\TestSuite\IntegrationTestCase;
use MyPlugin\Controller\UsersController;
class UsersControllerTest extends IntegrationTestCase
{
The phpunit.xml.dist of the plugin:
<?xml version="1.0" encoding="UTF-8"?><phpunit
colors="true"
processIsolation="false"
stopOnFailure="false"
syntaxCheck="false"
bootstrap="./tests/bootstrap.php"
>
<php>
<ini name="memory_limit" value="-1"/>
<ini name="apc.enable_cli" value="1"/>
</php>
<!-- Add any additional test suites you want to run here -->
<testsuites>
<testsuite name="MyPlugin Test Suite">
<directory>./tests/TestCase</directory>
</testsuite>
</testsuites>
<!-- Setup a listener for fixtures -->
<listeners>
<listener
class="\Cake\TestSuite\Fixture\FixtureInjector"
file="../../vendor/cakephp/cakephp/src/TestSuite/Fixture/FixtureInjector.php">
<arguments>
<object class="\Cake\TestSuite\Fixture\FixtureManager" />
</arguments>
</listener>
</listeners>
<!-- Prevent coverage reports from looking in tests and vendors -->
<filter>
<blacklist>
<directory suffix=".php">./vendor/</directory>
<directory suffix=".ctp">./vendor/</directory>
<directory suffix=".php">./tests/</directory>
<directory suffix=".ctp">./tests/</directory>
</blacklist>
</filter></phpunit>
And the composer.json:
{
"name": "your-name-here/MyPlugin",
"description": "MyPlugin plugin for CakePHP",
"type": "cakephp-plugin",
"require": {
"php": ">=5.4.16",
"cakephp/cakephp": "~3.0"
},
"require-dev": {
"phpunit/phpunit": "*"
},
"autoload": {
"psr-4": {
"MyPlugin\\": "src"
}
},
"autoload-dev": {
"psr-4": {
"MyPlugin\\Test\\": "tests",
"Cake\\Test\\": "/var/www/MyApp/vendor/cakephp/cakephp/tests",
}
}
}
Thanks in advance!! ;)
Finally I got it fixed. In the phpunit.xml.dist file of the plugin, I made the bootstrap point to the one of the main application:
<?xml version="1.0" encoding="UTF-8"?><phpunit
colors="true"
processIsolation="false"
stopOnFailure="false"
syntaxCheck="false"
bootstrap="../../config/bootstrap.php"
>
Also, in the same file, do not forget to make the listener in the same file point to the vendor of the main application, so that you don't have to re-install the entire CakePHP suite in your plugin:
<!-- Setup a listener for fixtures -->
<listeners>
<listener
class="\Cake\TestSuite\Fixture\FixtureInjector"
file="../../vendor/cakephp/cakephp/src/TestSuite/Fixture/FixtureInjector.php">
<arguments>
<object class="\Cake\TestSuite\Fixture\FixtureManager" />
</arguments>
</listener>
</listeners>
It appears that by default, when baking a plugin, these two elements are not set the right way.
You need to run composer install in your plugin folder so that the CakePHP lib in installed under <your-plugin>/vendor/cakephp/cakephp
Since CakePHP 3.7 you should use
Application::addPlugin()
So in setUp() method it would be something like:
public function setUp()
{
parent::setUp();
(new \App\Application(APP . 'config' . DS))->addPlugin('YourPlugin');
//other options
}

FileTransfer is undefined in Cordova

I am working on Cordova tool in Visual studio.
I want to download files via given url, So for that I have installed File and FileTransfer plugins in application.
But it is giving me eror that,
FileTransfer is undefined.
I am writing it after device load.
I read somewhere that I need to activate requestFileSystem first, so I have also tried this code, but fail.
window.requestFileSystem(window.PERSISTENT, 0,
function onFileSystemSuccess(fileSystem) {
fileSystem.root.getFile(
//create a dummy file to get paths
"dummy.html", { create: true, exclusive: false },
function gotFileEntry(fileEntry) {
var sPath = fileEntry.toURL().replace("dummy.html", "");
alert("Path = " + sPath);
//invoke the method to transfer files
var fileTransfer = new FileTransfer();
//remove the dummy file
fileEntry.remove();
//and now, we can download
fileTransfer.download("http://192.168.2.32:8080/MOBILEHRServices/leaveNotifications/getAttachments/2833739", sPath,
function (theFile) {
alert("Succ");
},
function (error) {
alert("Err");
}
);
},
fail);
},
fail);
Second code is,
alert("Start");
var fileTransfer = new FileTransfer();
fileTransfer.download("http://192.168.2.32:8080/MOBILEHRServices/leaveNotifications/getAttachments/2833739", sPath,
function (theFile) {
alert("Succ");
},
function (error) {
alert("Err");
}
);
In both above code FileTransfer() undefined...
Do I need to add anyrhing else too in solution. ?
My config file is,
in visual studio, We can add plugins via wizard...
File and FileTransfer plugins...
<?xml version="1.0" encoding="utf-8"?>
<widget xmlns:cdv="http://cordova.apache.org/ns/1.0" xmlns:vs="http://schemas.microsoft.com/appx/2014/htmlapps" id="io.cordova.down" version="1.0.0.0" xmlns="http://www.w3.org/ns/widgets">
<name>down</name>
<description>A blank project that uses Apache Cordova to help you build an app that targets multiple mobile platforms: Android, iOS, Windows, and Windows Phone.</description>
<author href="http://cordova.io" email="dev#cordova.apache.org">Apache Cordova Team </author>
<content src="index.html" />
<access origin="*" />
<preference name="SplashScreen" value="screen" />
<preference name="windows-target-version" value="8.0" />
<preference name="windows-phone-target-version" value="8.1" />
<vs:plugin name="org.apache.cordova.file" version="1.3.1" />
<vs:plugin name="org.apache.cordova.file-transfer" version="0.4.6" />
<vs:platformSpecificValues />
</widget>
Thank you.

Cassette.Nancy unbundled files returning 404

I've added Cassette.Nancy to an existing Nancy web project. This works fine when I set CassetteNancyStartup.OptimizeOutput = true; but when this is set to false I get 404 on the unbundled resources.
Here's my set up.
I'm using the following packages:
Cassette.Nancy version="2.1.1"
Cassette version="2.4.1"
Nancy version="0.22.2"
Nancy.Owin version="0.22.2"
Nancy.Viewengines.Razor version="0.22.2"
The files are like so:
Content
file1.css
file2.css
Scripts
script1.js
script2.js
CassetteBundleConfiguration:
public class CassetteBundleConfiguration : IConfiguration<BundleCollection>
{
public void Configure(BundleCollection bundles)
{
bundles.AddPerSubDirectory<StylesheetBundle>("Content");
bundles.Add<ScriptBundle>("Scripts");
}
}
in my _Layout.cshtml:
#{
Bundles.Reference("Content");
Bundles.Reference("Scripts");
}
#Bundles.RenderStylesheets()
#Bundles.RenderScripts()
And finally in Bootstrapper:
public Bootstrapper()
{
CassetteNancyStartup.OptimizeOutput = false;
}
Like I say this works fine when CassetteNancyStartup.OptimizeOutput is set to true but when false each of the resources return a 404 like this one:
GET http://localhost:10005/_cassette/asset/Content/file1.css?cf7a7edf515a8184a0c53ec498c583cc64bb0e63 404 (Not Found)
Any suggestions?
This issue was down to me not adding the Owin handler in the web.config. Adding this fixed it.
<system.webServer>
<handlers>
<add name="Owin" verb="*" path="*" type="Microsoft.Owin.Host.SystemWeb.OwinHttpHandler, Microsoft.Owin.Host.SystemWeb" />
</handlers>
</system.webServer>

Resources