Initial commit.

This commit is contained in:
Relintai 2021-11-19 09:24:55 +01:00
commit 520bacdabe
16 changed files with 1527 additions and 0 deletions

128
.clang-format Normal file
View File

@ -0,0 +1,128 @@
# Commented out parameters are those with the same value as base LLVM style
# We can uncomment them if we want to change their value, or enforce the
# chosen value in case the base style changes (last sync: Clang 6.0.1).
---
### General config, applies to all languages ###
BasedOnStyle: LLVM
AccessModifierOffset: -4
AlignAfterOpenBracket: DontAlign
# AlignConsecutiveAssignments: false
# AlignConsecutiveDeclarations: false
# AlignEscapedNewlines: Right
# AlignOperands: true
AlignTrailingComments: false
AllowAllParametersOfDeclarationOnNextLine: false
# AllowShortBlocksOnASingleLine: false
AllowShortCaseLabelsOnASingleLine: true
AllowShortFunctionsOnASingleLine: Inline
AllowShortIfStatementsOnASingleLine: true
# AllowShortLoopsOnASingleLine: false
# AlwaysBreakAfterDefinitionReturnType: None
# AlwaysBreakAfterReturnType: None
# AlwaysBreakBeforeMultilineStrings: false
# AlwaysBreakTemplateDeclarations: false
# BinPackArguments: true
# BinPackParameters: true
# BraceWrapping:
# AfterClass: false
# AfterControlStatement: false
# AfterEnum: false
# AfterFunction: false
# AfterNamespace: false
# AfterObjCDeclaration: false
# AfterStruct: false
# AfterUnion: false
# AfterExternBlock: false
# BeforeCatch: false
# BeforeElse: false
# IndentBraces: false
# SplitEmptyFunction: true
# SplitEmptyRecord: true
# SplitEmptyNamespace: true
# BreakBeforeBinaryOperators: None
# BreakBeforeBraces: Attach
# BreakBeforeInheritanceComma: false
BreakBeforeTernaryOperators: false
# BreakConstructorInitializersBeforeComma: false
BreakConstructorInitializers: AfterColon
# BreakStringLiterals: true
ColumnLimit: 0
# CommentPragmas: '^ IWYU pragma:'
# CompactNamespaces: false
ConstructorInitializerAllOnOneLineOrOnePerLine: true
ConstructorInitializerIndentWidth: 8
ContinuationIndentWidth: 8
Cpp11BracedListStyle: false
# DerivePointerAlignment: false
# DisableFormat: false
# ExperimentalAutoDetectBinPacking: false
# FixNamespaceComments: true
# ForEachMacros:
# - foreach
# - Q_FOREACH
# - BOOST_FOREACH
# IncludeBlocks: Preserve
IncludeCategories:
- Regex: '".*"'
Priority: 1
- Regex: '^<.*\.h>'
Priority: 2
- Regex: '^<.*'
Priority: 3
# IncludeIsMainRegex: '(Test)?$'
IndentCaseLabels: true
# IndentPPDirectives: None
IndentWidth: 4
# IndentWrappedFunctionNames: false
# JavaScriptQuotes: Leave
# JavaScriptWrapImports: true
# KeepEmptyLinesAtTheStartOfBlocks: true
# MacroBlockBegin: ''
# MacroBlockEnd: ''
# MaxEmptyLinesToKeep: 1
# NamespaceIndentation: None
# PenaltyBreakAssignment: 2
# PenaltyBreakBeforeFirstCallParameter: 19
# PenaltyBreakComment: 300
# PenaltyBreakFirstLessLess: 120
# PenaltyBreakString: 1000
# PenaltyExcessCharacter: 1000000
# PenaltyReturnTypeOnItsOwnLine: 60
# PointerAlignment: Right
# RawStringFormats:
# - Delimiter: pb
# Language: TextProto
# BasedOnStyle: google
# ReflowComments: true
# SortIncludes: true
# SortUsingDeclarations: true
# SpaceAfterCStyleCast: false
# SpaceAfterTemplateKeyword: true
# SpaceBeforeAssignmentOperators: true
# SpaceBeforeParens: ControlStatements
# SpaceInEmptyParentheses: false
# SpacesBeforeTrailingComments: 1
# SpacesInAngles: false
# SpacesInContainerLiterals: true
# SpacesInCStyleCastParentheses: false
# SpacesInParentheses: false
# SpacesInSquareBrackets: false
TabWidth: 4
UseTab: Always
---
### C++ specific config ###
Language: Cpp
Standard: Cpp03
---
### ObjC specific config ###
Language: ObjC
Standard: Cpp03
ObjCBlockIndentWidth: 4
# ObjCSpaceAfterProperty: false
# ObjCSpaceBeforeProtocolList: true
---
### Java specific config ###
Language: Java
# BreakAfterJavaFieldAnnotations: false
JavaImportGroups: ['org.godotengine', 'android', 'androidx', 'com.android', 'com.google', 'java', 'javax']
...

