GnuCashew ~ Web Application compatible with GnuCash sql data files.
GCW
Loading...
Searching...
No Matches
App.cpp
Go to the documentation of this file.
1#line 2 "src/App.cpp"
2
3/*
4** USER_LOGIN is a switch that sets up the UI with
5** a user-login-widget. It's not working yet.
6**
7*/
8//#define USER_LOGIN
9
10#include <Wt/Date/tz.h>
11#include <Wt/WBootstrapTheme.h>
12#include <Wt/Auth/AuthWidget.h>
13#include <Wt/WDate.h>
14#include <Wt/WDialog.h>
15#include <Wt/WCheckBox.h>
16#include <Wt/WEnvironment.h>
17#include <Wt/WHBoxLayout.h>
18#include <Wt/WVBoxLayout.h>
19#include <Wt/WLocale.h>
20#include <Wt/WServer.h>
21#include <Wt/WText.h>
22#include <Wt/WVBoxLayout.h>
23
24#include "App.h"
25#include "Dbo/Users/Auth.h"
26#include "GnuCashew.h"
28
29extern std::string g_dbName;
30
31namespace {
32
33void showEnvironment()
34{
35 auto app = GCW::app();
36
37 std::cout << __FILE__ << ":" << __LINE__
38 << "\n title: " << app-> title()
39 << "\n appRoot: " << app-> appRoot()
40 << "\n docRoot: " << app-> docRoot()
41 << "\n sessionId: " << app-> sessionId()
42 << "\n metaHeader: " << app-> metaHeader( Wt::MetaHeaderType::Meta, "*" )
43 << "\n bodyClass: " << app-> bodyClass()
44 << "\n htmlClass: " << app-> htmlClass()
45 << "\n url: " << app-> url()
46 << "\n bookmarkUrl: " << app-> bookmarkUrl()
47 << "\n internalPath: " << app-> internalPath()
48 << "\n javaScriptClass: " << app-> javaScriptClass()
49 << "\n resourcesUrl: " << app-> resourcesUrl()
50 << "\n r-resourcesUrl: " << app-> relativeResourcesUrl()
51 << "\n referrer: " << app-> environment().referer()
52 << "\n accept: " << app-> environment().accept()
53 << "\n Host: " << app-> environment().headerValue( "Host" )
54 << "\n Referrer: " << app-> environment().headerValue( "Referrer" )
55 << "\n Accept: " << app-> environment().headerValue( "Accept" )
56 << "\n Origin: " << app-> environment().headerValue( "Origin" )
57 << "\n Content-Type: " << app-> environment().headerValue( "Content-Type" )
58 << "\n Content-Length: " << app-> environment().headerValue( "Content-Length" )
59 << "\n X-Forwarded-For: " << app-> environment().headerValue( "X-Forwarded-For" )
60 << "\n X-Forwarded-Client: " << app-> environment().headerValue( "X-Forwarded-Client" )
61 << "\n X-Forwarded-Xyz: " << app-> environment().headerValue( "X-Forwarded-Xyz" )
62 << "\n clientAddress: " << app-> environment().clientAddress()
63 << std::endl
64 ;
65
66 std::cout << __FILE__ << ":" << __LINE__ << " parameterMapSize: " << app-> environment().getParameterMap().size() << std::endl;
67 for( const auto & pair : app-> environment().getParameterMap() )
68 for( const auto & value : pair.second )
69 std::cout << __FILE__ << ":" << __LINE__ << " " << pair.first << "=" << value << std::endl;
70
71} // endvoid showEnvironment()
72
73} // endnamespace {
74
76{
77 return static_cast< GCW::App* >( Wt::WApplication::instance() );
78}
79
81: Wt::WApplication( env )
82{
83 root()-> addStyleClass( "GnuCashewRoot" );
84
85 setTitle( "GnuCashew ~ " + g_dbName );
86
87#ifdef NEVER
88 // something to note about the X-Forwarded-For haproxy value. This setting
89 // needs to be set within the 'haproxy.cfg haproxy_loop' section. To
90 // troubleshoot this, open the /var/log/haproxy.log file and look for the
91 // reported IP address;
92 // Oct 10 09:45:26 lsus1 haproxy[31634]: 104.28.50.130:50944 [10/Oct/2024:09:45:24.526] www-https~ haproxy_loop/haproxy_loop 0/0/1998 297 -- 6/3/2/1/0 0/0
93 // Oct 10 09:45:27 lsus1 haproxy[31634]: 127.0.0.1:43110 [10/Oct/2024:09:45:26.362] www-http gnucashew/gnucashew_wt 976/0/0/6/982 200 3777 - - ---- 6/3/0/1/0 0/0 "POST /demo?wtd=wDqiKVj7Wjibd276 HTTP/1.1"
94 // note in the first-line, haproxy_loop, the IP address noted is the actual
95 // ip address of the incoming client. this is the section that needs to
96 // carry the 'option forwardfor' setting to forward that address along to
97 // the next section;
98 // backend haproxy_loop
99 // mode http
100 // option forwardfor
101 // server haproxy_loop localhost:80
102 //
103 // note: also that the wt_config.xml file needs to posess the
104 // <behind-reverse-proxy>true</behind-reverse-proxy> value
105 // note: that the wthttp back-end does not regard the X-Forwarded-For value
106 // and therefore will report the incorrect IP address to the console
107 //
108 std::cout << __FILE__ << ":" << __LINE__ << " " << environment().headerValue( "X-Forwarded-For" ) << std::endl;
109 for( const auto & kvp : environment().getParameterMap() )
110 for( const auto vvv : kvp.second )
111 std::cout << __FILE__ << ":" << __LINE__ << " " << kvp.first << " " << vvv << std::endl;
112#endif
113
114#ifndef NEVER
115 std::cout
116 << __FILE__ << ":" << __LINE__ << std::endl
117 << __FILE__ << ":" << __LINE__
119 << "] " << environment().clientAddress()
120 << " " << sessionId()
121 << " " << url() << std::endl
122 << __FILE__ << ":" << __LINE__
123 << std::endl;
124#endif
125
126#ifdef USE_GNUCASH_ENGINE
127 gnucash_session().open( g_dbName );
128#endif
129
130#ifdef USE_GNUCASHEW_SESSION
132#endif
133
134 engine().open( g_dbName );
135
136// showEnvironment();
137
138 /*
139 ** Utilize the bootstrap theme.
140 **
141 */
142 auto bootstrapTheme = std::make_shared<Wt::WBootstrapTheme>();
143 bootstrapTheme-> setVersion( Wt::BootstrapVersion::v3 );
144 bootstrapTheme-> setResponsive( true );
145 setTheme( bootstrapTheme );
146 useStyleSheet( "resources/themes/bootstrap/3/bootstrap-theme.min.css" );
147 useStyleSheet( "styles/gcw.css" );
148
149 /*
150 ** GnuCashew english language translations
151 **
152 ** Note on the 'language elements' files.
153 ** The 'files' are located in the docroot folder. The main "united states english"
154 ** translation file is called "gcw.xml". This file contains all the words used in
155 ** the system called upon by Wt::WString::tr("id value"). Each 'language' file is
156 ** therefore;
157 ** "gcw_nl.xml" Dutch (netherlands)
158 ** "gcw_sp.xml" Spanish
159 **
160 ** It is only necessary to reference the english "gcw.xml" file, and the other language
161 ** files will get loaded automatically when the language changes.
162 **
163 ** See "Gui/MainWidget.cpp" for the references to the 'langCombo' code.
164 **
165 */
166 messageResourceBundle().use( docRoot() + "/styles/gcw" ); // Language Elements
167 messageResourceBundle().use( docRoot() + "/styles/gcw_gui" ); // UI elements
168
169 /*
170 ** set the date format to the browser.
171 **
172 */
173#ifdef NEVER
174 auto loc = locale();
175 auto tz = date::locate_zone( environment().timeZoneName() );
176 loc.setTimeZone( tz );
177#endif
178
179#ifdef USER_LOGIN
180 auto lw = root()-> setLayout( std::make_unique< Wt::WVBoxLayout >() );
181
182 lw-> addWidget( ( createAuthWidget() ) );
183
184 m_mainContainer = lw-> addWidget( std::make_unique< Wt::WContainerWidget >(), 1 );
185
186 /*
187 ** If the login status changes, respond to it.
188 **
189 */
190 gnucashew_session().login().changed().connect( this, &App::buildSite );
191#endif
192
193 /*
194 ** build the site
195 **
196 */
197 buildSite();
198
199#ifdef NEVER
200 std::cout << __FILE__ << ":" << __LINE__
201 << " \tcommodity.isocode"
202 << " \tcommodity.unitname"
203 << " \tcommodity.partname"
204 << " \tcommodity.nameSpace"
205 << " \tcommodity.exchangeCode"
206 << " \tcommodity.partsPerUnit"
207 << " \tcommodity.smallestFraction"
208 << " \tcommodity.localSymbol"
209 << " \tcommodity.fullname"
210 << std::endl;
211 for( auto & commodity : GCW::Dbo::Commodities::getIso4217Commodities() )
212 {
213 std::cout << __FILE__ << ":" << __LINE__
214 << " \t" << commodity.isocode
215 << " \t" << commodity.unitname
216 << " \t" << commodity.partname
217 << " \t" << commodity.nameSpace
218 << " \t" << commodity.exchangeCode
219 << " \t" << commodity.partsPerUnit
220 << " \t" << commodity.smallestFraction
221 << " \t" << commodity.localSymbol
222 << " \t" << commodity.fullname
223 << std::endl;
224 }
225#endif
226
227#ifdef SIMPLE_REPEATING_TIMER_FOR_TESTING_THINGS
228 m_timer = std::make_unique< Wt::WTimer >();
229 m_timer-> setInterval( std::chrono::seconds(1) );
230 m_timer-> start();
231 m_timer->
232 timeout().connect( [&]( Wt::WMouseEvent _event )
233 {
234 std::cout << __FILE__ << ":" << __LINE__ << " testing something..." << std::endl;
235 });
236#endif
237
238} // endGCW::App::App( const Wt::WEnvironment & env )
239
240auto
242configItem( const std::string & _cfy )-> GCW::Dbo::Vars::Item::Ptr
243{
244 Wt::Dbo::Transaction t( GCW::app()-> gnucashew_session() );
245
246 auto retVal = GCW::Dbo::Vars::get( "config", _cfy );
247
248 return retVal;
249}
250
251auto
253showWelcome()-> void
254{
255 auto config = configItem( "welcome" );
256 if( config-> getVarString( "suppress" ) != "yes" )
257 {
258 Wt::WDialog dialog( TR( "gcw.welcome.title" ) );
259 dialog.rejectWhenEscapePressed( true );
260 dialog.setClosable( true );
261 dialog.contents()-> addNew< Wt::WText >( TR( "gcw.welcome.body" ) );
262 auto cbxSuppress = dialog.contents()-> addNew< Wt::WCheckBox >( "do not show this message again" );
263 dialog.exec();
264
265 Wt::Dbo::Transaction t( GCW::app()-> gnucashew_session() );
266 config.modify()-> setVar( "suppress", cbxSuppress-> valueText().toUTF8() );
267 }
268
269} // endshowWelcome()-> void
270
271auto
273createAuthWidget() -> std::unique_ptr< Wt::Auth::AuthWidget >
274{
275 auto retVal = std::make_unique< Wt::Auth::AuthWidget >
276 (
278 gnucashew_session().users(),
279 gnucashew_session().login()
280 );
281
282 retVal-> model()-> addPasswordAuth( & GCW::Dbo::Users::passwordService() );
283 retVal-> model()-> addOAuth( GCW::Dbo::Users::oService() );
284 retVal-> setRegistrationEnabled( true );
285 retVal-> processEnvironment();
286
287 return std::move( retVal );
288
289} // endcreateLoginWidget() -> std::unique_ptr< Wt::Auth::AuthWidget >
290
291
292auto
294buildSite()-> void
295{
296#ifdef USER_LOGIN
297 std::cout << __FILE__ << ":" << __LINE__ << " " << gnucashew_session().login().loggedIn() << std::endl;
298
299 if( m_mainWidget )
300 m_mainContainer-> removeWidget( m_mainWidget );
301// m_mainContainer-> clear();
302
303 std::cout << __FILE__ << ":" << __LINE__ << " " << gnucashew_session().login().loggedIn() << std::endl;
304
305// if( gnucashew_session().login().loggedIn() )
306// if( true )
307 if( bookmarkUrl() == "demo" || gnucashew_session().login().loggedIn() )
308 buildLoggedIn();
309 else
310 buildLogin();
311#else
312
313 buildLoggedIn();
314
315#endif
316
317} // endbuildSite()-> void
318
319auto
321buildLogin()-> void
322{
323
324} // endbuildLogin()-> void
325
326auto
328buildLoggedIn()-> void
329{
330
331#ifdef USER_LOGIN
332 /*
333 ** Set a layout manager on the root widget so that everything can
334 ** be laid out correctly.
335 **
336 */
337 auto lw = m_mainContainer-> setLayout( std::make_unique< Wt::WVBoxLayout >() );
338 lw-> setSpacing( 0 );
339
340 /*
341 ** Build and install the main desktop widget.
342 **
343 */
344 m_mainWidget = lw-> addWidget( std::make_unique< GCW::Gui::MainWidget >() );
345
346#else
347
348 /*
349 ** Set a layout manager on the root widget so that everything can
350 ** be laid out correctly.
351 **
352 */
353 auto lw = root()-> setLayout( std::make_unique< Wt::WVBoxLayout >() );
354 lw-> setSpacing( 0 );
355
356 /*
357 ** Build and install the main desktop widget.
358 **
359 */
360 m_mainWidget = lw-> addWidget( std::make_unique< GCW::Gui::MainWidget >() );
361
362#endif
363
364 Wt::WTimer::singleShot( std::chrono::seconds(1), this, &App::showWelcome );
365
366 /*
367 ** If we have the gnucashew extensions, then record that we logged on.
368 **
369 */
370// if( engine().hasGnuCashewExtensions() )
371// {
372// Wt::Dbo::Transaction t( gnucashew_session() );
373// auto item = GCW::Dbo::Vars::get( "logon","sys" );
374// item.modify()-> setVar( "logonOn", Wt::WDateTime::currentDateTime().toString( ISO_DATE_FORMAT ) );
375// item.modify()-> setVar( "logonBy", "dev(0)" );
376// }
377
378} // endbuildLoggedIn()-> void
379
380
381
std::string g_dbName
Definition main.cpp:25
static std::unique_ptr< GCW::Gui::BillPay::PaymentWidgetDialog > dialog
Definition App.h:27
auto buildLogin() -> void
Definition App.cpp:321
auto configItem(const std::string &_cfy) -> GCW::Dbo::Vars::Item::Ptr
Definition App.cpp:242
Wt::WContainerWidget * m_mainContainer
Definition App.h:62
std::unique_ptr< Wt::WTimer > m_timer
Definition App.h:65
Dbo::GnuCashew::Session & gnucashew_session()
Definition App.h:40
auto createAuthWidget() -> std::unique_ptr< Wt::Auth::AuthWidget >
Definition App.cpp:273
App(const Wt::WEnvironment &env)
Definition App.cpp:80
auto buildSite() -> void
Definition App.cpp:294
GCW::Eng::Engine & engine()
Definition App.h:32
auto showWelcome() -> void
Definition App.cpp:253
auto buildLoggedIn() -> void
Definition App.cpp:328
auto login() -> Wt::Auth::Login &
bool open(const std::string &_path)
Open a database.
bool open(const std::string &_filePath)
Open the Database.
Definition Engine.cpp:19
std::string sessionId() const
std::string docRoot() const
WMessageResourceBundle & messageResourceBundle()
WContainerWidget * root() const
const WLocale & locale() const
void setTheme(const std::shared_ptr< WTheme > &theme)
void setTitle(const WString &title)
void useStyleSheet(const WLink &link, const std::string &media="all")
std::string url(const std::string &internalPath=std::string()) const
const WEnvironment & environment() const
static WDateTime currentDateTime()
WString toString() const
const Http::ParameterMap & getParameterMap() const
const std::string headerValue(const std::string &field) const
const std::string & clientAddress() const
void use(const std::string &path, bool loadInMemory=true)
static void singleShot(std::chrono::milliseconds interval, T *receiver, void(V::*method)())
#define TR(X)
Definition define.h:17
auto getIso4217Commodities() -> std::vector< Commodity_t >
Get Commodities.
auto passwordService() -> const Wt::Auth::PasswordService &
Definition Auth.cpp:93
auto service() -> const Wt::Auth::AuthService &
Definition Auth.cpp:85
auto oService() -> const std::vector< const Wt::Auth::OAuthService * >
Definition Auth.cpp:101
auto get(const std::string &_keyValue, const std::string &_cfyValue="*", bool _add=true) -> GCW::Dbo::Vars::Item::Ptr
Definition Vars.cpp:16
App * app()
Definition App.cpp:75