├── template
├── module.css
├── README.md
├── _Installation
│ ├── ReleaseNotes.md
│ ├── SQL
│ │ ├── 01.00.00.SqlDataProvider
│ │ └── Uninstall.SqlDataProvider
│ ├── License.txt
│ └── Company.Project.dnn
├── Project.html
├── Common
│ ├── ISettingsStore.cs
│ ├── Globals.cs
│ ├── PortalScopedSettings.cs
│ ├── ModuleScopedSettings.cs
│ ├── TabModuleScopedSettings.cs
│ ├── ProjectApiController.cs
│ ├── RouteMapper.cs
│ ├── ContextSecurity.cs
│ ├── AuditableEntity.cs
│ ├── ModuleSettings.cs
│ ├── ProjectAuthorizeAttribute.cs
│ ├── StringBasedSettings.cs
│ └── Localization.cs
├── Repositories
│ ├── WidgetBaseRepository.cs
│ └── WidgetRepository.cs
├── js
│ └── src
│ │ ├── Widget.js
│ │ ├── Project.js
│ │ └── service.js
├── Project.sln
├── Controllers
│ ├── SettingsController.cs
│ ├── ModuleController.cs
│ ├── WidgetsController.cs
│ └── WidgetsController_Services.cs
├── Models
│ └── Widgets
│ │ ├── Widget.cs
│ │ └── WidgetBase.cs
├── Properties
│ └── AssemblyInfo.cs
├── .gitignore
├── _package.json
├── gulpfile.js
├── Data
│ └── RepositoryImpl.cs
├── App_LocalResources
│ ├── ClientResources.resx
│ └── SharedResources.resx
└── Project.csproj
├── .gitignore
├── .gitattributes
├── .yo-rc.json
├── .travis.yml
├── .editorconfig
├── .jshintrc
├── test
└── test-app.js
├── package.json
├── generators
└── app
│ ├── util.js
│ └── index.js
└── README.md
/template/module.css:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules/
2 |
--------------------------------------------------------------------------------
/.gitattributes:
--------------------------------------------------------------------------------
1 | * text=auto
2 |
--------------------------------------------------------------------------------
/.yo-rc.json:
--------------------------------------------------------------------------------
1 | {
2 | "generator-generator": {}
3 | }
--------------------------------------------------------------------------------
/template/README.md:
--------------------------------------------------------------------------------
1 | # <%= props.organization %> <%= props.projectName %> module
2 |
3 |
--------------------------------------------------------------------------------
/template/_Installation/ReleaseNotes.md:
--------------------------------------------------------------------------------
1 | ## Release Notes
2 | Here are some notes
3 |
4 |
--------------------------------------------------------------------------------
/template/_Installation/SQL/01.00.00.SqlDataProvider:
--------------------------------------------------------------------------------
1 | /*
2 | SQL Install Scripts
3 | */
4 |
--------------------------------------------------------------------------------
/template/_Installation/SQL/Uninstall.SqlDataProvider:
--------------------------------------------------------------------------------
1 | /*
2 | SQL Uninstall Scripts
3 | */
4 |
5 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | sudo: false
2 | language: node_js
3 | node_js:
4 | - 'iojs'
5 | - '0.12'
6 | - '0.10'
7 |
--------------------------------------------------------------------------------
/.editorconfig:
--------------------------------------------------------------------------------
1 | # http://editorconfig.org
2 | root = true
3 |
4 | [*]
5 | indent_style = space
6 | indent_size = 2
7 | charset = utf-8
8 | trim_trailing_whitespace = true
9 | insert_final_newline = true
10 |
11 | [*.md]
12 | trim_trailing_whitespace = false
13 |
--------------------------------------------------------------------------------
/.jshintrc:
--------------------------------------------------------------------------------
1 | {
2 | "node": true,
3 | "esnext": true,
4 | "bitwise": true,
5 | "camelcase": true,
6 | "curly": true,
7 | "eqeqeq": true,
8 | "immed": true,
9 | "indent": 2,
10 | "latedef": true,
11 | "newcap": true,
12 | "noarg": true,
13 | "quotmark": "single",
14 | "undef": true,
15 | "unused": true,
16 | "strict": true
17 | }
18 |
--------------------------------------------------------------------------------
/template/Project.html:
--------------------------------------------------------------------------------
1 | [JavaScript:{ path: "~/DesktopModules/<%= props.organization %>/<%= props.projectName %>/js/react.min.js"}]
2 | [JavaScript:{ path: "~/DesktopModules/<%= props.organization %>/<%= props.projectName %>/js/<%= props.projectName.toLowerCase() %>.js"}]
3 |
4 |
5 |
--------------------------------------------------------------------------------
/template/Common/ISettingsStore.cs:
--------------------------------------------------------------------------------
1 | using System.Runtime.CompilerServices;
2 |
3 | namespace <%= props.organization %>.DNN.Modules.<%= props.projectName %>.Common
4 | {
5 | public interface ISettingsStore
6 | {
7 | T Get(T @default = default(T), [CallerMemberName] string name = null);
8 | void Set(T value, [CallerMemberName] string name = null);
9 | void Save();
10 | }
11 | }
--------------------------------------------------------------------------------
/template/Repositories/WidgetBaseRepository.cs:
--------------------------------------------------------------------------------
1 | using <%= props.organization %>.DNN.Modules.<%= props.projectName %>.Data;
2 | using <%= props.organization %>.DNN.Modules.<%= props.projectName %>.Models.<%= props.widgetName %>s;
3 |
4 | namespace <%= props.organization %>.DNN.Modules.<%= props.projectName %>.Repositories
5 | {
6 | public class <%= props.widgetName %>BaseRepository : RepositoryImpl<<%= props.widgetName %>Base>
7 | {
8 | }
9 | }
10 |
11 |
--------------------------------------------------------------------------------
/template/Repositories/WidgetRepository.cs:
--------------------------------------------------------------------------------
1 | using <%= props.organization %>.DNN.Modules.<%= props.projectName %>.Data;
2 | using <%= props.organization %>.DNN.Modules.<%= props.projectName %>.Models.<%= props.widgetName %>s;
3 |
4 | namespace <%= props.organization %>.DNN.Modules.<%= props.projectName %>.Repositories
5 | {
6 |
7 | public class <%= props.widgetName %>Repository : RepositoryImpl<<%= props.widgetName %>>
8 | {
9 | }
10 |
11 | }
12 |
13 |
--------------------------------------------------------------------------------
/template/Common/Globals.cs:
--------------------------------------------------------------------------------
1 | namespace <%= props.organization %>.DNN.Modules.<%= props.projectName %>.Common
2 | {
3 | public static class Globals
4 | {
5 |
6 | public const string ClientResourceFileName = "~/DesktopModules/<%= props.organization %>/<%= props.projectName %>/App_LocalResources/ClientResources.resx";
7 | public const string SharedResourceFileName = "~/DesktopModules/<%= props.organization %>/<%= props.projectName %>/App_LocalResources/SharedResources.resx";
8 |
9 | }
10 | }
--------------------------------------------------------------------------------
/template/Common/PortalScopedSettings.cs:
--------------------------------------------------------------------------------
1 | using DotNetNuke.Entities.Portals;
2 |
3 | namespace <%= props.organization %>.DNN.Modules.<%= props.projectName %>.Common
4 | {
5 | public class PortalScopedSettings : StringBasedSettings
6 | {
7 | public PortalScopedSettings(int portalId)
8 | : base(
9 | name => PortalController.GetPortalSetting(name, portalId, ""),
10 | (name, value) => PortalController.UpdatePortalSetting(portalId, name, value, true)
11 | )
12 | { }
13 | }
14 | }
--------------------------------------------------------------------------------
/template/Common/ModuleScopedSettings.cs:
--------------------------------------------------------------------------------
1 | using System.Collections;
2 | using DotNetNuke.Entities.Modules;
3 |
4 | namespace <%= props.organization %>.DNN.Modules.<%= props.projectName %>.Common
5 | {
6 | public class ModuleScopedSettings : StringBasedSettings
7 | {
8 | public ModuleScopedSettings(int moduleId, Hashtable moduleSettings)
9 | : base(
10 | name => moduleSettings[name] as string,
11 | (name, value) => new ModuleController().UpdateModuleSetting(moduleId, name, value)
12 | ) { }
13 | }
14 | }
--------------------------------------------------------------------------------
/template/Common/TabModuleScopedSettings.cs:
--------------------------------------------------------------------------------
1 | using System.Collections;
2 | using DotNetNuke.Entities.Modules;
3 |
4 | namespace <%= props.organization %>.DNN.Modules.<%= props.projectName %>.Common
5 | {
6 | public class TabModuleScopedSettings : StringBasedSettings
7 | {
8 | public TabModuleScopedSettings(int tabModuleId, Hashtable moduleSettings)
9 | : base(
10 | name => moduleSettings[name] as string,
11 | (name, value) => new ModuleController().UpdateTabModuleSetting(tabModuleId, name, value)
12 | ) { }
13 | }
14 | }
--------------------------------------------------------------------------------
/test/test-app.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var path = require('path');
4 | var assert = require('yeoman-generator').assert;
5 | var helpers = require('yeoman-generator').test;
6 | var os = require('os');
7 |
8 | describe('dnn-spa-gulp-react:app', function () {
9 | before(function (done) {
10 | helpers.run(path.join(__dirname, '../generators/app'))
11 | .withOptions({ skipInstall: true })
12 | .withPrompts({ someOption: true })
13 | .on('end', done);
14 | });
15 |
16 | it('creates files', function () {
17 | assert.file([
18 | 'bower.json',
19 | 'package.json',
20 | '.editorconfig',
21 | '.jshintrc'
22 | ]);
23 | });
24 | });
25 |
--------------------------------------------------------------------------------
/template/Common/ProjectApiController.cs:
--------------------------------------------------------------------------------
1 | using DotNetNuke.Web.Api;
2 |
3 | namespace <%= props.organization %>.DNN.Modules.<%= props.projectName %>.Common
4 | {
5 | public abstract class <%= props.projectName %>ApiController : DnnApiController
6 | {
7 | private ModuleSettings _settings;
8 | public ModuleSettings Settings
9 | {
10 | get { return _settings ?? (_settings = ModuleSettings.GetSettings(ActiveModule)); }
11 | set { _settings = value; }
12 | }
13 |
14 | private ContextSecurity _security;
15 | public ContextSecurity Security
16 | {
17 | get { return _security ?? (_security = new ContextSecurity(ActiveModule)); }
18 | set { _security = value; }
19 | }
20 |
21 | }
22 | }
--------------------------------------------------------------------------------
/template/Common/RouteMapper.cs:
--------------------------------------------------------------------------------
1 | using DotNetNuke.Web.Api;
2 |
3 | namespace <%= props.organization %>.DNN.Modules.<%= props.projectName %>.Common
4 | {
5 | public class RouteMapper : IServiceRouteMapper
6 | {
7 |
8 | #region IServiceRouteMapper
9 | public void RegisterRoutes(IMapRoute routeManager)
10 | {
11 | routeManager.MapHttpRoute("<%= props.organization %>/<%= props.projectName %>", "<%= props.organization %><%= props.projectName %>1", "{controller}/{action}", null, null, new[] { "<%= props.organization %>.DNN.Modules.<%= props.projectName %>.Controllers" });
12 | routeManager.MapHttpRoute("<%= props.organization %>/<%= props.projectName %>", "<%= props.organization %><%= props.projectName %>2", "{controller}/{action}/{id}", null, new { id = "\\d*" }, new[] { "<%= props.organization %>.DNN.Modules.<%= props.projectName %>.Controllers" });
13 | }
14 | #endregion
15 |
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/template/js/src/Widget.js:
--------------------------------------------------------------------------------
1 | /** @jsx React.DOM */
2 | var <%= props.widgetName %>Component = React.createClass({
3 |
4 | getInitialState: function() {
5 | return {
6 | moduleId: this.props.moduleId,
7 | service: <%= props.organization %><%= props.projectName %>.modules[this.props.moduleId].service,
8 | security: <%= props.organization %><%= props.projectName %>.modules[this.props.moduleId].security,
9 | settings: <%= props.organization %><%= props.projectName %>.modules[this.props.moduleId].settings,
10 | resources: <%= props.organization %><%= props.projectName %>.modules[this.props.moduleId].resources
11 | }
12 | },
13 |
14 | shouldComponentUpdate: function(nextProps, nextState) {
15 | return nextState.settings !== this.state.settings;
16 | },
17 |
18 | render: function() {
19 | return (
20 |
21 | Hello World
22 |
23 | );
24 | }
25 |
26 | });
27 |
28 | module.exports = <%= props.organization %><%= props.projectName %>Component;
29 |
--------------------------------------------------------------------------------
/template/Common/ContextSecurity.cs:
--------------------------------------------------------------------------------
1 | using DotNetNuke.Entities.Modules;
2 | using DotNetNuke.Entities.Portals;
3 | using DotNetNuke.Entities.Users;
4 | using DotNetNuke.Security;
5 | using DotNetNuke.Security.Permissions;
6 |
7 | namespace <%= props.organization %>.DNN.Modules.<%= props.projectName %>.Common
8 | {
9 | public class ContextSecurity
10 | {
11 | public bool CanView { get; set; }
12 | public bool CanEdit { get; set; }
13 | public bool IsAdmin { get; set; }
14 | public int UserId { get; set; }
15 |
16 | #region ctor
17 | public ContextSecurity(ModuleInfo objModule)
18 | {
19 | UserId = UserController.Instance.GetCurrentUserInfo().UserID;
20 | CanView = ModulePermissionController.CanViewModule(objModule);
21 | CanEdit = ModulePermissionController.HasModulePermission(objModule.ModulePermissions, "EDIT");
22 | IsAdmin = PortalSecurity.IsInRole(PortalSettings.Current.AdministratorRoleName);
23 | }
24 | #endregion
25 |
26 | }
27 | }
--------------------------------------------------------------------------------
/template/Project.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio 2013
4 | VisualStudioVersion = 12.0.31101.0
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "<%= props.projectName %>", "<%= props.projectName %>.csproj", "{7D61A32C-0F21-453F-A981-BD8E5A3A5304}"
7 | EndProject
8 | Global
9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
10 | Debug|Any CPU = Debug|Any CPU
11 | Release|Any CPU = Release|Any CPU
12 | EndGlobalSection
13 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
14 | {7D61A32C-0F21-453F-A981-BD8E5A3A5304}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
15 | {7D61A32C-0F21-453F-A981-BD8E5A3A5304}.Debug|Any CPU.Build.0 = Debug|Any CPU
16 | {7D61A32C-0F21-453F-A981-BD8E5A3A5304}.Release|Any CPU.ActiveCfg = Release|Any CPU
17 | {7D61A32C-0F21-453F-A981-BD8E5A3A5304}.Release|Any CPU.Build.0 = Release|Any CPU
18 | EndGlobalSection
19 | GlobalSection(SolutionProperties) = preSolution
20 | HideSolutionNode = FALSE
21 | EndGlobalSection
22 | EndGlobal
23 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "generator-dnn-spa-gulp-react",
3 | "version": "0.1.2",
4 | "description": "Yeoman generator for a DNN SPA module using Gulp and React",
5 | "license": "MIT",
6 | "main": "app/index.js",
7 | "repository": {
8 | "type": "git",
9 | "url": "https://github.com/donker/generator-dnn-spa-gulp-react.git"
10 | },
11 | "bugs": {
12 | "url": "https://github.com/donker/generator-dnn-spa-gulp-react/issues"
13 | },
14 | "homepage": "https://github.com/donker/generator-dnn-spa-gulp-react#readme",
15 | "author": {
16 | "name": "Peter Donker",
17 | "email": "peter@bring2mind.net",
18 | "url": "https://github.com/donker"
19 | },
20 | "scripts": {
21 | "test": "mocha"
22 | },
23 | "files": [
24 | "generators",
25 | "template"
26 | ],
27 | "keywords": [
28 | "yeoman-generator"
29 | ],
30 | "dependencies": {
31 | "yeoman-generator": "^0.19.0",
32 | "extend": "^3.0.0",
33 | "chalk": "^1.0.0",
34 | "yosay": "^1.0.2"
35 | },
36 | "devDependencies": {
37 | "mocha": "*"
38 | },
39 | "directories": {}
40 | }
41 |
--------------------------------------------------------------------------------
/template/Controllers/SettingsController.cs:
--------------------------------------------------------------------------------
1 | using System.Net;
2 | using System.Net.Http;
3 | using System.Web.Http;
4 | using <%= props.organization %>.DNN.Modules.<%= props.projectName %>.Common;
5 | using DotNetNuke.Web.Api;
6 |
7 | namespace <%= props.organization %>.DNN.Modules.<%= props.projectName %>.Controllers
8 | {
9 |
10 | public partial class SettingsController : <%= props.projectName %>ApiController
11 | {
12 | public class SettingsDTO
13 | {
14 | public int MySetting { get; set; }
15 | }
16 |
17 |
18 | #region Service Methods
19 | [HttpPost]
20 | [MapAuthorize(SecurityLevel = SecurityAccessLevel.Edit)]
21 | [ValidateAntiForgeryToken]
22 | public HttpResponseMessage Update(SettingsDTO newSettings)
23 | {
24 | var oldSettings = ModuleSettings.GetSettings(ActiveModule);
25 | oldSettings.MySetting = newSettings.MySetting;
26 | oldSettings.SaveSettings();
27 | return Request.CreateResponse(HttpStatusCode.OK, oldSettings);
28 | }
29 | #endregion
30 |
31 | }
32 | }
33 |
34 |
--------------------------------------------------------------------------------
/generators/app/util.js:
--------------------------------------------------------------------------------
1 | var fs = require('fs');
2 |
3 | module.exports = {
4 |
5 | getFilesRecursive: function(basePath, path) {
6 | var that = this;
7 | var foundPaths = [];
8 | var files = fs.readdirSync(basePath + '/' + path);
9 | files.forEach(function(el, i, arr) {
10 | var newPath = basePath + '/' + path + '/' + el;
11 | var st = fs.statSync(newPath);
12 | if (st.isDirectory()) {
13 | if (path === '') {
14 | foundPaths = foundPaths.concat(that.getFilesRecursive(basePath, el));
15 | } else {
16 | foundPaths = foundPaths.concat(that.getFilesRecursive(basePath, path + '/' + el));
17 | }
18 | } else {
19 | if (path === '') {
20 | foundPaths.push(el);
21 | } else {
22 | foundPaths.push(path + '/' + el);
23 | }
24 | }
25 | });
26 | return foundPaths;
27 | },
28 |
29 | ensureFolder: function(path) {
30 | try {
31 | stats = fs.lstatSync(path);
32 | if (stats.isDirectory()) {
33 | return;
34 | }
35 | } catch (e) {
36 | fs.mkdir(path);
37 | }
38 | }
39 |
40 | }
41 |
--------------------------------------------------------------------------------
/template/Common/AuditableEntity.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Data;
3 | using System.Runtime.Serialization;
4 | using DotNetNuke.Common.Utilities;
5 |
6 | namespace <%= props.organization %>.DNN.Modules.<%= props.projectName %>.Common
7 | {
8 |
9 | [DataContract]
10 | public abstract class AuditableEntity
11 | {
12 |
13 | public void FillAuditFields(IDataReader dr)
14 | {
15 | CreatedByUserID = Convert.ToInt32(Null.SetNull(dr["CreatedByUserID"], CreatedByUserID));
16 | CreatedOnDate = Convert.ToDateTime(Null.SetNull(dr["CreatedOnDate"], CreatedOnDate));
17 | LastModifiedByUserID = Convert.ToInt32(Null.SetNull(dr["LastModifiedByUserID"], LastModifiedByUserID));
18 | LastModifiedOnDate = Convert.ToDateTime(Null.SetNull(dr["LastModifiedOnDate"], LastModifiedOnDate));
19 | }
20 |
21 | #region Public Properties
22 | [DataMember]
23 | public int CreatedByUserID { get; set; }
24 | [DataMember]
25 | public DateTime CreatedOnDate { get; set; }
26 | [DataMember]
27 | public int LastModifiedByUserID { get; set; }
28 | [DataMember]
29 | public DateTime LastModifiedOnDate { get; set; }
30 | #endregion
31 |
32 |
33 | }
34 | }
35 |
36 |
--------------------------------------------------------------------------------
/template/_Installation/License.txt:
--------------------------------------------------------------------------------
1 | <%= props.organization %> - <%= props.url %>
2 | Copyright (c) 2002-2015
3 | by <%= props.organization %>
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
6 | documentation files (the "Software"), to deal in the Software without restriction, including without limitation
7 | the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and
8 | to permit persons to whom the Software is furnished to do so, subject to the following conditions:
9 |
10 | The above copyright notice and this permission notice shall be included in all copies or substantial portions
11 | of the Software.
12 |
13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
14 | TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
15 | THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
16 | CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
17 | DEALINGS IN THE SOFTWARE.
18 |
--------------------------------------------------------------------------------
/template/_Installation/Company.Project.dnn:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | <%= props.organization %>_<%= props.projectName %>
8 | <%= props.organization %>/<%= props.projectName %>
9 |
10 |
11 |
12 | <%= props.organization %> <%= props.projectName %>
13 | 0
14 |
15 |
16 |
17 | DesktopModules/<%= props.organization %>/<%= props.projectName %>/<%= props.projectName %>.html
18 | False
19 |
20 | View
21 |
22 |
23 | 0
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
--------------------------------------------------------------------------------
/template/Models/Widgets/Widget.cs:
--------------------------------------------------------------------------------
1 | using System.Runtime.Serialization;
2 | using DotNetNuke.ComponentModel.DataAnnotations;
3 |
4 | namespace <%= props.organization %>.DNN.Modules.<%= props.projectName %>.Models.<%= props.widgetName %>s
5 | {
6 |
7 | [TableName("vw_<%= props.organization %>_<%= props.projectName %>_<%= props.widgetName %>s")]
8 | [PrimaryKey("<%= props.widgetName %>Id", AutoIncrement = true)]
9 | [Scope("ModuleId")]
10 | [DataContract]
11 | public class <%= props.widgetName %> : <%= props.widgetName %>Base
12 | {
13 |
14 | #region Public Properties
15 | [DataMember]
16 | public string CreatedByUser { get; set; }
17 | [DataMember]
18 | public string LastModifiedByUser { get; set; }
19 | #endregion
20 |
21 | #region Public Methods
22 | public <%= props.widgetName %>Base Get<%= props.widgetName %>Base()
23 | {
24 | <%= props.widgetName %>Base res = new <%= props.widgetName %>Base();
25 | res.CreatedByUserID = CreatedByUserID;
26 | res.CreatedOnDate = CreatedOnDate;
27 | res.LastModifiedByUserID = LastModifiedByUserID;
28 | res.LastModifiedOnDate = LastModifiedOnDate;
29 | res.<%= props.widgetName %>Id = <%= props.widgetName %>Id;
30 | res.ModuleId = ModuleId;
31 | res.Message = Message;
32 | return res;
33 | }
34 | #endregion
35 |
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/template/Controllers/ModuleController.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using System.Net;
3 | using System.Net.Http;
4 | using System.Web.Http;
5 | using <%= props.organization %>.DNN.Modules.<%= props.projectName %>.Common;
6 |
7 | namespace <%= props.organization %>.DNN.Modules.<%= props.projectName %>.Controllers
8 | {
9 |
10 | public partial class ModuleController : <%= props.projectName %>ApiController
11 | {
12 |
13 | public class InitData
14 | {
15 | public ModuleSettings Settings { get; set; }
16 | public IEnumerable<<%= props.widgetName %>> <%= props.widgetName %>s { get; set; }
17 | public ContextSecurity Security { get; set; }
18 | public Dictionary ClientResources { get; set; }
19 | }
20 |
21 | #region Service Methods
22 | [HttpGet]
23 | [<%= props.projectName %>Authorize(SecurityLevel = SecurityAccessLevel.View)]
24 | public HttpResponseMessage InitialData()
25 | {
26 | InitData init = new InitData();
27 | init.Settings = ModuleSettings.GetSettings(ActiveModule);
28 | init.Security = new ContextSecurity(ActiveModule);
29 | init.ClientResources = Localization.GetResourceFile(PortalSettings, ClientResourceFileName,
30 | System.Threading.Thread.CurrentThread.CurrentCulture.Name);
31 | return Request.CreateResponse(HttpStatusCode.OK, init);
32 | }
33 | #endregion
34 |
35 | }
36 | }
37 |
38 |
--------------------------------------------------------------------------------
/template/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 | using System.Runtime.InteropServices;
3 |
4 | // General Information about an assembly is controlled through the following
5 | // set of attributes. Change these attribute values to modify the information
6 | // associated with an assembly.
7 | [assembly: AssemblyTitle("<%= props.projectName %> Module")]
8 | [assembly: AssemblyDescription("")]
9 | [assembly: AssemblyConfiguration("")]
10 | [assembly: AssemblyCompany("<%= props.organization %>")]
11 | [assembly: AssemblyProduct("<%= props.projectName %>")]
12 | [assembly: AssemblyCopyright("Copyright 2015 by <%= props.organization %>")]
13 | [assembly: AssemblyTrademark("")]
14 | [assembly: AssemblyCulture("")]
15 |
16 | // Setting ComVisible to false makes the types in this assembly not visible
17 | // to COM components. If you need to access a type in this assembly from
18 | // COM, set the ComVisible attribute to true on that type.
19 | [assembly: ComVisible(false)]
20 |
21 | // The following GUID is for the ID of the typelib if this project is exposed to COM
22 | [assembly: Guid("5ef01dd5-84a1-49f3-9232-067440288455")]
23 |
24 | // Version information for an assembly consists of the following four values:
25 | //
26 | // Major Version
27 | // Minor Version
28 | // Build Number
29 | // Revision
30 | //
31 | // You can specify all the values or you can default the Revision and Build Numbers
32 | // by using the '*' as shown below:
33 | [assembly: AssemblyVersion("01.00.00")]
34 | [assembly: AssemblyFileVersion("01.00.00")]
35 |
--------------------------------------------------------------------------------
/template/js/src/Project.js:
--------------------------------------------------------------------------------
1 | /** @jsx React.DOM */
2 | var <%= props.organization %><%= props.projectName %>Component = require('./<%= props.widgetName %>'),
3 | <%= props.projectName %>Service = require('./service');
4 |
5 | ;
6 | (function($, window, document, undefined) {
7 |
8 | $(document).ready(function() {
9 | <%= props.organization %><%= props.projectName %>.loadData();
10 | });
11 |
12 | window.<%= props.organization %><%= props.projectName %> = {
13 | modules: {},
14 |
15 | loadData: function() {
16 | $('.<%= props.organization %><%= props.projectName %>').each(function(i, el) {
17 | var moduleId = $(el).data('moduleid');
18 | var newModule = {
19 | service: new <%= props.projectName %>Service($, moduleId)
20 | };
21 | <%= props.organization %><%= props.projectName %>.modules[moduleId] = newModule;
22 | <%= props.organization %><%= props.projectName %>.modules[moduleId].service.getInitialData(function(data) {
23 | <%= props.organization %><%= props.projectName %>.modules[moduleId].settings = data.Settings;
24 | <%= props.organization %><%= props.projectName %>.modules[moduleId].<%= props.widgetName %>s = data.<%= props.widgetName %>s;
25 | <%= props.organization %><%= props.projectName %>.modules[moduleId].security = data.Security;
26 | <%= props.organization %><%= props.projectName %>.modules[moduleId].resources = data.ClientResources;
27 | });
28 | });
29 | }
30 |
31 | }
32 |
33 |
34 | })(jQuery, window, document);
35 |
--------------------------------------------------------------------------------
/template/Models/Widgets/WidgetBase.cs:
--------------------------------------------------------------------------------
1 |
2 | using System;
3 | using System.Runtime.Serialization;
4 | using <%= props.organization %>.DNN.Modules.<%= props.projectName %>.Common;
5 | using DotNetNuke.ComponentModel.DataAnnotations;
6 |
7 | namespace <%= props.organization %>.DNN.Modules.<%= props.projectName %>.Models.<%= props.widgetName %>s
8 | {
9 | [TableName("<%= props.organization %>_<%= props.projectName %>_<%= props.widgetName %>s")]
10 | [PrimaryKey("<%= props.widgetName %>Id", AutoIncrement = true)]
11 | [Scope("ModuleId")]
12 | [DataContract]
13 | public class <%= props.widgetName %>Base : AuditableEntity
14 | {
15 |
16 | #region Public Properties
17 | [DataMember]
18 | public int <%= props.widgetName %>Id { get; set; }
19 | [DataMember]
20 | public int ModuleId { get; set; }
21 | [DataMember]
22 | public string Message { get; set; }
23 | #endregion
24 |
25 | #region Methods
26 | public void Read<%= props.widgetName %>Base(<%= props.widgetName %>Base <%= props.widgetName %>)
27 | {
28 | if (<%= props.widgetName %>.<%= props.widgetName %>Id > -1)
29 | <%= props.widgetName %>Id = <%= props.widgetName %>.<%= props.widgetName %>Id;
30 |
31 | if (<%= props.widgetName %>.ModuleId > -1)
32 | ModuleId = <%= props.widgetName %>.ModuleId;
33 |
34 | if (!String.IsNullOrEmpty(<%= props.widgetName %>.Message))
35 | Message = <%= props.widgetName %>.Message;
36 |
37 | }
38 | #endregion
39 |
40 | }
41 | }
42 |
43 |
44 |
45 |
--------------------------------------------------------------------------------
/template/js/src/service.js:
--------------------------------------------------------------------------------
1 | var <%= props.organization %><%= props.projectName %>Service = function ($, mid) {
2 | var moduleId = mid;
3 | var baseServicepath = $.dnnSF(moduleId).getServiceRoot('<%= props.organization %>/<%= props.projectName %>');
4 |
5 | this.ajaxCall = function(type, controller, action, id, data, success, fail) {
6 | // showLoading();
7 | $.ajax({
8 | type: type,
9 | url: baseServicepath + controller + '/' + action + (id != null ? '/' + id : ''),
10 | beforeSend: $.dnnSF(moduleId).setModuleHeaders,
11 | data: data
12 | }).done(function(retdata) {
13 | // hideLoading();
14 | if (success != undefined) {
15 | success(retdata);
16 | }
17 | }).fail(function(xhr, status) {
18 | // showError(xhr.responseText);
19 | if (fail != undefined) {
20 | fail(xhr.responseText);
21 | }
22 | });
23 | }
24 |
25 | this.getInitialData = function(success) {
26 | this.ajaxCall('GET', 'Module', 'InitialData', null, null, success);
27 | }
28 |
29 | this.updateSettings = function(newSettings, success) {
30 | this.ajaxCall('POST', 'Settings', 'Update', null, newSettings, success);
31 | }
32 |
33 | this.submitPoint = function(new<%= props.widgetName %>, success) {
34 | this.ajaxCall('POST', '<%= props.widgetName %>s', '<%= props.widgetName %>', null, new<%= props.widgetName %>, success);
35 | }
36 |
37 | this.deletePoint = function(id, success) {
38 | this.ajaxCall('POST', '<%= props.widgetName %>s', 'Delete', id, null, success);
39 | }
40 |
41 | }
42 |
43 | module.exports = <%= props.organization %><%= props.projectName %>Service;
44 |
--------------------------------------------------------------------------------
/template/Common/ModuleSettings.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Web.Caching;
3 | using DotNetNuke.Common.Utilities;
4 | using DotNetNuke.Entities.Modules;
5 |
6 | namespace <%= props.organization %>.DNN.Modules.<%= props.projectName %>.Common
7 | {
8 | public class ModuleSettings
9 | {
10 |
11 | #region Properties
12 | internal ISettingsStore TmsStore;
13 | internal ISettingsStore MsStore;
14 | internal ISettingsStore PsStore;
15 | public int MySetting { get { return TmsStore.Get(1); } set { TmsStore.Set(value); } }
16 | public string Version = typeof(ModuleSettings).Assembly.GetName().Version.ToString();
17 | #endregion
18 |
19 | #region .ctor
20 | public ModuleSettings(ModuleInfo ctlModule)
21 | {
22 | PsStore = new PortalScopedSettings(ctlModule.PortalID);
23 | MsStore = new ModuleScopedSettings(ctlModule.ModuleID, ctlModule.ModuleSettings);
24 | TmsStore = new TabModuleScopedSettings(ctlModule.TabModuleID, ctlModule.TabModuleSettings);
25 | }
26 | #endregion
27 |
28 | #region Public Members
29 | public void SaveSettings()
30 | {
31 | PsStore.Save();
32 | MsStore.Save();
33 | TmsStore.Save();
34 | }
35 |
36 | public static ModuleSettings GetSettings(ModuleInfo ctlModule)
37 | {
38 | return CBO.GetCachedObject(new CacheItemArgs(CacheKey(ctlModule.TabModuleID), 20, CacheItemPriority.AboveNormal),
39 | cacheItemArgs => new ModuleSettings(ctlModule),
40 | true);
41 | }
42 |
43 | public static string CacheKey(int moduleId)
44 | {
45 | return string.Format("SettingsModule{0}", moduleId);
46 | }
47 | #endregion
48 |
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/template/.gitignore:
--------------------------------------------------------------------------------
1 | # Build and Object Folders
2 | bin/
3 | obj/
4 |
5 | #User Specific Files
6 | *.user
7 | *.suo
8 |
9 | ## Ignore Visual Studio temporary files, build results, and
10 | ## files generated by popular Visual Studio add-ons.
11 |
12 | # User-specific files
13 | *.suo
14 | *.user
15 | *.sln.docstates
16 |
17 | # Build results
18 | [Dd]ebug/
19 | [Rr]elease/
20 | x64/
21 | *_i.c
22 | *_p.c
23 | *.ilk
24 | *.meta
25 | *.obj
26 | *.pch
27 | *.pdb
28 | *.pgc
29 | *.pgd
30 | *.rsp
31 | *.sbr
32 | *.tlb
33 | *.tli
34 | *.tlh
35 | *.tmp
36 | *.log
37 | *.vspscc
38 | *.vssscc
39 | .builds
40 |
41 | # Visual C++ cache files
42 | ipch/
43 | *.aps
44 | *.ncb
45 | *.opensdf
46 | *.sdf
47 |
48 | # Visual Studio profiler
49 | *.psess
50 | *.vsp
51 | *.vspx
52 |
53 | # Guidance Automation Toolkit
54 | *.gpState
55 |
56 | # ReSharper is a .NET coding add-in
57 | _ReSharper*
58 |
59 | # NCrunch
60 | *.ncrunch*
61 | .*crunch*.local.xml
62 |
63 | # Installshield output folder
64 | [Ee]xpress
65 |
66 | # DocProject is a documentation generator add-in
67 | DocProject/buildhelp/
68 | DocProject/Help/*.HxT
69 | DocProject/Help/*.HxC
70 | DocProject/Help/*.hhc
71 | DocProject/Help/*.hhk
72 | DocProject/Help/*.hhp
73 | DocProject/Help/Html2
74 | DocProject/Help/html
75 |
76 | # Click-Once directory
77 | publish
78 |
79 | # Publish Web Output
80 | *.Publish.xml
81 |
82 | # Others
83 | [Bb]in
84 | [Oo]bj
85 | TestResults
86 | [Tt]est[Rr]esult*
87 | *.Cache
88 | ClientBin
89 | [Ss]tyle[Cc]op.*
90 | ~$*
91 | *.dbmdl
92 | Generated_Code #added for RIA/Silverlight projects
93 |
94 | # mac stuff
95 | *DS_Store
96 |
97 | # Backup & report files from converting an old project file to a newer
98 | # Visual Studio version. Backup files are not needed, because we have git ;-)
99 | _UpgradeReport_Files/
100 | Backup*/
101 | UpgradeLog*.XML
102 |
103 | node_modules
104 | bower_components
105 | _Packages
106 | js/*.js
107 |
108 |
109 |
--------------------------------------------------------------------------------
/template/Common/ProjectAuthorizeAttribute.cs:
--------------------------------------------------------------------------------
1 | using DotNetNuke.Common;
2 | using DotNetNuke.Entities.Users;
3 | using DotNetNuke.Web.Api;
4 |
5 | namespace <%= props.organization %>.DNN.Modules.<%= props.projectName %>.Common
6 | {
7 | public enum SecurityAccessLevel
8 | {
9 | Anonymous = 0,
10 | View = 1,
11 | Edit = 2,
12 | Admin = 3,
13 | Host = 4
14 | }
15 |
16 | public class <%= props.projectName %>AuthorizeAttribute : AuthorizeAttributeBase, IOverrideDefaultAuthLevel
17 | {
18 | public SecurityAccessLevel SecurityLevel { get; set; }
19 | public UserInfo User { get; set; }
20 |
21 | public <%= props.projectName %>AuthorizeAttribute()
22 | {
23 | SecurityLevel = SecurityAccessLevel.Admin;
24 | }
25 |
26 | public <%= props.projectName %>AuthorizeAttribute(SecurityAccessLevel accessLevel)
27 | {
28 | SecurityLevel = accessLevel;
29 | }
30 |
31 | public override bool IsAuthorized(AuthFilterContext context)
32 | {
33 | if (SecurityLevel == SecurityAccessLevel.Anonymous)
34 | {
35 | return true;
36 | }
37 | User = HttpContextSource.Current.Request.IsAuthenticated ? UserController.Instance.GetCurrentUserInfo() : new UserInfo();
38 | ContextSecurity security = new ContextSecurity(context.ActionContext.Request.FindModuleInfo());
39 | switch (SecurityLevel)
40 | {
41 | case SecurityAccessLevel.Host:
42 | return User.IsSuperUser;
43 | case SecurityAccessLevel.Admin:
44 | return security.IsAdmin | User.IsSuperUser;
45 | case SecurityAccessLevel.Edit:
46 | return security.CanEdit | security.IsAdmin | User.IsSuperUser;
47 | case SecurityAccessLevel.View:
48 | return security.CanView;
49 | }
50 |
51 | return false;
52 | }
53 | }
54 | }
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # DNN SPA Module generator with Gulp and React
2 |
3 | > A [Yeoman](http://yeoman.io) generator
4 |
5 | This generator scaffolds out a module leveraging DNN's SPA module pattern. Included are references to Gulp and React so if you're using those then you'll hit the road running. This generator *must be run in the DesktopModules folder*. It will create subfolders for the organization and module name based on your input. It will allow you to store common settings such as name, email etc to the generator's settings so you don't need to type them in every time you create a module.
6 |
7 | ## Getting Started
8 |
9 | ### What is Yeoman? (skip if you know Yeoman and have it installed)
10 |
11 | Head over to the [Yeoman site](http://yeoman.io) for in-depth info. Basically it is a code generator based on templates called "generators". You can install Yeoman using npm (i.e. you also need Node js installed first!) as follows:
12 |
13 | ```bash
14 | npm install -g yo
15 | ```
16 |
17 | ### Installing the DNN SPA module generator
18 |
19 | To install this generator, run:
20 |
21 | ```bash
22 | npm install -g generator-dnn-spa-gulp-react
23 | ```
24 |
25 | ### Use
26 |
27 | Now, head over to the DesktopModules folder of your project, start a shell and type:
28 |
29 | ```bash
30 | yo dnn-spa-gulp-react
31 | ```
32 |
33 | This will prompt you with a few questions, some of which are mandatory to answer as they are used to configure the module:
34 |
35 | 1. Project name. Use a short name without special characters or spaces as it is used for namespaces and folders. (e.g. "Map")
36 | 2. Primary object name. This is the name of the primary object of your module that you're managing. You can leave this as-is. Again a short name without special characters or spaces (e.g. MapPoints).
37 | 3. Organization name. Used to create the subfolder and namespaces as well. So like the above without special characters or spaces, please (e.g. DNNConnect).
38 | 4. Url. Url of your organization or any other url you'd like to use for this project. It's used in the DNN manifest.
39 | 5. Your name. Used in the manifest.
40 | 6. Email. Used in the manifest.
41 |
42 | Finally the generator will ask if you wish to overwrite the old settings in the template so that any subsequent module generations will prompt the same name, email, etc.
43 |
44 | ## License
45 |
46 | MIT
47 |
--------------------------------------------------------------------------------
/template/Controllers/WidgetsController.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using <%= props.organization %>.DNN.Modules.<%= props.projectName %>.Models.<%= props.widgetName %>s;
4 | using <%= props.organization %>.DNN.Modules.<%= props.projectName %>.Repositories;
5 |
6 | namespace <%= props.organization %>.DNN.Modules.<%= props.projectName %>.Controllers
7 | {
8 |
9 | public partial class <%= props.widgetName %>sController
10 | {
11 |
12 | public static IEnumerable<<%= props.widgetName %>> Get<%= props.widgetName %>s(int moduleId)
13 | {
14 | <%= props.widgetName %>Repository repo = new <%= props.widgetName %>Repository();
15 | return repo.Get(moduleId);
16 | }
17 |
18 | public static <%= props.widgetName %> Get<%= props.widgetName %>(int <%= props.widgetName %>Id, int moduleId)
19 | {
20 | <%= props.widgetName %>Repository repo = new <%= props.widgetName %>Repository();
21 | return repo.GetById(<%= props.widgetName %>Id, moduleId);
22 | }
23 |
24 | public static int Add<%= props.widgetName %>(ref <%= props.widgetName %>Base <%= props.widgetName %>, int userId)
25 | {
26 | <%= props.widgetName %>.CreatedByUserID = userId;
27 | <%= props.widgetName %>.CreatedOnDate = DateTime.Now;
28 | <%= props.widgetName %>.LastModifiedByUserID = userId;
29 | <%= props.widgetName %>.LastModifiedOnDate = DateTime.Now;
30 | <%= props.widgetName %>BaseRepository repo = new <%= props.widgetName %>BaseRepository();
31 | repo.Insert(<%= props.widgetName %>);
32 | return <%= props.widgetName %>.<%= props.widgetName %>Id;
33 | }
34 |
35 | public static void Update<%= props.widgetName %>(<%= props.widgetName %>Base <%= props.widgetName %>, int userId)
36 | {
37 | <%= props.widgetName %>.LastModifiedByUserID = userId;
38 | <%= props.widgetName %>.LastModifiedOnDate = DateTime.Now;
39 | <%= props.widgetName %>BaseRepository repo = new <%= props.widgetName %>BaseRepository();
40 | repo.Update(<%= props.widgetName %>);
41 | }
42 |
43 | public static void Delete<%= props.widgetName %>(<%= props.widgetName %>Base <%= props.widgetName %>)
44 | {
45 | <%= props.widgetName %>BaseRepository repo = new <%= props.widgetName %>BaseRepository();
46 | repo.Delete(<%= props.widgetName %>);
47 | }
48 |
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/template/_package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "<%= props.projectName %>",
3 | "version": "01.00.00",
4 | "description": "Demo module used at DNN <%= props.organization %> 2015",
5 | "dnnModule": {
6 | "fullName": "<%= props.organization %>.<%= props.projectName %>",
7 | "friendlyName": "<%= props.projectName %> Module",
8 | "packageName": "<%= props.organization %>_<%= props.projectName %>",
9 | "owner": {
10 | "name": "<%= props.name %>",
11 | "organization": "<%= props.organization %>",
12 | "url": "<%= props.url %>.org",
13 | "email": "<%= props.email %>"
14 | },
15 | "module": {
16 | "packageName": "<%= props.organization %>_<%= props.projectName %>",
17 | "folderName": "<%= props.organization %>/<%= props.projectName %>",
18 | "azureCompatible": "true",
19 | "iconFile": "DesktopModules\\<%= props.organization %>\\<%= props.projectName %>\\<%= props.projectName.toLowerCase() %>.png"
20 | },
21 | "tempPath": "./package",
22 | "packagesPath": "./_Packages",
23 | "pathToAssemblies": "./bin",
24 | "pathToScripts": "./_Installation/SQL",
25 | "pathToSupplementaryFiles": "./_Installation",
26 | "excludeFilter": [
27 | "node_modules",
28 | "bin",
29 | "obj"
30 | ]
31 | },
32 | "main": "index.js",
33 | "scripts": {
34 | "test": "echo \"Error: no test specified\" && exit 1"
35 | },
36 | "repository": {
37 | "type": "git",
38 | "url": "git+https://github.com/<%= props.organization %>/<%= props.projectName %>.git"
39 | },
40 | "author": "",
41 | "license": "ISC",
42 | "bugs": {
43 | "url": "https://github.com/DNN-<%= props.organization %>/<%= props.projectName %>/issues"
44 | },
45 | "homepage": "https://github.com/DNN-<%= props.organization %>/<%= props.projectName %>#readme",
46 | "devDependencies": {
47 | "gulp": "^3.9.0",
48 | "gulp-browserify": "^0.5.1",
49 | "gulp-dnn-manifest": "^0.1.1",
50 | "gulp-dotnet-assembly-info": "^0.1.11",
51 | "gulp-filter": "^3.0.1",
52 | "gulp-markdown": "^1.1.0",
53 | "gulp-minify-css": "^1.2.1",
54 | "gulp-msbuild": "^0.2.13",
55 | "gulp-plumber": "^1.0.1",
56 | "gulp-react": "^3.0.1",
57 | "gulp-rename": "^1.2.2",
58 | "gulp-uglify": "^1.4.1",
59 | "gulp-util": "^3.0.6",
60 | "gulp-zip": "^3.0.2",
61 | "merge2": "^0.3.6",
62 | "react": "^0.13.3",
63 | "react-tools": "^0.13.3",
64 | "reactify": "^1.1.1"
65 | },
66 | "dependencies": {
67 | "jquery": "^2.1.4"
68 | }
69 | }
70 |
--------------------------------------------------------------------------------
/template/Controllers/WidgetsController_Services.cs:
--------------------------------------------------------------------------------
1 | using System.Net;
2 | using System.Net.Http;
3 | using System.Web.Http;
4 | using <%= props.organization %>.DNN.Modules.<%= props.projectName %>.Common;
5 | using <%= props.organization %>.DNN.Modules.<%= props.projectName %>.Models.<%= props.widgetName %>s;
6 | using DotNetNuke.Web.Api;
7 |
8 | namespace <%= props.organization %>.DNN.Modules.<%= props.projectName %>.Controllers
9 | {
10 |
11 | public partial class <%= props.widgetName %>sController : <%= props.projectName %>ApiController
12 | {
13 |
14 | #region Service Methods
15 | [HttpPost]
16 | [ValidateAntiForgeryToken]
17 | [<%= props.projectName %>Authorize(SecurityLevel = SecurityAccessLevel.Pointer)]
18 | public HttpResponseMessage <%= props.widgetName %>(<%= props.widgetName %>Base postData)
19 | {
20 | <%= props.widgetName %> returnData;
21 | postData.ModuleId = ActiveModule.ModuleID;
22 | if (postData.<%= props.widgetName %>Id == -1)
23 | {
24 | Add<%= props.widgetName %>(ref postData, UserInfo.UserID);
25 | returnData = Get<%= props.widgetName %>(postData.<%= props.widgetName %>Id, ActiveModule.ModuleID);
26 | }
27 | else
28 | {
29 | var oldData = Get<%= props.widgetName %>(postData.<%= props.widgetName %>Id, ActiveModule.ModuleID).Get<%= props.widgetName %>Base();
30 | if (oldData.CreatedByUserID == UserInfo.UserID | Settings.AllowOtherEdit | Security.CanEdit | Security.IsAdmin)
31 | {
32 | oldData.Latitude = postData.Latitude;
33 | oldData.Longitude = postData.Longitude;
34 | oldData.Message = postData.Message;
35 | Update<%= props.widgetName %>(oldData, UserInfo.UserID);
36 | returnData = Get<%= props.widgetName %>(postData.<%= props.widgetName %>Id, ActiveModule.ModuleID);
37 | }
38 | else
39 | {
40 | return Request.CreateResponse(HttpStatusCode.Unauthorized, "");
41 | }
42 | }
43 | return Request.CreateResponse(HttpStatusCode.OK, returnData);
44 | }
45 |
46 | [HttpPost]
47 | [ValidateAntiForgeryToken]
48 | [<%= props.projectName %>Authorize(SecurityLevel = SecurityAccessLevel.Pointer)]
49 | public HttpResponseMessage Delete(int id)
50 | {
51 | var <%= props.widgetName %> = Get<%= props.widgetName %>(id, ActiveModule.ModuleID);
52 | if (<%= props.widgetName %>.CreatedByUserID == UserInfo.UserID | Settings.AllowOtherEdit | Security.CanEdit |
53 | Security.IsAdmin)
54 | {
55 | Delete<%= props.widgetName %>(<%= props.widgetName %>.Get<%= props.widgetName %>Base());
56 | return Request.CreateResponse(HttpStatusCode.OK, "");
57 | }
58 | return Request.CreateResponse(HttpStatusCode.Unauthorized, <%= props.widgetName %>);
59 | }
60 |
61 | #endregion
62 |
63 | }
64 | }
65 |
66 |
--------------------------------------------------------------------------------
/template/Common/StringBasedSettings.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.ComponentModel;
4 | using System.Runtime.CompilerServices;
5 | using DotNetNuke.Common;
6 |
7 | namespace <%= props.organization %>.DNN.Modules.<%= props.projectName %>.Common
8 | {
9 | public class StringBasedSettings : ISettingsStore
10 | {
11 | Dictionary _cache;
12 | Dictionary _dirty;
13 | Func _get;
14 | Action _set;
15 |
16 | /// Function to get a value out of your setting store
17 | /// Action to save a value back to the setting store
18 | public StringBasedSettings(Func get, Action set)
19 | {
20 | Requires.NotNull("Get", get);
21 | Requires.NotNull("Set", set);
22 |
23 | _get = get;
24 | _set = set;
25 | _cache = new Dictionary();
26 | _dirty = new Dictionary();
27 | }
28 |
29 | // All changes to the settings are recorded and get only executed on demand
30 | public void Save()
31 | {
32 | foreach (var save in _dirty.Values) save();
33 | _dirty.Clear();
34 | }
35 |
36 | // CallerMemberName is used for the name of the setting. No more magic strings
37 | public string Get(string @default = default(string), [CallerMemberName] string name = null)
38 | {
39 | Requires.NotNull("Name", name);
40 |
41 | if (_cache.ContainsKey(name))
42 | {
43 | return _cache[name];
44 | }
45 | else
46 | {
47 | var value = _get(name) ?? @default;
48 | _cache[name] = value;
49 | return value;
50 | }
51 | }
52 |
53 | public T Get(T @default = default(T), [CallerMemberName] string name = null)
54 | {
55 | //required to behave Get and Get the same
56 | if (typeof(T) == typeof(string)) return (T)(object)Get((string)(object)@default, name);
57 |
58 | var converter = TypeDescriptor.GetConverter(typeof(T));
59 | Requires.NotNull("Converter for T", converter);
60 |
61 | try
62 | {
63 | var defaultValueAsString = converter.ConvertToInvariantString(@default);
64 | string value = Get(defaultValueAsString, name);
65 | return (T)converter.ConvertFromInvariantString(value);
66 | }
67 | catch
68 | {
69 | return @default;
70 | }
71 | }
72 |
73 | public void Set(string value, [CallerMemberName] string name = null)
74 | {
75 | Requires.NotNull("Name", name);
76 | var modified = !(_cache.ContainsKey(name) && _cache[name] == value);
77 |
78 | if (modified)
79 | {
80 | _cache[name] = value;
81 | _dirty[name] = () => _set(name, value);
82 | };
83 | }
84 |
85 | public void Set(T value, [CallerMemberName] string name = null)
86 | {
87 | //required to behave Set and Set the same
88 | if (typeof(T) == typeof(string))
89 | Set((string)(object)value, name);
90 | else
91 | {
92 | var converter = TypeDescriptor.GetConverter(typeof(T));
93 | Requires.NotNull("Converter for T", converter);
94 |
95 | Set(converter.ConvertToInvariantString(value), name);
96 | }
97 | }
98 | }
99 | }
--------------------------------------------------------------------------------
/template/gulpfile.js:
--------------------------------------------------------------------------------
1 | var gulp = require('gulp'),
2 | msbuild = require('gulp-msbuild'),
3 | browserify = require('gulp-browserify'),
4 | minifyCss = require('gulp-minify-css'),
5 | uglify = require('gulp-uglify'),
6 | assemblyInfo = require('gulp-dotnet-assembly-info'),
7 | plumber = require('gulp-plumber'),
8 | config = require('./package.json'),
9 | zip = require('gulp-zip'),
10 | filter = require('gulp-filter'),
11 | merge = require('merge2'),
12 | gutil = require('gulp-util'),
13 | markdown = require('gulp-markdown'),
14 | rename = require('gulp-rename'),
15 | manifest = require('gulp-dnn-manifest');
16 |
17 | gulp.task('browserify', function() {
18 | gulp.src('js/src/<%= props.projectName.toLowerCase() %>.js')
19 | .pipe(plumber())
20 | .pipe(browserify({
21 | transform: 'reactify',
22 | ignore: 'react'
23 | }))
24 | .pipe(gulp.dest('js/'));
25 | });
26 |
27 | gulp.task('watch', function() {
28 | gulp.watch('js/src/**/*.js', ['browserify']);
29 | });
30 |
31 | gulp.task('assemblyInfo', function() {
32 | return gulp
33 | .src('**/AssemblyInfo.cs')
34 | .pipe(assemblyInfo({
35 | title: config.dnnModule.friendlyName,
36 | description: config.description,
37 | version: config.version,
38 | fileVersion: config.version,
39 | company: config.dnnModule.owner.organization,
40 | copyright: function(value) {
41 | return 'Copyright ' + new Date().getFullYear() + ' by ' + config.dnnModule.owner.organization;
42 | }
43 | }))
44 | .pipe(gulp.dest('.'));
45 | });
46 |
47 | gulp.task('build', ['assemblyInfo'], function() {
48 | return gulp.src('./<%= props.projectName %>.csproj')
49 | .pipe(msbuild({
50 | toolsVersion: 12.0,
51 | targets: ['Clean', 'Build'],
52 | errorOnFail: true,
53 | stdout: true,
54 | properties: {
55 | Configuration: 'Release',
56 | OutputPath: config.dnnModule.pathToAssemblies
57 | }
58 | }));
59 | });
60 |
61 | gulp.task('packageInstall', ['browserify', 'build'], function() {
62 | var packageName = config.dnnModule.fullName + '_' + config.version;
63 | var dirFilter = filter(fileTest);
64 | return merge(
65 | merge(
66 | gulp.src([
67 | '**/*.html',
68 | '**/*.resx'
69 | ], {
70 | base: '.'
71 | })
72 | .pipe(dirFilter),
73 | gulp.src(['**/*.css'], {
74 | base: '.'
75 | })
76 | .pipe(minifyCss())
77 | .pipe(dirFilter),
78 | gulp.src(['js/*.js', '!js/*.min.js'], {
79 | base: '.'
80 | })
81 | .pipe(uglify().on('error', gutil.log)),
82 | gulp.src(['js/*.min.js'], {
83 | base: '.'
84 | })
85 | )
86 | .pipe(zip('Resources.zip')),
87 | gulp.src(config.dnnModule.pathToSupplementaryFiles + '/*.dnn')
88 | .pipe(manifest(config)),
89 | gulp.src([config.dnnModule.pathToAssemblies + '/*.dll',
90 | config.dnnModule.pathToScripts + '/*.SqlDataProvider',
91 | config.dnnModule.pathToSupplementaryFiles + '/License.txt',
92 | config.dnnModule.pathToSupplementaryFiles + '/ReleaseNotes.txt'
93 | ]),
94 | gulp.src(config.dnnModule.pathToSupplementaryFiles + '/ReleaseNotes.md')
95 | .pipe(markdown())
96 | .pipe(rename('ReleaseNotes.txt'))
97 | )
98 | .pipe(zip(packageName + '_Install.zip'))
99 | .pipe(gulp.dest(config.dnnModule.packagesPath));
100 | });
101 |
102 | gulp.task('packageSource', ['browserify', 'build'], function() {
103 | var packageName = config.dnnModule.fullName + '_' + config.version;
104 | var dirFilter = filter(fileTest);
105 | return merge(
106 | gulp.src(['**/*.html',
107 | '**/*.css',
108 | 'js/**/*.js',
109 | '**/*.??proj',
110 | '**/*.sln',
111 | '**/*.json',
112 | '**/*.cs',
113 | '**/*.vb',
114 | '**/*.resx',
115 | config.dnnModule.pathToSupplementaryFiles + '**/*.*'
116 | ], {
117 | base: '.'
118 | })
119 | .pipe(dirFilter)
120 | .pipe(zip('Resources.zip')),
121 | gulp.src(config.dnnModule.pathToSupplementaryFiles + '/*.dnn')
122 | .pipe(manifest(config)),
123 | gulp.src([config.dnnModule.pathToAssemblies + '/*.dll',
124 | config.dnnModule.pathToScripts + '/*.SqlDataProvider',
125 | config.dnnModule.pathToSupplementaryFiles + '/License.txt',
126 | config.dnnModule.pathToSupplementaryFiles + '/ReleaseNotes.txt'
127 | ])
128 | )
129 | .pipe(zip(packageName + '_Source.zip'))
130 | .pipe(gulp.dest(config.dnnModule.packagesPath));
131 | })
132 |
133 | gulp.task('package', ['packageInstall', 'packageSource'], function() {
134 | return null;
135 | })
136 |
137 | gulp.task('default', ['browserify']);
138 |
139 | function fileTest(file) {
140 | var res = false;
141 | for (var i = config.dnnModule.excludeFilter.length - 1; i >= 0; i--) {
142 | res = res | file.relative.startsWith(config.dnnModule.excludeFilter[i]);
143 | };
144 | return !res;
145 | }
146 |
147 | function startsWith(str, strToSearch) {
148 | return str.indexOf(strToSearch) === 0;
149 | }
--------------------------------------------------------------------------------
/template/Data/RepositoryImpl.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using DotNetNuke.Collections;
3 | using DotNetNuke.Data;
4 |
5 | namespace <%= props.organization %>.DNN.Modules.<%= props.projectName %>.Data
6 | {
7 | public abstract class RepositoryImpl : IRepository where T : class
8 | {
9 |
10 | public virtual void Delete(T item)
11 | {
12 | using (IDataContext db = DataContext.Instance())
13 | {
14 | IRepository repo = db.GetRepository();
15 | repo.Delete(item);
16 | }
17 | }
18 |
19 | public virtual void Delete(string sqlCondition, params object[] args)
20 | {
21 | using (IDataContext db = DataContext.Instance())
22 | {
23 | IRepository repo = db.GetRepository();
24 | repo.Delete(sqlCondition, args);
25 | }
26 | }
27 |
28 | public virtual IEnumerable Find(string sqlCondition, params object[] args)
29 | {
30 | IEnumerable list = null;
31 | using (IDataContext db = DataContext.Instance())
32 | {
33 | IRepository repo = db.GetRepository();
34 | list = repo.Find(sqlCondition, args);
35 | }
36 | return list;
37 | }
38 |
39 | public virtual IPagedList Find(int pageIndex, int pageSize, string sqlCondition, params object[] args)
40 | {
41 | IPagedList list = null;
42 | using (IDataContext db = DataContext.Instance())
43 | {
44 | IRepository repo = db.GetRepository();
45 | list = repo.Find(pageIndex, pageSize, sqlCondition, args);
46 | }
47 | return list;
48 | }
49 |
50 | public virtual IEnumerable Get()
51 | {
52 | IEnumerable list = null;
53 | using (IDataContext db = DataContext.Instance())
54 | {
55 | IRepository repo = db.GetRepository();
56 | list = repo.Get();
57 | }
58 | return list;
59 | }
60 |
61 | public virtual IEnumerable Get(TScopeType scopeValue)
62 | {
63 | IEnumerable list = null;
64 | using (IDataContext db = DataContext.Instance())
65 | {
66 | IRepository repo = db.GetRepository();
67 | list = repo.Get(scopeValue);
68 | }
69 | return list;
70 | }
71 |
72 | public virtual T GetById(TProperty id)
73 | {
74 | T item = null;
75 | using (IDataContext db = DataContext.Instance())
76 | {
77 | IRepository repo = db.GetRepository();
78 | item = repo.GetById(id);
79 | }
80 | return item;
81 | }
82 |
83 | public virtual T GetById(TProperty id, TScopeType scopeValue)
84 | {
85 | T item = null;
86 | using (IDataContext db = DataContext.Instance())
87 | {
88 | IRepository repo = db.GetRepository();
89 | item = repo.GetById(id, scopeValue);
90 | }
91 | return item;
92 | }
93 |
94 | public virtual IPagedList GetPage(int pageIndex, int pageSize)
95 | {
96 | IPagedList list = null;
97 | using (IDataContext db = DataContext.Instance())
98 | {
99 | IRepository repo = db.GetRepository();
100 | list = repo.GetPage(pageIndex, pageSize);
101 | }
102 | return list;
103 | }
104 |
105 | public virtual IPagedList GetPage(TScopeType scopeValue, int pageIndex, int pageSize)
106 | {
107 | IPagedList list = null;
108 | using (IDataContext db = DataContext.Instance())
109 | {
110 | IRepository repo = db.GetRepository();
111 | list = repo.GetPage(scopeValue, pageIndex, pageSize);
112 | }
113 | return list;
114 | }
115 |
116 | public virtual void Insert(T item)
117 | {
118 | using (IDataContext db = DataContext.Instance())
119 | {
120 | IRepository repo = db.GetRepository();
121 | repo.Insert(item);
122 | }
123 | }
124 |
125 | public virtual void Update(T item)
126 | {
127 | using (IDataContext db = DataContext.Instance())
128 | {
129 | IRepository repo = db.GetRepository();
130 | repo.Update(item);
131 | }
132 | }
133 |
134 | public virtual void Update(string sqlCondition, params object[] args)
135 | {
136 | using (IDataContext db = DataContext.Instance())
137 | {
138 | IRepository repo = db.GetRepository();
139 | repo.Update(sqlCondition, args);
140 | }
141 | }
142 |
143 | }
144 | }
145 |
146 |
--------------------------------------------------------------------------------
/generators/app/index.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 | var yeoman = require('yeoman-generator'),
3 | chalk = require('chalk'),
4 | yosay = require('yosay'),
5 | path = require('path'),
6 | extend = require('extend'),
7 | fs = require('fs'),
8 | util = require('./util.js');
9 |
10 | module.exports = yeoman.generators.Base.extend({
11 |
12 | _configPath: '',
13 | _config: {},
14 | _defaults: {
15 | dnn: {
16 | organization: 'Connect',
17 | url: 'http://dnn-connect.org',
18 | email: 'webmaster@dnn-connect.org',
19 | name: ''
20 | }
21 | },
22 |
23 | initializing: function() {
24 |
25 | if (path.basename(this.destinationPath()).toLowerCase() !== 'desktopmodules') {
26 | this.log('You must run this in the ' + chalk.red('DesktopModules') + ' folder!!');
27 | process.exit();
28 | }
29 |
30 | this._configPath = this.sourceRoot() + '/../../../.yo-rc.json';
31 | this._config = extend(true, this._defaults, this.fs.readJSON(path.normalize(this._configPath)));
32 |
33 | String.prototype.replaceAll = function(find, replace) {
34 | var str = this;
35 | return str.replace(new RegExp(find, 'g'), replace);
36 | };
37 |
38 | },
39 |
40 | prompting: function() {
41 | var done = this.async();
42 |
43 | this.log(yosay(
44 | 'Welcome to the ' + chalk.red('DNN SPA Module using Gulp and React') + ' generator!'
45 | ));
46 |
47 | var prompts = [{
48 | type: 'input',
49 | name: 'projectName',
50 | message: 'Project Name',
51 | validate: function(value) {
52 | if (value !== '') {
53 | return true;
54 | } else {
55 | return "You must enter a name for the project";
56 | }
57 | }
58 | }, {
59 | type: 'input',
60 | name: 'widgetName',
61 | message: 'Name of your primary object',
62 | default: 'Widget'
63 | }, {
64 | type: 'input',
65 | name: 'organization',
66 | message: 'Organization name (also used as subfolder and in namespaces)',
67 | default: this._config.dnn.organization,
68 | validate: function(value) {
69 | if (value !== '') {
70 | return true;
71 | } else {
72 | return "You must enter a name for the organization";
73 | }
74 | }
75 | }, {
76 | type: 'input',
77 | name: 'url',
78 | message: 'Url or your organization',
79 | default: this._config.dnn.url
80 | }, {
81 | type: 'input',
82 | name: 'name',
83 | message: 'Your name',
84 | default: this._config.dnn.name,
85 | validate: function(value) {
86 | if (value !== '') {
87 | return true;
88 | } else {
89 | return "You must enter your name";
90 | }
91 | }
92 | }, {
93 | type: 'input',
94 | name: 'email',
95 | message: 'Email address to use for project',
96 | default: this._config.dnn.email
97 | }, {
98 | type: 'confirm',
99 | name: 'overwriteSettings',
100 | message: 'Overwrite previous settings for organization, name and email?',
101 | default: false
102 | }];
103 |
104 | this.prompt(prompts, function(props) {
105 | this.props = props;
106 | if (this.props.overwriteSettings) {
107 | this._config.dnn.organization = this.props.organization;
108 | this._config.dnn.name = this.props.name;
109 | this._config.dnn.email = this.props.email;
110 | this._config.dnn.url = this.props.url;
111 | this.fs.writeJSON(this._configPath, this._config);
112 | }
113 | this.sourceRoot(this.sourceRoot() + '/../../../template');
114 | done();
115 | }.bind(this));
116 | },
117 |
118 | writing: {
119 | app: function() {
120 | util.ensureFolder(this.destinationPath(this.props.organization));
121 | this.destinationRoot(this.props.organization);
122 | util.ensureFolder(this.destinationPath(this.props.projectName));
123 | this.destinationRoot(this.props.projectName);
124 | },
125 |
126 | projectfiles: function() {
127 |
128 | var files = util.getFilesRecursive(this.templatePath(), '');
129 | for (var i = files.length - 1; i >= 0; i--) {
130 | var dest = files[i].replaceAll('Project', this.props.projectName)
131 | .replace('_package', 'package')
132 | .replaceAll('Company', this.props.organization)
133 | .replaceAll('Widget', this.props.widgetName);
134 | this.fs.copyTpl(
135 | this.templatePath(files[i]),
136 | this.destinationPath(dest), {
137 | props: this.props
138 | }
139 | );
140 | };
141 |
142 | }
143 |
144 | },
145 |
146 | copyFiles: function(fileList) {
147 | if (fileList === undefined) {
148 | return;
149 | }
150 | console.log(typeof fileList);
151 | for (var i = fileList.length - 1; i >= 0; i--) {
152 | this.fs.copyTpl(
153 | this.templatePath(fileList[i][0]),
154 | this.destinationPath(fileList[i][1]), {
155 | props: this.props
156 | }
157 | );
158 | };
159 | },
160 |
161 | install: function() {
162 | // this.installDependencies();
163 | }
164 |
165 | });
166 |
--------------------------------------------------------------------------------
/template/App_LocalResources/ClientResources.resx:
--------------------------------------------------------------------------------
1 |
2 |
3 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 | text/microsoft-resx
110 |
111 |
112 | 2.0
113 |
114 |
115 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
116 |
117 |
118 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
119 |
120 |
--------------------------------------------------------------------------------
/template/App_LocalResources/SharedResources.resx:
--------------------------------------------------------------------------------
1 |
2 |
3 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 | text/microsoft-resx
110 |
111 |
112 | 2.0
113 |
114 |
115 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
116 |
117 |
118 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
119 |
120 |
--------------------------------------------------------------------------------
/template/Project.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | AnyCPU
7 |
8 |
9 | 2.0
10 | {7D61A32C-0F21-453F-A981-BD8E5A3A5304}
11 | {349c5851-65df-11da-9384-00065b846f21};{fae04ec0-301f-11d3-bf4b-00c04f79efbc}
12 | Library
13 | Properties
14 | <%= props.organization %>.DNN.Modules.<%= props.projectName %>
15 | <%= props.organization %>.DNN.Modules.<%= props.projectName %>
16 | v4.5
17 | false
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 | true
26 | full
27 | false
28 | ..\..\..\bin\
29 | DEBUG;TRACE
30 | prompt
31 | 4
32 | false
33 |
34 |
35 | none
36 | true
37 | bin\
38 | TRACE
39 | prompt
40 | 4
41 | false
42 |
43 |
44 |
45 | _References\DotNetNuke.dll
46 | False
47 |
48 |
49 | False
50 | _References\DotNetNuke.Web.dll
51 | False
52 |
53 |
54 |
55 |
56 |
57 | False
58 | _References\System.Net.Http.Formatting.dll
59 | False
60 |
61 |
62 |
63 |
64 | False
65 | _References\System.Web.Http.dll
66 | False
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
115 | 10.0
116 | $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)
117 |
118 |
119 |
120 |
121 |
122 |
123 |
124 |
125 | True
126 | False
127 | 0
128 |
129 |
130 | http://dnndev.me/desktopmodules/<%= props.projectName %>
131 | True
132 | http://dnndev.me
133 | False
134 | False
135 |
136 |
137 | False
138 |
139 |
140 |
141 |
142 |
--------------------------------------------------------------------------------
/template/Common/Localization.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.IO;
4 | using System.Linq;
5 | using System.Web.Hosting;
6 | using System.Xml.XPath;
7 | using DotNetNuke.Collections.Internal;
8 | using DotNetNuke.Common.Utilities;
9 | using DotNetNuke.Entities.Portals;
10 | using DotNetNuke.Services.Cache;
11 | using DotNetNuke.Services.Localization;
12 |
13 | namespace <%= props.organization %>.DNN.Modules.<%= props.projectName %>.Common
14 | {
15 | public class Localization
16 | {
17 |
18 | public static Dictionary GetResourceFile(PortalSettings portalSettings, string resourceFile, string locale)
19 | {
20 | return
21 | (Dictionary) GetCompiledResourceFileCallBack(
22 | new CacheItemArgs("Compiled-" + resourceFile + "-" + locale + "-" + portalSettings.PortalId,
23 | DataCache.ResourceFilesCacheTimeOut, DataCache.ResourceFilesCachePriority, resourceFile, locale,
24 | portalSettings));
25 | }
26 |
27 | private static object GetCompiledResourceFileCallBack(CacheItemArgs cacheItemArgs)
28 | {
29 | string resourceFile = (string)cacheItemArgs.Params[0];
30 | string locale = (string)cacheItemArgs.Params[1];
31 | PortalSettings portalSettings = (PortalSettings)cacheItemArgs.Params[2];
32 | string systemLanguage = DotNetNuke.Services.Localization.Localization.SystemLocale;
33 | string defaultLanguage = portalSettings.DefaultLanguage;
34 | string fallbackLanguage = DotNetNuke.Services.Localization.Localization.SystemLocale;
35 | Locale targetLocale = LocaleController.Instance.GetLocale(locale);
36 | if (!String.IsNullOrEmpty(targetLocale.Fallback))
37 | {
38 | fallbackLanguage = targetLocale.Fallback;
39 | }
40 |
41 | // get system default and merge the specific ones one by one
42 | var res = GetResourceFile(resourceFile);
43 | if (res == null)
44 | {
45 | return new Dictionary();
46 | }
47 | res = MergeResourceFile(res, GetResourceFileName(resourceFile, systemLanguage, portalSettings.PortalId));
48 | if (defaultLanguage != systemLanguage)
49 | {
50 | res = MergeResourceFile(res, GetResourceFileName(resourceFile, defaultLanguage, -1));
51 | res = MergeResourceFile(res, GetResourceFileName(resourceFile, defaultLanguage, portalSettings.PortalId));
52 | }
53 | if (fallbackLanguage != defaultLanguage)
54 | {
55 | res = MergeResourceFile(res, GetResourceFileName(resourceFile, fallbackLanguage, -1));
56 | res = MergeResourceFile(res, GetResourceFileName(resourceFile, fallbackLanguage, portalSettings.PortalId));
57 | }
58 | if (locale != fallbackLanguage)
59 | {
60 | res = MergeResourceFile(res, GetResourceFileName(resourceFile, locale, -1));
61 | res = MergeResourceFile(res, GetResourceFileName(resourceFile, locale, portalSettings.PortalId));
62 | }
63 | return res;
64 | }
65 |
66 | private static Dictionary MergeResourceFile(Dictionary current, string resourceFile)
67 | {
68 | var resFile = GetResourceFile(resourceFile);
69 | if (resFile == null)
70 | {
71 | return current;
72 | }
73 | foreach (string key in current.Keys.ToList())
74 | {
75 | if (resFile.ContainsKey(key))
76 | {
77 | current[key] = resFile[key];
78 | }
79 | }
80 | return current;
81 | }
82 |
83 | #region Core Localization
84 | // Copy of methods from core localization provider but which kept these methods private, making it impossible to get a resource file from the cache
85 | public static Dictionary GetResourceFile(string resourceFile)
86 | {
87 | return CBO.GetCachedObject>(new CacheItemArgs(resourceFile, DataCache.ResourceFilesCacheTimeOut, DataCache.ResourceFilesCachePriority),
88 | GetResourceFileCallBack,
89 | true);
90 | }
91 |
92 | private static object GetResourceFileCallBack(CacheItemArgs cacheItemArgs)
93 | {
94 | string cacheKey = cacheItemArgs.CacheKey;
95 | Dictionary resources = null;
96 |
97 | string filePath = null;
98 | try
99 | {
100 | //Get resource file lookup to determine if the resource file even exists
101 | SharedDictionary resourceFileExistsLookup = GetResourceFileLookupDictionary();
102 |
103 | if (ResourceFileMayExist(resourceFileExistsLookup, cacheKey))
104 | {
105 | //check if an absolute reference for the resource file was used
106 | if (cacheKey.Contains(":\\") && Path.IsPathRooted(cacheKey))
107 | {
108 | //if an absolute reference, check that the file exists
109 | if (File.Exists(cacheKey))
110 | {
111 | filePath = cacheKey;
112 | }
113 | }
114 |
115 | //no filepath found from an absolute reference, try and map the path to get the file path
116 | if (filePath == null)
117 | {
118 | filePath = HostingEnvironment.MapPath(DotNetNuke.Common.Globals.ApplicationPath + cacheKey);
119 | }
120 |
121 | //The file is not in the lookup, or we know it exists as we have found it before
122 | if (File.Exists(filePath))
123 | {
124 | if (filePath != null)
125 | {
126 | var doc = new XPathDocument(filePath);
127 | resources = new Dictionary();
128 | foreach (XPathNavigator nav in doc.CreateNavigator().Select("root/data"))
129 | {
130 | if (nav.NodeType != XPathNodeType.Comment)
131 | {
132 | var selectSingleNode = nav.SelectSingleNode("value");
133 | if (selectSingleNode != null)
134 | {
135 | resources[nav.GetAttribute("name", String.Empty)] = selectSingleNode.Value;
136 | }
137 | }
138 | }
139 | }
140 | cacheItemArgs.CacheDependency = new DNNCacheDependency(filePath);
141 |
142 | //File exists so add it to lookup with value true, so we are safe to try again
143 | using (resourceFileExistsLookup.GetWriteLock())
144 | {
145 | resourceFileExistsLookup[cacheKey] = true;
146 | }
147 | }
148 | else
149 | {
150 | //File does not exist so add it to lookup with value false, so we don't try again
151 | using (resourceFileExistsLookup.GetWriteLock())
152 | {
153 | resourceFileExistsLookup[cacheKey] = false;
154 | }
155 | }
156 | }
157 | }
158 | catch (Exception ex)
159 | {
160 | throw new Exception(string.Format("The following resource file caused an error while reading: {0}", filePath), ex);
161 | }
162 | return resources;
163 | }
164 |
165 | private static SharedDictionary GetResourceFileLookupDictionary()
166 | {
167 | return
168 | CBO.GetCachedObject>(
169 | new CacheItemArgs(DataCache.ResourceFileLookupDictionaryCacheKey, DataCache.ResourceFileLookupDictionaryTimeOut, DataCache.ResourceFileLookupDictionaryCachePriority),
170 | c => new SharedDictionary(),
171 | true);
172 | }
173 |
174 | private static bool ResourceFileMayExist(SharedDictionary resourceFileExistsLookup, string cacheKey)
175 | {
176 | bool mayExist;
177 | using (resourceFileExistsLookup.GetReadLock())
178 | {
179 | mayExist = !resourceFileExistsLookup.ContainsKey(cacheKey) || resourceFileExistsLookup[cacheKey];
180 | }
181 | return mayExist;
182 | }
183 |
184 | private static string GetResourceFileName(string resourceFileRoot, string language, int portalId)
185 | {
186 | string resourceFile;
187 | language = language.ToLower();
188 | if (resourceFileRoot != null)
189 | {
190 | if (language == DotNetNuke.Services.Localization.Localization.SystemLocale.ToLower() || String.IsNullOrEmpty(language))
191 | {
192 | switch (resourceFileRoot.Substring(resourceFileRoot.Length - 5, 5).ToLower())
193 | {
194 | case ".resx":
195 | resourceFile = resourceFileRoot;
196 | break;
197 | case ".ascx":
198 | resourceFile = resourceFileRoot + ".resx";
199 | break;
200 | case ".aspx":
201 | resourceFile = resourceFileRoot + ".resx";
202 | break;
203 | default:
204 | resourceFile = resourceFileRoot + ".ascx.resx"; //a portal module
205 | break;
206 | }
207 | }
208 | else
209 | {
210 | switch (resourceFileRoot.Substring(resourceFileRoot.Length - 5, 5).ToLower())
211 | {
212 | case ".resx":
213 | resourceFile = resourceFileRoot.Replace(".resx", "." + language + ".resx");
214 | break;
215 | case ".ascx":
216 | resourceFile = resourceFileRoot.Replace(".ascx", ".ascx." + language + ".resx");
217 | break;
218 | case ".aspx":
219 | resourceFile = resourceFileRoot.Replace(".aspx", ".aspx." + language + ".resx");
220 | break;
221 | default:
222 | resourceFile = resourceFileRoot + ".ascx." + language + ".resx";
223 | break;
224 | }
225 | }
226 | }
227 | else
228 | {
229 | if (language == DotNetNuke.Services.Localization.Localization.SystemLocale.ToLower() || String.IsNullOrEmpty(language))
230 | {
231 | resourceFile = DotNetNuke.Services.Localization.Localization.SharedResourceFile;
232 | }
233 | else
234 | {
235 | resourceFile = DotNetNuke.Services.Localization.Localization.SharedResourceFile.Replace(".resx", "." + language + ".resx");
236 | }
237 | }
238 | if (portalId != -1)
239 | {
240 | resourceFile = resourceFile.Replace(".resx", ".Portal-" + portalId + ".resx");
241 | }
242 | return resourceFile;
243 | }
244 | #endregion
245 |
246 | }
247 | }
--------------------------------------------------------------------------------