32
.gitignore vendored Normal file
View File

@ -0,0 +1,32 @@
engine
modules/*
logs/*
*.d
*.o
*.meta
game/.import/**
game/.prop_tool_temp/**
.sconsign.dblite
.DS_Store
export/**
release/**
.vs/*
.kdev4/*
.vscode/*
.cache/**
TestRWTextures
_build/*
_binaries/*
game/android/build/*
*.blend1
.dir-locals.el
build.config
database.sqlite

1
HEADS Normal file
View File

@ -0,0 +1 @@
{"engine": {"master": "000174f3c89174bf2d34a9f890c470daa7a1b998"}}

19
LICENSE Normal file
View File

@ -0,0 +1,19 @@
Copyright (c) 2021 Péter Magyar
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

81
Readme.md Normal file
View File

@ -0,0 +1,81 @@
# CrystalCMS
An old CMS of mine that was originally written for/in laravel now ported to (rcpp_framework)[https://github.com/Relintai/rcpp_framework].
This is highly experimental stuff. It probably shouldn't be used by anyone who's sane.
Note: this readme has been taken from an another project of mine, it will be updated later.
## Compilation
Will only work on linux! Works on the rasberry pi.
### Dependencies
Arch/Manjaro:
```
pacman -S --needed scons pkgconf gcc yasm
```
Debian/Raspian:
```
sudo apt-get install build-essential scons pkg-config libudev-dev yasm
```
Optionally if you install MariaDB/MySQL and/or PostgreSQL the compile system should pick it up. Make sure to get a version
whoch contains the development headers (A bunch of .h files).
### Initial setup
clone this repo, then call `scons`, it will clone rcpp cms into a new engine directory. Run this every time you update the project.
You don't have to run it before / between builds.
```
# git clone https://github.com/Relintai/crystal_cms.git crystal_cms
# cd crystal_cms
# scons
```
Now you can build the project like: `scons bl`. ([b]uild [l]inux)
Adding -jX to the build command will run the build on that many threads. Like: `scons bl -j4`.
```
# scons bl -j4
- or -
# ./build.sh
```
Now you can run it.
First run migrations, this will create the necessary database tables:
```
# ./engine/bin/server m
- or -
# ./migrate.sh
```
Now you can start the server:
```
# ./engine/bin/server
- or -
# ./run.sh
```
Make sure to run it from the project's directory, as it needs data files.
Now just open http://127.0.0.1:8080
You can push floats to the "a/b" MQTT topics, and the new values will be save in the `database.sqlite` file, and will appear
in your browser.
## Structure
The main Application implementation is `app/ic_application.h`.
The `main.cpp` contains the initialization code for the framework.
The `content/www` folder is the wwwroot.

501
SConstruct Normal file
View File

@ -0,0 +1,501 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# Copyright (c) 2019-2021 Péter Magyar
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in all
# copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
EnsureSConsVersion(0, 98, 1)
import sys
import os
import subprocess
import json
import shutil
import traceback
folders = [
'app',
]
module_folders = [
'../custom_modules',
]
databases=True
main_file = 'main.cpp'
repository_index = 0
module_clone_path = '/modules/'
clone_command = 'git clone {0} {1}'
visual_studio_call_vcvarsall = False
visual_studio_vcvarsall_path = 'C:\\Program Files (x86)\\Microsoft Visual Studio\\2019\\Community\\VC\\Auxiliary\\Build\\vcvarsall.bat'
visual_studio_arch = 'amd64'
exports = {
'global': [],
'linux': [],
'windows': [],
'android': [],
'javascript': [],
}
engine_repository = [ ['https://github.com/Relintai/rcpp_cms.git', 'git@github.com:Relintai/rcpp_cms.git'], 'engine', '' ]
module_repositories = [
]
addon_repositories = [
]
third_party_addon_repositories = [
]
target_commits = {}
engine_branch = 'master'
def onerror(func, path, exc_info):
"""
https://stackoverflow.com/questions/2656322/shutil-rmtree-fails-on-windows-with-access-is-denied
Because Windows.
Error handler for ``shutil.rmtree``.
If the error is due to an access error (read only file)
it attempts to add write permission and then retries.
If the error is for another reason it re-raises the error.
Usage : ``shutil.rmtree(path, onerror=onerror)``
"""
import stat
if not os.access(path, os.W_OK):
# Is the error an access error ?
os.chmod(path, stat.S_IWUSR)
func(path)
else:
raise
def load_target_commits_array():
global target_commits
if os.path.isfile('./HEADS'):
with open('./HEADS', 'r') as infile:
target_commits = json.load(infile)
else:
target_commits = {}
def save_target_commits_array():
with open('./HEADS', 'w') as outfile:
json.dump(target_commits, outfile)
def update_repository(data, clone_path, branch = 'master'):
cwd = os.getcwd()
full_path = cwd + clone_path + data[1] + '/'
if not os.path.isdir(full_path):
os.chdir(cwd + clone_path)
subprocess.call(clone_command.format(data[0][repository_index], data[1]), shell=True)
os.chdir(full_path)
subprocess.call('git reset', shell=True)
subprocess.call('git reset --hard', shell=True)
subprocess.call('git clean -f -d', shell=True)
subprocess.call('git checkout -B ' + branch + ' origin/' + branch, shell=True)
subprocess.call('git reset', shell=True)
subprocess.call('git reset --hard', shell=True)
subprocess.call('git clean -f -d', shell=True)
subprocess.call('git pull origin ' + branch, shell=True)
process = subprocess.Popen('git rev-parse HEAD', shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
output = process.communicate()[0].decode().strip()
if data[1] not in target_commits:
target_commits[data[1]] = {}
target_commits[data[1]][branch] = output
os.chdir(cwd)
def setup_repository(data, clone_path, branch = 'master'):
cwd = os.getcwd()
full_path = cwd + clone_path + data[1] + '/'
if not os.path.isdir(full_path):
os.chdir(cwd + clone_path)
subprocess.call(clone_command.format(data[0][repository_index], data[1]), shell=True)
os.chdir(full_path)
subprocess.call('git reset', shell=True)
subprocess.call('git reset --hard', shell=True)
subprocess.call('git clean -f -d', shell=True)
subprocess.call('git checkout -B ' + branch + ' origin/' + branch, shell=True)
subprocess.call('git pull origin ' + branch, shell=True)
subprocess.call('git reset', shell=True)
subprocess.call('git reset --hard', shell=True)
if data[1] in target_commits:
target = target_commits[data[1]][branch]
subprocess.call('git checkout -B ' + branch + ' ' + target, shell=True)
subprocess.call('git clean -f -d', shell=True)
subprocess.call('git reset', shell=True)
subprocess.call('git reset --hard', shell=True)
os.chdir(cwd)
def copy_repository(data, target_folder, clone_path):
copytree(os.path.abspath(clone_path + data[1] + '/' + data[2]), os.path.abspath(target_folder + data[1]))
def copytree(src, dst):
for item in os.listdir(src):
sp = os.path.join(src, item)
dp = os.path.join(dst, item)
if os.path.isdir(sp):
if os.path.isdir(dp):
shutil.rmtree(dp, onerror=onerror)
shutil.copytree(sp, dp)
else:
if not os.path.isdir(dst):
os.makedirs(dst)
shutil.copy2(sp, dp)
def update_engine():
update_repository(engine_repository, '/', engine_branch)
def update_modules():
for rep in module_repositories:
update_repository(rep, module_clone_path)
copy_repository(rep, './engine/modules/', '.' + module_clone_path)
def update_addons():
for rep in addon_repositories:
update_repository(rep, module_clone_path)
copy_repository(rep, './game/addons/', '.' + module_clone_path)
def update_addons_third_party_addons():
for rep in third_party_addon_repositories:
update_repository(rep, module_clone_path)
copy_repository(rep, './game/addons/', '.' + module_clone_path)
def update_all():
update_engine()
update_modules()
update_addons()
update_addons_third_party_addons()
save_target_commits_array()
def setup_engine():
setup_repository(engine_repository, '/', engine_branch)
def setup_modules():
for rep in module_repositories:
setup_repository(rep, module_clone_path)
copy_repository(rep, './engine/modules/', '.' + module_clone_path)
def setup_addons():
for rep in addon_repositories:
setup_repository(rep, module_clone_path)
copy_repository(rep, './game/addons/', '.' + module_clone_path)
def setup_addons_third_party_addons():
for rep in third_party_addon_repositories:
setup_repository(rep, module_clone_path)
copy_repository(rep, './game/addons/', '.' + module_clone_path)
def setup_all():
setup_engine()
setup_modules()
setup_addons()
setup_addons_third_party_addons()
def format_path(path):
if 'win' in sys.platform:
path = path.replace('/', '\\')
path = path.replace('~', '%userprofile%')
return path
def get_exports_for(platform):
export_command = 'export '
command_separator = ';'
if 'win' in sys.platform:
command_separator = '&'
export_command = 'set '
command = ''
for p in exports[platform]:
command += export_command + p + command_separator
return command
def parse_config():
global visual_studio_vcvarsall_path
global visual_studio_arch
global visual_studio_call_vcvarsall
global exports
if not os.path.isfile('build.config'):
return
with open('build.config', 'r') as f:
for line in f:
ls = line.strip()
if ls == '' or ls.startswith('#'):
continue
words = line.split()
if (len(words) < 2):
print('This build.config line is malformed, and got ignored: ' + ls)
continue
if words[0] == 'visual_studio_vcvarsall_path':
visual_studio_vcvarsall_path = format_path(ls[29:])
elif words[0] == 'visual_studio_arch':
visual_studio_arch = format_path(ls[19:])
elif words[0] == 'visual_studio_call_vcvarsall':
visual_studio_call_vcvarsall = words[1].lower() in [ 'true', '1', 't', 'y', 'yes' ]
elif words[0] == 'export':
if (len(words) < 3) or not words[1] in exports:
print('This build.config line is malformed, and got ignored: ' + ls)
continue
export_path = format_path(ls[8 + len(words[1]):])
exports[words[1]].append(export_path)
parse_config()
env = Environment()
if len(sys.argv) > 1:
arg = sys.argv[1]
arg_split = arg.split('_')
arg = arg_split[0]
arg_split = arg_split[1:]
if arg[0] == 'b':
build_string = get_exports_for('global') + 'scons '
build_string += 'target='
if 'r' in arg:
build_string += 'release'
elif 'd' in arg:
build_string += 'debug'
else:
build_string += 'release_debug'
build_string += ' '
if 'm' in arg:
build_string += 'use_mingw=yes'
else:
if 'win' in sys.platform and visual_studio_call_vcvarsall:
build_string = 'call "{0}" {1}&'.format(visual_studio_vcvarsall_path, visual_studio_arch) + build_string
if 'o' in arg:
build_string += 'use_llvm=yes'
if 'v' in arg:
build_string += 'vsproj=yes'
if databases:
build_string += " databases=yes "
build_string += 'folders="'
for f in folders:
build_string += '../' + f
build_string += ';'
build_string += '" '
build_string += 'main_file="../' + main_file + '" '
for i in range(2, len(sys.argv)):
build_string += ' ' + sys.argv[i] + ' '
cwd = os.getcwd()
full_path = cwd + '/engine/'
if not os.path.isdir(full_path):
print('engine directory doesnt exists.')
exit()
os.chdir(full_path)
if 'l' in arg:
build_string += 'platform=x11'
build_string = get_exports_for('linux') + build_string
print('Running command: ' + build_string)
subprocess.call(build_string, shell=True)
elif 'w' in arg:
build_string += 'platform=windows'
build_string = get_exports_for('windows') + build_string
print('Running command: ' + build_string)
subprocess.call(build_string, shell=True)
elif 'a' in arg:
build_string += 'platform=android'
build_string = get_exports_for('android') + build_string
print('Running command: ' + build_string + ' android_arch=armv7')
subprocess.call(build_string + ' android_arch=armv7', shell=True)
print('Running command: ' + build_string + ' android_arch=arm64v8')
subprocess.call(build_string + ' android_arch=arm64v8', shell=True)
print('Running command: ' + build_string + ' android_arch=x86')
subprocess.call(build_string + ' android_arch=x86', shell=True)
os.chdir(full_path + 'platform/android/java/')
print('Running command: ' + get_exports_for('global') + get_exports_for('android') + './gradlew generateGodotTemplates')
subprocess.call(get_exports_for('global') + get_exports_for('android') + './gradlew generateGodotTemplates', shell=True)
elif 'j' in arg:
build_string += 'platform=javascript'
build_string = get_exports_for('javascript') + build_string
print('Running command: ' + build_string)
subprocess.call(build_string, shell=True)
else:
print('No platform specified')
exit()
exit()
elif arg[0] == 'p':
if arg == 'p':
#print("Applies a patch. Append c for the compilation database patch. For example: pc")
print("Applies a patch. No Patches right now.")
exit()
cwd = os.getcwd()
full_path = cwd + '/engine/'
if not os.path.isdir(full_path):
print('engine directory doesnt exists.')
exit()
os.chdir(full_path)
#apply the patch to just the working directory, without creating a commit
#if 'c' in arg:
# subprocess.call('git apply --index ../patches/compilation_db.patch', shell=True)
#unstage all files
subprocess.call('git reset', shell=True)
exit()
opts = Variables(args=ARGUMENTS)
opts.Add('a', 'What to do', '')
opts.Add(EnumVariable('action', 'What to do', 'setup', ('setup', 'update')))
opts.Add('t', 'Action target', '')
opts.Add(EnumVariable('target', 'Action target', 'all', ('all', 'engine', 'modules', 'all_addons', 'addons', 'third_party_addons')))
opts.Add(EnumVariable('repository_type', 'Type of repositories to clone from first', 'http', ('http', 'ssh')))
opts.Update(env)
Help(opts.GenerateHelpText(env))
load_target_commits_array()
rt = env['repository_type']
if rt == 'ssh':
repository_index = 1
action = env['action']
target = env['target']
if env['a']:
action = env['a']
if env['t']:
target = env['t']
if not os.path.isdir('./modules'):
os.mkdir('./modules')
if 'm' in action:
godot_branch = 'master'
if 'setup' in action or action[0] == 's':
if target == 'all':
setup_all()
elif target == 'engine':
setup_engine()
elif target == 'modules':
setup_modules()
elif target == 'all_addons':
setup_addons()
setup_addons_third_party_addons()
elif target == 'addons':
setup_addons()
elif target == 'third_party_addons':
setup_addons_third_party_addons()
elif 'update' in action or action[0] == 'u':
if target == 'all':
update_all()
elif target == 'engine':
update_engine()
save_target_commits_array()
elif target == 'modules':
update_modules()
save_target_commits_array()
elif target == 'all_addons':
update_addons()
update_addons_third_party_addons()
save_target_commits_array()
elif target == 'addons':
update_addons()
save_target_commits_array()
elif target == 'third_party_addons':
update_addons_third_party_addons()
save_target_commits_array()

295
app/ccms_application.cpp Normal file
View File

@ -0,0 +1,295 @@
#include "ccms_application.h"
#include "core/http/request.h"
#include <iostream>
#include "core/file_cache.h"
#include "core/http/handler_instance.h"
#include "core/database/database_manager.h"
#include "core/html/html_builder.h"
#include "core/http/http_session.h"
#include "core/http/session_manager.h"
#include "modules/users/user.h"
//#include "modules/users/user_controller.h"
#include "modules/rbac_users/rbac_user_controller.h"
#include "modules/admin_panel/admin_panel.h"
#include "modules/rbac/rbac_controller.h"
#include "modules/rbac/rbac_model.h"
bool CCMSApplication::is_logged_in(Request *request) {
if (!request->session) {
return false;
}
Ref<User> u = request->reference_data["user"];
return u.is_valid();
}
void CCMSApplication::index(Object *instance, Request *request) {
ENSURE_LOGIN(request);
add_menu(request, MENUENTRY_NEWS);
/*
<?php if (isset($hero)): ?>
<link rel="stylesheet" type="text/css" href="<?=base_url('css/hero.css'); ?>">
<?php endif; ?>
<?php if ($userlevel > 2): ?>
<link rel="stylesheet" type="text/css" href="<?=base_url('css/admin.css'); ?>">
<?php endif; ?>
<?php if ($page == 'mail'): ?>
<link rel="stylesheet" type="text/css" href="<?=base_url('css/mail.css'); ?>">
<?php endif; ?>
<?php if ($resources): ?>
<script src="<?=base_url('js/resource.js'); ?>"></script>
<?php endif; ?>
*/
//dynamic_cast<ListPage *>(instance)->index(request);
request->body += "test";
request->compile_and_send_body();
}
void CCMSApplication::session_middleware_func(Object *instance, Request *request) {
}
void CCMSApplication::add_menu(Request *request, const MenuEntries index) {
request->head += menu_head;
HTMLBuilder b;
HTMLTag *t;
/*
<?php if ($weather): ?>
<div class="menu_base <?=$weather['css']; ?>">
<?php else: ?>
<div class="menu_base">
<?php endif; ?>
*/
b.div()->cls("menu_base");
{
b.div()->cls("left");
{
b.div()->cls("menu_news");
{
b.a()->href("/news/index");
b.w("News");
b.ca();
}
b.cdiv();
b.div()->cls("menu_mail");
{
b.a()->href("/mail/inbox");
b.w("Mails");
//if ($newmail) echo '!';
b.ca();
}
b.cdiv();
b.div()->cls("menu_hero");
{
b.a()->href("/hero/selected");
b.w("Hero");
b.ca();
}
b.cdiv();
b.div()->cls("menu_village");
{
b.a()->href("/village/selected");
b.w("Village"); //villagename
b.ca();
}
b.cdiv();
b.div()->cls("menu_sel_village");
{
b.a()->href("/village/select");
b.w("v");
b.ca();
}
b.cdiv();
/*
<?php if ($alliancename): ?>
<div class="menu_alliance">
<a href="<?=site_url($menu_alliance); ?>">[<?=$alliancename; ?>]</a>
</div>
<?php endif; ?>
*/
/*
<?php if ($weather): ?>
<div class="weather">
<abbr title="<?=$weather['description']; ?>"><?=$weather['name']; ?></abbr>
</div>
<?php endif; ?>
*/
}
b.cdiv();
b.div()->cls("right");
{
/*
<?php if ($userlevel > 4): ?>
<div class="menu_gm">
<a href="<?=site_url($link_gm); ?>">GM</a>
</div>
<?php endif; ?>
*/
/*
<?php if ($userlevel > 5): //dev+?>
<div class="menu_admin">
<a href="<?=site_url($link_admin); ?>">Admin</a>
</div>
<?php endif; ?>
*/
b.div()->cls("menu_alliance_menu");
{
b.a()->href("/alliance/alliance_menu");
b.w("Alliances");
b.ca();
}
b.cdiv();
b.div()->cls("menu_forum");
{
b.a()->href("/forum/index");
b.w("Forum");
b.ca();
}
b.cdiv();
b.div()->cls("menu_settings");
{
b.a()->href("/user/settings");
b.w("Settings");
b.ca();
}
b.cdiv();
b.div()->cls("menu_logout");
{
b.a()->href("/user/logout");
b.w("Logout");
b.ca();
}
b.cdiv();
}
b.cdiv();
b.div()->cls("nofloat");
b.cdiv();
}
b.cdiv();
b.div()->cls("main");
b.write_tag();
request->body += b.result;
request->footer = footer;
}
void CCMSApplication::village_page_func(Object *instance, Request *request) {
add_menu(request, MENUENTRY_VILLAGE);
//dynamic_cast<ListPage *>(instance)->index(request);
request->body += "test";
request->compile_and_send_body();
}
void CCMSApplication::admin_page_func(Object *instance, Request *request) {
AdminPanel::get_singleton()->handle_request_main(request);
}
void CCMSApplication::user_page_func(Object *instance, Request *request) {
if (is_logged_in(request)) {
add_menu(request, MENUENTRY_SETTINGS);
}
UserController::get_singleton()->handle_request_default(request);
}
void CCMSApplication::setup_routes() {
DWebApplication::setup_routes();
index_func = HandlerInstance(index);
main_route_map["admin"] = HandlerInstance(admin_page_func);
main_route_map["user"] = HandlerInstance(user_page_func);
}
void CCMSApplication::setup_middleware() {
middlewares.push_back(HandlerInstance(::SessionManager::session_setup_middleware));
//middlewares.push_back(HandlerInstance(::UserController::user_session_setup_middleware));
//middlewares.push_back(HandlerInstance(::RBACUserController::rbac_user_session_setup_middleware));
middlewares.push_back(HandlerInstance(::RBACUserController::rbac_default_user_session_middleware));
DWebApplication::setup_middleware();
}
void CCMSApplication::migrate() {
_rbac_model->migrate();
}
void CCMSApplication::compile_menu() {
HTMLBuilder bh;
bh.meta()->charset_utf_8();
bh.meta()->name("description")->content("RPG browsergame");
bh.meta()->name("keywords")->content("RPG,browsergame,Mourne,game,play");
bh.title();
bh.w("Mourne");
bh.ctitle();
bh.link()->rel_stylesheet()->href("/css/base.css");
bh.link()->rel_stylesheet()->href("/css/menu.css");
bh.write_tag();
menu_head = bh.result;
HTMLBuilder bf;
bf.cdiv();
bf.footer();
bf.cfooter();
footer = bf.result;
}
CCMSApplication::CCMSApplication() :
DWebApplication() {
_rbac_model = new RBACModel();
_rbac_controller = new RBACController();
_rbac_controller->initialize();
_admin_panel = new AdminPanel();
_admin_panel->register_admin_controller("rbac", _rbac_controller);
compile_menu();
}
CCMSApplication::~CCMSApplication() {
delete _admin_panel;
delete _rbac_controller;
delete _rbac_model;
}
std::string CCMSApplication::menu_head = "";
std::string CCMSApplication::footer = "";

75
app/ccms_application.h Normal file
View File

@ -0,0 +1,75 @@
#ifndef CCMS_APPLICATION_H
#define CCMS_APPLICATION_H
//#include "core/http/web_application.h"
#include "core/object.h"
#include "modules/drogon/web_application.h"
#undef LOG_TRACE
#undef LOG_WARN
#include "modules/list_page/list_page.h"
#include "modules/message_page/message_page.h"
#include "modules/paged_article/paged_article.h"
#include "modules/paged_list/paged_list.h"
class AdminPanel;
class RBACController;
class RBACModel;
#define ENSURE_LOGIN(request) \
if (!is_logged_in(request)) { \
request->send_redirect("/user/login"); \
return; \
}
class CCMSApplication : public DWebApplication {
public:
enum MenuEntries {
MENUENTRY_NEWS = 0,
MENUENTRY_MAIL,
MENUENTRY_HERO,
MENUENTRY_VILLAGE,
MENUENTRY_SELECT_VILLAGE,
MENUENTRY_ALLIANCE,
MENUENTRY_ALLIANCE_MENU,
MENUENTRY_FORUM,
MENUENTRY_CHANGELOG,
MENUENTRY_SETTINGS,
MENUENTRY_LOGOUT,
MENUENTRY_MAX,
};
public:
static bool is_logged_in(Request *request);
static void index(Object *instance, Request *request);
static void session_middleware_func(Object *instance, Request *request);
static void add_menu(Request *request, const MenuEntries index);
static void village_page_func(Object *instance, Request *request);
static void admin_page_func(Object *instance, Request *request);
static void user_page_func(Object *instance, Request *request);
virtual void setup_routes();
virtual void setup_middleware();
virtual void migrate();
void compile_menu();
CCMSApplication();
~CCMSApplication();
AdminPanel *_admin_panel;
RBACController *_rbac_controller;
RBACModel *_rbac_model;
static std::string menu_head;
static std::string footer;
};
#endif

View File

@ -0,0 +1,191 @@
#include "ccms_user_controller.h"
#include "core/html/form_validator.h"
#include "core/html/html_builder.h"
#include "core/http/cookie.h"
#include "core/http/http_session.h"
#include "core/http/request.h"
#include "core/http/session_manager.h"
#include "modules/users/user_model.h"
void CCMSUserController::render_login_request_default(Request *request, LoginRequestData *data) {
HTMLBuilder b;
b.w("Login");
b.br();
{
if (data->error_str.size() != 0) {
b.div()->cls("error");
b.w(data->error_str);
b.cdiv();
}
}
b.div()->cls("login");
{
//todo href path helper
b.form()->method("POST")->href("/user/login");
{
b.w("Username");
b.br();
b.input()->type("text")->name("username")->value(data->uname_val);
b.cinput();
b.br();
b.w("Password");
b.br();
b.input()->type("password")->name("password");
b.cinput();
b.br();
b.input()->type("submit")->value("Send");
b.cinput();
}
b.cform();
b.a()->href("/user/register");
b.w("Register");
b.ca();
}
b.cdiv();
request->body += b.result;
request->compile_and_send_body();
}
void CCMSUserController::render_register_request_default(Request *request, RegisterRequestData *data) {
HTMLBuilder b;
b.w("Registration");
b.br();
{
if (data->error_str.size() != 0) {
b.div()->cls("error");
b.w(data->error_str);
b.cdiv();
}
}
b.div()->cls("register");
{
//todo href path helper
b.form()->method("POST")->href("/user/register");
{
b.w("Username");
b.br();
b.input()->type("text")->name("username")->value(data->uname_val);
b.cinput();
b.br();
b.w("Email");
b.br();
b.input()->type("email")->name("email")->value(data->email_val);
b.cinput();
b.br();
b.w("Password");
b.br();
b.input()->type("password")->name("password");
b.cinput();
b.br();
b.w("Password again");
b.br();
b.input()->type("password")->name("password_check");
b.cinput();
b.br();
b.input()->type("submit")->value("Register");
b.cinput();
}
b.cform();
}
b.cdiv();
request->body += b.result;
request->compile_and_send_body();
}
void CCMSUserController::render_login_success(Request *request) {
request->body = "Login Success!<br>";
request->send_redirect("/");
}
void CCMSUserController::render_already_logged_in_error(Request *request) {
request->body += "You are already logged in.";
request->compile_and_send_body();
}
void CCMSUserController::render_settings_request(Ref<User> &user, Request *request, SettingsRequestData *data) {
HTMLBuilder b;
b.w("Settings");
b.br();
{
if (data->error_str.size() != 0) {
b.div()->cls("error");
b.w(data->error_str);
b.cdiv();
}
}
b.div()->cls("settings");
{
//todo href path helper
b.form()->method("POST")->href("/user/settings");
{
b.w("Username");
b.br();
b.input()->type("text")->name("username")->placeholder(user->name_user_input)->value(data->uname_val);
b.cinput();
b.br();
b.w("Email");
b.br();
b.input()->type("email")->name("email")->placeholder(user->email_user_input)->value(data->email_val);
b.cinput();
b.br();
b.w("Password");
b.br();
b.input()->type("password")->placeholder("*******")->name("password");
b.cinput();
b.br();
b.w("Password again");
b.br();
b.input()->type("password")->placeholder("*******")->name("password_check");
b.cinput();
b.br();
b.input()->type("submit")->value("Save");
b.cinput();
}
b.cform();
}
b.cdiv();
request->body += b.result;
request->compile_and_send_body();
}
CCMSUserController::CCMSUserController() :
RBACUserController() {
}
CCMSUserController::~CCMSUserController() {
}

View File

@ -0,0 +1,25 @@
#ifndef CCMS_USER_CONTROLLER_H
#define CCMS_USER_CONTROLLER_H
#include "modules/rbac_users/rbac_user_controller.h"
#include <string>
#include "modules/users/user.h"
class Request;
class FormValidator;
class CCMSUserController : public RBACUserController {
RCPP_OBJECT(CCMSUserController, RBACUserController);
public:
void render_login_request_default(Request *request, LoginRequestData *data);
void render_register_request_default(Request *request, RegisterRequestData *data);
void render_login_success(Request *request);
void render_already_logged_in_error(Request *request);
void render_settings_request(Ref<User> &user, Request *request, SettingsRequestData *data);
CCMSUserController();
~CCMSUserController();
};
#endif

44
build.config.example Normal file
View File

@ -0,0 +1,44 @@
# Copyright (c) 2019-2020 Péter Magyar
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in all
# copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
# Rename this file to build.config to use it
# Lines starting with # are comments. (Only works at the start of the line!)
# Note:
# ~ will be converted to %userprofile% on windows
# / will be converted to \ on windows
# so you don't have to worry about it
# Visual studio related setup:
visual_studio_call_vcvarsall True
visual_studio_vcvarsall_path C:/Program Files (x86)/Microsoft Visual Studio/2019/Community/VC/Auxiliary/Build/vcvarsall.bat
visual_studio_arch amd64
# export related setup
# available export targets: global, linux, windows, android, javascript
export global SCONS_CACHE=~/.scons_cache
export global SCONS_CACHE_LIMIT=5000
export android ANDROID_NDK_ROOT=~/SDKs/Android/NDK/android-ndk-r20b
export android ANDROID_NDK_HOME=~/SDKs/Android/NDK/android-ndk-r20b
export android ANDROID_HOME=~/SDKs/Android/SDK

1
build.sh Executable file
View File

@ -0,0 +1 @@
scons bl -j4

131
main.cpp Normal file

File diff suppressed because one or more lines are too long

1
migrate.sh Executable file
View File

@ -0,0 +1 @@
./engine/bin/server m

1
run.sh Executable file
View File

@ -0,0 +1 @@
./engine/bin/server

1
wg Normal file
View File

@ -0,0 +1 @@
wget -E -H -k -p -T 15 -nd