Compare commits

..

10 Commits

Author SHA1 Message Date
687424391a 2023-01-04 01:51:06 +00:00
b2934649f1 2022-12-14 17:43:20 +00:00
e4127231e7 2022-12-14 17:30:09 +00:00
001f4d959e 2022-12-09 01:59:57 +00:00
02ed8f54d7 2022-12-07 02:30:19 +00:00
7f09d7481f 2022-12-06 23:13:37 +00:00
41c5574a5f 2022-12-03 00:02:07 +00:00
33f70e8f0c 2022-12-02 23:20:39 +00:00
ecb102aa1c 2022-11-30 18:34:48 +00:00
06b31c3d39 fixed bug not saving quantity for purchase 2022-11-25 00:17:51 +00:00
16 changed files with 1504 additions and 384 deletions

View File

@@ -99,7 +99,7 @@ namespace rockfishCore.Controllers
NewRequest.EmailConfirmCode = NewRequest.Id.ToString() + FetchKeyCode.generate();
await ct.SaveChangesAsync();
var verifyUrl = LICENSE_SERVER_URL + $"rvr/verify/{NewRequest.EmailConfirmCode}";
var body = $"Please verify your email address by clicking the link below or copy and pasting into a browser\r\n{verifyUrl}\r\n(If you did not request this you can ignore this message)";
var body = $"Please verify your email address by clicking the link below or copy and pasting into a browser\r\n{verifyUrl}\r\nOnce your email is verified the request will be processed manually during business hours.\r\n(If you did not request this you can ignore this message)";
//send confirmation email
RfMail.SendMessage("support@ayanova.com", NewRequest.Email, "AyaNova trial request email verification", body, false);
//return Ok(new { Accepted = true });
@@ -137,7 +137,7 @@ namespace rockfishCore.Controllers
{
ContentType = "text/html",
StatusCode = 200,
Content = "<html><body><h4>Email validated!</h4><p>Your request is being processed and you will receive an email with instructions for starting your AyaNova evaluation.</p></body></html>"
Content = "<html><body><h4>Email validated!</h4><p>Your request will be processed during business hours manually, and you will receive an email with instructions for starting your AyaNova evaluation.</p></body></html>"
};
}

View File

@@ -0,0 +1,5 @@
# url link for purchasing 7.3 and older individual user licenses
300751105 - AyaNova 7.3 & Older Scheduleable Resource License
[https://order.shareit.com/cart/add?vendorid=14466&PRODUCT[300751105]=1](https://order.shareit.com/cart/add?vendorid=14466&PRODUCT[300751105]=1 )

View File

@@ -1,7 +1,796 @@
# title
# Hosted server deployment
## section
## Create droplet
### detail
- LOCATION: user choice of US West, US East, Toronto Canada, Amsterdam Netherlands, Frankfurt Germany, Singapore, Bangalore India
- SIZE: 7 dollar AMD cpu second cheapest 1gb 25gb
- SSH KEY: "onayanova.com"
- NAME: domain name e.g. companyrequestingabbreviated.onayanova.com
(Use whatever could potentially be permanent name here in case of purchase)
blah blah blah
## Standup script and steps
```bash
#!/bin/bash
# 1) create new droplet **DO NOT PICK IPV6 just the monitoring option**
# 2) immediately set subdomain name in networking
# 3) Add droplet into raven-server-standard-firewall
# 4) check DNS available using https://letsdebug.net/
# 5) Open putty, select X.onayanova.com, change ip to new droplet domain name and open it
# 6) apt-get update && apt-get upgrade reboot, if necessary use apt --with-new-pkgs upgrade
# 7) TRIAL: make calendar entry 8 days hence to decommision and blueberry color reminder 0 days 11am
# 8) nano ayinit.sh paste in this
# 9) CHANGE the values at the top of the script to the desired time zone (see rfdocs for list) and subdomain, Save and exit nano
# 9) chmod a+x ayinit.sh
# 10) ./ayinit.sh
# Done. If trial use response email template from rfdocs and set server path
TIMEZONE='America/Vancouver'
DOMAINNAME='subdomain.onayanova.com'
#############################
echo STARTING...
timedatectl set-timezone $TIMEZONE
apt-get update
apt-get dist-upgrade -y
echo SET SWAP FILE
fallocate -l 1G /swapfile
chmod 600 /swapfile
mkswap /swapfile
swapon /swapfile
echo '/swapfile none swap sw 0 0' | sudo tee -a /etc/fstab
echo 'vm.swappiness=10' | sudo tee -a /etc/sysctl.conf
echo 'vm.vfs_cache_pressure=50' | sudo tee -a /etc/sysctl.conf
echo INSTALL .NET CORE
apt-get install -y aspnetcore-runtime-6.0
echo INSTALL POSTGRESQL
sh -c 'echo "deb http://apt.postgresql.org/pub/repos/apt $(lsb_release -cs)-pgdg main" > /etc/apt/sources.list.d/pgdg.list'
wget --quiet -O - https://www.postgresql.org/media/keys/ACCC4CF8.asc | sudo apt-key add -
sudo apt-get update
sudo apt-get -y install postgresql
sudo -u postgres psql -U postgres -d postgres -c "alter user postgres with password 'YOUR_PASSWORD_HERE';"
echo INSTALL REPORTING LIBS
sudo apt-get install -yq gconf-service libasound2 libatk1.0-0 libc6 libcairo2 libcups2 libdbus-1-3 \
libexpat1 libfontconfig1 libgcc1 libgconf-2-4 libgdk-pixbuf2.0-0 libglib2.0-0 libgtk-3-0 libnspr4 \
libpango-1.0-0 libpangocairo-1.0-0 libstdc++6 libx11-6 libx11-xcb1 libxcb1 libxcomposite1 \
libxcursor1 libxdamage1 libxext6 libxfixes3 libxi6 libxrandr2 libxrender1 libxss1 libxtst6 libgbm1 \
ca-certificates fonts-liberation libappindicator1 libnss3 lsb-release xdg-utils wget
echo INSTALL AYANOVA
apt install zip unzip -y
mkdir /var/ayanova
mkdir /var/ayanova/data
mkdir /var/ayanova/.local-chromium
cd /var/ayanova
curl -O https://www.ayanova.com/download/ayanova-subscription-linux-x64-server.zip && \
unzip -o ayanova-subscription-linux-x64-server.zip
chown -vR :www-data /var/ayanova
chmod -R g+rw /var/ayanova/data
chmod -R g+rwx /var/ayanova/.local-chromium
echo '[Unit]' >> /etc/systemd/system/ayanova.service
echo 'Description=AyaNova server' >> /etc/systemd/system/ayanova.service
echo '' >> /etc/systemd/system/ayanova.service
echo '[Service]' >> /etc/systemd/system/ayanova.service
echo 'WorkingDirectory=/var/ayanova' >> /etc/systemd/system/ayanova.service
echo 'ExecStart=/usr/bin/dotnet /var/ayanova/AyaNova.dll' >> /etc/systemd/system/ayanova.service
echo 'Restart=always' >> /etc/systemd/system/ayanova.service
echo 'RestartSec=10' >> /etc/systemd/system/ayanova.service
echo 'KillSignal=SIGINT' >> /etc/systemd/system/ayanova.service
echo 'SyslogIdentifier=ayanova-server' >> /etc/systemd/system/ayanova.service
echo 'User=www-data' >> /etc/systemd/system/ayanova.service
echo 'Environment=ASPNETCORE_ENVIRONMENT=Production' >> /etc/systemd/system/ayanova.service
echo 'Environment=DOTNET_PRINT_TELEMETRY_MESSAGE=false' >> /etc/systemd/system/ayanova.service
echo '' >> /etc/systemd/system/ayanova.service
echo '[Install]' >> /etc/systemd/system/ayanova.service
echo 'WantedBy=multi-user.target' >> /etc/systemd/system/ayanova.service
systemctl enable ayanova.service
echo START AYANOVA SERVICE
systemctl start ayanova.service
echo INSTALL NGINX
apt install nginx -y
echo 'server {' > /etc/nginx/sites-available/default
echo ' listen 80;' >> /etc/nginx/sites-available/default
echo " server_name $DOMAINNAME;" >> /etc/nginx/sites-available/default
echo ' location / {' >> /etc/nginx/sites-available/default
echo ' add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always;' >> /etc/nginx/sites-available/default
echo ' add_header X-XSS-Protection "1; mode=block" always;' >> /etc/nginx/sites-available/default
echo ' add_header X-Content-Type-Options "nosniff" always;' >> /etc/nginx/sites-available/default
echo ' add_header X-Frame-Options "SAMEORIGIN" always;' >> /etc/nginx/sites-available/default
echo ' add_header Referrer-Policy "strict-origin" always;' >> /etc/nginx/sites-available/default
echo ' gzip on;' >> /etc/nginx/sites-available/default
echo ' gzip_vary on;' >> /etc/nginx/sites-available/default
echo ' gzip_min_length 10240;' >> /etc/nginx/sites-available/default
echo ' gzip_proxied expired no-cache no-store private auth;' >> /etc/nginx/sites-available/default
echo ' gzip_http_version 1.1;' >> /etc/nginx/sites-available/default
echo ' gzip_types application/javascript text/css application/json text/plain;' >> /etc/nginx/sites-available/default
echo '' >> /etc/nginx/sites-available/default
echo ' proxy_pass http://127.0.0.1:7575;' >> /etc/nginx/sites-available/default
echo ' proxy_http_version 1.1;' >> /etc/nginx/sites-available/default
echo ' proxy_set_header Upgrade $http_upgrade;' >> /etc/nginx/sites-available/default
echo ' proxy_set_header Connection keep-alive;' >> /etc/nginx/sites-available/default
echo ' proxy_set_header Host $host;' >> /etc/nginx/sites-available/default
echo ' proxy_cache_bypass $http_upgrade;' >> /etc/nginx/sites-available/default
echo ' proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;' >> /etc/nginx/sites-available/default
echo ' proxy_set_header X-Forwarded-Proto $scheme;' >> /etc/nginx/sites-available/default
echo ' proxy_connect_timeout 3600;' >> /etc/nginx/sites-available/default
echo ' proxy_send_timeout 3600;' >> /etc/nginx/sites-available/default
echo ' proxy_read_timeout 3600;' >> /etc/nginx/sites-available/default
echo ' send_timeout 3600; ' >> /etc/nginx/sites-available/default
echo ' client_max_body_size 25M;' >> /etc/nginx/sites-available/default
echo ' }' >> /etc/nginx/sites-available/default
echo '}' >> /etc/nginx/sites-available/default
systemctl restart nginx
echo INSTALL CERTBOT
apt install certbot python3-certbot-nginx -y
echo GET CERTIFICATE
certbot --nginx --noninteractive --agree-tos --email ops@onayanova.com --no-eff-email -d $DOMAINNAME
echo ...COMPLETED
```
## Trial email response message
**BE SURE TO REPLACE XXXXXX BELOW WITH SERVER NAME**
```
Hello and thank you for your interest in AyaNova.
A hosted trial AyaNova server has just been activated in the London data center at the following address:
https://XXXXXXX.onayanova.com
(Note that due to internet DNS propagation it may take a few minutes for your internet service provider to update and recognize the address)
This server will be available for ** 7 days ** as a free trial and securely wiped and decommissioned after that time.
You can continue using this server with the purchase of a month to month or yearly subscription plan before the trial period has expired:
https://ayanova.com/r/pricing.htm#subscription
NEXT STEP
--------------
The next step is to log in and request a trial evaluation license key.
We have a guided tour available here to help you in your evaluation of AyaNova:
https://ayanova.com/docs/tour-bootstrap-intro/
If you have any questions please do not hesitate to reply to this message or use our contact form:
https://contact.ayanova.com/contact
```
## TIMEZONES
** Captured 2022-12-14 **
```
Africa/Abidjan
Africa/Accra
Africa/Addis_Ababa
Africa/Algiers
Africa/Asmara
Africa/Asmera
Africa/Bamako
Africa/Bangui
Africa/Banjul
Africa/Bissau
Africa/Blantyre
Africa/Brazzaville
Africa/Bujumbura
Africa/Cairo
Africa/Casablanca
Africa/Ceuta
Africa/Conakry
Africa/Dakar
Africa/Dar_es_Salaam
Africa/Djibouti
Africa/Douala
Africa/El_Aaiun
Africa/Freetown
Africa/Gaborone
Africa/Harare
Africa/Johannesburg
Africa/Juba
Africa/Kampala
Africa/Khartoum
Africa/Kigali
Africa/Kinshasa
Africa/Lagos
Africa/Libreville
Africa/Lome
Africa/Luanda
Africa/Lubumbashi
Africa/Lusaka
Africa/Malabo
Africa/Maputo
Africa/Maseru
Africa/Mbabane
Africa/Mogadishu
Africa/Monrovia
Africa/Nairobi
Africa/Ndjamena
Africa/Niamey
Africa/Nouakchott
Africa/Ouagadougou
Africa/Porto-Novo
Africa/Sao_Tome
Africa/Timbuktu
Africa/Tripoli
Africa/Tunis
Africa/Windhoek
America/Adak
America/Anchorage
America/Anguilla
America/Antigua
America/Araguaina
America/Argentina/Buenos_Aires
America/Argentina/Catamarca
America/Argentina/ComodRivadavia
America/Argentina/Cordoba
America/Argentina/Jujuy
America/Argentina/La_Rioja
America/Argentina/Mendoza
America/Argentina/Rio_Gallegos
America/Argentina/Salta
America/Argentina/San_Juan
America/Argentina/San_Luis
America/Argentina/Tucuman
America/Argentina/Ushuaia
America/Aruba
America/Asuncion
America/Atikokan
America/Atka
America/Bahia
America/Bahia_Banderas
America/Barbados
America/Belem
America/Belize
America/Blanc-Sablon
America/Boa_Vista
America/Bogota
America/Boise
America/Buenos_Aires
America/Cambridge_Bay
America/Campo_Grande
America/Cancun
America/Caracas
America/Catamarca
America/Cayenne
America/Cayman
America/Chicago
America/Chihuahua
America/Ciudad_Juarez
America/Coral_Harbour
America/Cordoba
America/Costa_Rica
America/Creston
America/Cuiaba
America/Curacao
America/Danmarkshavn
America/Dawson
America/Dawson_Creek
America/Denver
America/Detroit
America/Dominica
America/Edmonton
America/Eirunepe
America/El_Salvador
America/Ensenada
America/Fort_Nelson
America/Fort_Wayne
America/Fortaleza
America/Glace_Bay
America/Godthab
America/Goose_Bay
America/Grand_Turk
America/Grenada
America/Guadeloupe
America/Guatemala
America/Guayaquil
America/Guyana
America/Halifax
America/Havana
America/Hermosillo
America/Indiana/Indianapolis
America/Indiana/Knox
America/Indiana/Marengo
America/Indiana/Petersburg
America/Indiana/Tell_City
America/Indiana/Vevay
America/Indiana/Vincennes
America/Indiana/Winamac
America/Indianapolis
America/Inuvik
America/Iqaluit
America/Jamaica
America/Jujuy
America/Juneau
America/Kentucky/Louisville
America/Kentucky/Monticello
America/Knox_IN
America/Kralendijk
America/La_Paz
America/Lima
America/Los_Angeles
America/Louisville
America/Lower_Princes
America/Maceio
America/Managua
America/Manaus
America/Marigot
America/Martinique
America/Matamoros
America/Mazatlan
America/Mendoza
America/Menominee
America/Merida
America/Metlakatla
America/Mexico_City
America/Miquelon
America/Moncton
America/Monterrey
America/Montevideo
America/Montreal
America/Montserrat
America/Nassau
America/New_York
America/Nipigon
America/Nome
America/Noronha
America/North_Dakota/Beulah
America/North_Dakota/Center
America/North_Dakota/New_Salem
America/Nuuk
America/Ojinaga
America/Panama
America/Pangnirtung
America/Paramaribo
America/Phoenix
America/Port-au-Prince
America/Port_of_Spain
America/Porto_Acre
America/Porto_Velho
America/Puerto_Rico
America/Punta_Arenas
America/Rainy_River
America/Rankin_Inlet
America/Recife
America/Regina
America/Resolute
America/Rio_Branco
America/Rosario
America/Santa_Isabel
America/Santarem
America/Santiago
America/Santo_Domingo
America/Sao_Paulo
America/Scoresbysund
America/Shiprock
America/Sitka
America/St_Barthelemy
America/St_Johns
America/St_Kitts
America/St_Lucia
America/St_Thomas
America/St_Vincent
America/Swift_Current
America/Tegucigalpa
America/Thule
America/Thunder_Bay
America/Tijuana
America/Toronto
America/Tortola
America/Vancouver
America/Virgin
America/Whitehorse
America/Winnipeg
America/Yakutat
America/Yellowknife
Antarctica/Casey
Antarctica/Davis
Antarctica/DumontDUrville
Antarctica/Macquarie
Antarctica/Mawson
Antarctica/McMurdo
Antarctica/Palmer
Antarctica/Rothera
Antarctica/South_Pole
Antarctica/Syowa
Antarctica/Troll
Antarctica/Vostok
Arctic/Longyearbyen
Asia/Aden
Asia/Almaty
Asia/Amman
Asia/Anadyr
Asia/Aqtau
Asia/Aqtobe
Asia/Ashgabat
Asia/Ashkhabad
Asia/Atyrau
Asia/Baghdad
Asia/Bahrain
Asia/Baku
Asia/Bangkok
Asia/Barnaul
Asia/Beirut
Asia/Bishkek
Asia/Brunei
Asia/Calcutta
Asia/Chita
Asia/Choibalsan
Asia/Chongqing
Asia/Chungking
Asia/Colombo
Asia/Dacca
Asia/Damascus
Asia/Dhaka
Asia/Dili
Asia/Dubai
Asia/Dushanbe
Asia/Famagusta
Asia/Gaza
Asia/Harbin
Asia/Hebron
Asia/Ho_Chi_Minh
Asia/Hong_Kong
Asia/Hovd
Asia/Irkutsk
Asia/Istanbul
Asia/Jakarta
Asia/Jayapura
Asia/Jerusalem
Asia/Kabul
Asia/Kamchatka
Asia/Karachi
Asia/Kashgar
Asia/Kathmandu
Asia/Katmandu
Asia/Khandyga
Asia/Kolkata
Asia/Krasnoyarsk
Asia/Kuala_Lumpur
Asia/Kuching
Asia/Kuwait
Asia/Macao
Asia/Macau
Asia/Magadan
Asia/Makassar
Asia/Manila
Asia/Muscat
Asia/Nicosia
Asia/Novokuznetsk
Asia/Novosibirsk
Asia/Omsk
Asia/Oral
Asia/Phnom_Penh
Asia/Pontianak
Asia/Pyongyang
Asia/Qatar
Asia/Qostanay
Asia/Qyzylorda
Asia/Rangoon
Asia/Riyadh
Asia/Saigon
Asia/Sakhalin
Asia/Samarkand
Asia/Seoul
Asia/Shanghai
Asia/Singapore
Asia/Srednekolymsk
Asia/Taipei
Asia/Tashkent
Asia/Tbilisi
Asia/Tehran
Asia/Tel_Aviv
Asia/Thimbu
Asia/Thimphu
Asia/Tokyo
Asia/Tomsk
Asia/Ujung_Pandang
Asia/Ulaanbaatar
Asia/Ulan_Bator
Asia/Urumqi
Asia/Ust-Nera
Asia/Vientiane
Asia/Vladivostok
Asia/Yakutsk
Asia/Yangon
Asia/Yekaterinburg
Asia/Yerevan
Atlantic/Azores
Atlantic/Bermuda
Atlantic/Canary
Atlantic/Cape_Verde
Atlantic/Faeroe
Atlantic/Faroe
Atlantic/Jan_Mayen
Atlantic/Madeira
Atlantic/Reykjavik
Atlantic/South_Georgia
Atlantic/St_Helena
Atlantic/Stanley
Australia/ACT
Australia/Adelaide
Australia/Brisbane
Australia/Broken_Hill
Australia/Canberra
Australia/Currie
Australia/Darwin
Australia/Eucla
Australia/Hobart
Australia/LHI
Australia/Lindeman
Australia/Lord_Howe
Australia/Melbourne
Australia/NSW
Australia/North
Australia/Perth
Australia/Queensland
Australia/South
Australia/Sydney
Australia/Tasmania
Australia/Victoria
Australia/West
Australia/Yancowinna
Brazil/Acre
Brazil/DeNoronha
Brazil/East
Brazil/West
CET
CST6CDT
Canada/Atlantic
Canada/Central
Canada/Eastern
Canada/Mountain
Canada/Newfoundland
Canada/Pacific
Canada/Saskatchewan
Canada/Yukon
Chile/Continental
Chile/EasterIsland
Cuba
EET
EST
EST5EDT
Egypt
Eire
Etc/GMT
Etc/GMT+0
Etc/GMT+1
Etc/GMT+10
Etc/GMT+11
Etc/GMT+12
Etc/GMT+2
Etc/GMT+3
Etc/GMT+4
Etc/GMT+5
Etc/GMT+6
Etc/GMT+7
Etc/GMT+8
Etc/GMT+9
Etc/GMT-0
Etc/GMT-1
Etc/GMT-10
Etc/GMT-11
Etc/GMT-12
Etc/GMT-13
Etc/GMT-14
Etc/GMT-2
Etc/GMT-3
Etc/GMT-4
Etc/GMT-5
Etc/GMT-6
Etc/GMT-7
Etc/GMT-8
Etc/GMT-9
Etc/GMT0
Etc/Greenwich
Etc/UCT
Etc/UTC
Etc/Universal
Etc/Zulu
Europe/Amsterdam
Europe/Andorra
Europe/Astrakhan
Europe/Athens
Europe/Belfast
Europe/Belgrade
Europe/Berlin
Europe/Bratislava
Europe/Brussels
Europe/Bucharest
Europe/Budapest
Europe/Busingen
Europe/Chisinau
Europe/Copenhagen
Europe/Dublin
Europe/Gibraltar
Europe/Guernsey
Europe/Helsinki
Europe/Isle_of_Man
Europe/Istanbul
Europe/Jersey
Europe/Kaliningrad
Europe/Kiev
Europe/Kirov
Europe/Kyiv
Europe/Lisbon
Europe/Ljubljana
Europe/London
Europe/Luxembourg
Europe/Madrid
Europe/Malta
Europe/Mariehamn
Europe/Minsk
Europe/Monaco
Europe/Moscow
Europe/Nicosia
Europe/Oslo
Europe/Paris
Europe/Podgorica
Europe/Prague
Europe/Riga
Europe/Rome
Europe/Samara
Europe/San_Marino
Europe/Sarajevo
Europe/Saratov
Europe/Simferopol
Europe/Skopje
Europe/Sofia
Europe/Stockholm
Europe/Tallinn
Europe/Tirane
Europe/Tiraspol
Europe/Ulyanovsk
Europe/Uzhgorod
Europe/Vaduz
Europe/Vatican
Europe/Vienna
Europe/Vilnius
Europe/Volgograd
Europe/Warsaw
Europe/Zagreb
Europe/Zaporozhye
Europe/Zurich
Factory
GB
GB-Eire
GMT
GMT+0
GMT-0
GMT0
Greenwich
HST
Hongkong
Iceland
Indian/Antananarivo
Indian/Chagos
Indian/Christmas
Indian/Cocos
Indian/Comoro
Indian/Kerguelen
Indian/Mahe
Indian/Maldives
Indian/Mauritius
Indian/Mayotte
Indian/Reunion
Iran
Israel
Jamaica
Japan
Kwajalein
Libya
MET
MST
MST7MDT
Mexico/BajaNorte
Mexico/BajaSur
Mexico/General
NZ
NZ-CHAT
Navajo
PRC
PST8PDT
Pacific/Apia
Pacific/Auckland
Pacific/Bougainville
Pacific/Chatham
Pacific/Chuuk
Pacific/Easter
Pacific/Efate
Pacific/Enderbury
Pacific/Fakaofo
Pacific/Fiji
Pacific/Funafuti
Pacific/Galapagos
Pacific/Gambier
Pacific/Guadalcanal
Pacific/Guam
Pacific/Honolulu
Pacific/Johnston
Pacific/Kanton
Pacific/Kiritimati
Pacific/Kosrae
Pacific/Kwajalein
Pacific/Majuro
Pacific/Marquesas
Pacific/Midway
Pacific/Nauru
Pacific/Niue
Pacific/Norfolk
Pacific/Noumea
Pacific/Pago_Pago
Pacific/Palau
Pacific/Pitcairn
Pacific/Pohnpei
Pacific/Ponape
Pacific/Port_Moresby
Pacific/Rarotonga
Pacific/Saipan
Pacific/Samoa
Pacific/Tahiti
Pacific/Tarawa
Pacific/Tongatapu
Pacific/Truk
Pacific/Wake
Pacific/Wallis
Pacific/Yap
Poland
Portugal
ROC
ROK
Singapore
Turkey
UCT
US/Alaska
US/Aleutian
US/Arizona
US/Central
US/East-Indiana
US/Eastern
US/Hawaii
US/Indiana-Starke
US/Michigan
US/Mountain
US/Pacific
US/Samoa
UTC
Universal
W-SU
WET
Zulu
```
Command to get this:
```bash
timedatectl list-timezones > timezones.txt
```
## How to point a subdomain from an external company's domain to one of our hosted ayanova instances
e.g. ayanova.thecompany.com pointing to thecompany.ayanova.com
Ok, I did this and it worked based on the below so when it comes time to do it again try this out and clean up this area of docs
RESEARCH: how to enable a portion of a domain from an outside to point to their droplet, is that on them or on us?
how does discourse do it?? https://meta.discourse.org/t/configure-your-domain-name-for-hosted-discourse/21827
SO, I would say it works just like we do with the test servers, they would need to edit their domain record to point a subdomain to us so we would tell them to do that, i.e. they would say
aya.fouralarm.ca points to \[ipaddressofdroplet\] or discourse does it by subdomain, they would say point to fouralarm.hosted-by-discourse.com so I wonder if we can do that too,
Maybe a way to test this out is like this:
make a droplet, make a domain record gztestco.helloayanova.com that points to that droplet
then make a cert on the droplet for the original gztestco.helloayanova.com and in nginx, request the cert so this is like the initial trial period or setup.
Test, confirm gztestco.helloayanova.com is working
then go to ayanova domain and make a CNAME (CNAME is different and is host pointing to host not to ip address) record aya.ayanova.com and point it to gztestco.helloayanova.com
Then change nginx config in droplet and ADD aya.ayanova.com and
then request a new cert with both aya.ayanova.com and gztestco.helloayanova.com and see if it works from both domains.
** To request a new cert need different command and need to know cert name which is the first domain requested but to confirm use certbot certificates to view the name
then use the command like this pattern: certbot --nginx --cert-name gztestco.helloayanova.com -d gztestco.helloayanova.com,aya.ayanova.com
(we would keep both domains in case they have dns issues with their own domain and need access or fuck up the redirect somehow later on)
THIS works, and this is the pattern for customers where aya.ayanova.com would be their equivalent to their ayanova subdomain
record they make with their domain registrar or whoever.
**TESTED, WORKS!: I do have a concern about the nginx cert autorenewal as expanding the domains didn't automatically edit the nginx config file and add the managed by certbot bit for the aya.ayanova.com domain

View File

@@ -22,10 +22,175 @@ The same format can be used to expand the set of domains a certificate contains,
certbot certonly --cert-name example.com -d example.org,www.example.org
```
SO FOR EXAMPLE for HelloAyaNova.com
SO FOR EXAMPLE for a test adding sockeye to onayanova.com on devops
- Added subdomain sockeye.onayanova.com to onayanova.com domain record and pointed to Devops server.
- Edited /etc/nginx/sites-available/default file and added sockeye.onayanova.com to server block only, didn't add it to any other part:
i.e. went from this:
```yml
server {
server_name test.onayanova.com;
location / {
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always;
add_header X-XSS-Protection "1; mode=block" always;
add_header X-Content-Type-Options "nosniff" always;
add_header X-Frame-Options "SAMEORIGIN" always;
add_header Referrer-Policy "strict-origin" always;
gzip on;
gzip_vary on;
gzip_min_length 10240;
gzip_proxied expired no-cache no-store private auth;
gzip_http_version 1.1;
gzip_types application/javascript text/css application/json text/plain;
proxy_pass http://127.0.0.1:7575;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection keep-alive;
proxy_set_header Host $host;
proxy_cache_bypass $http_upgrade;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_connect_timeout 3600;
proxy_send_timeout 3600;
proxy_read_timeout 3600;
send_timeout 3600;
# Note: the client_max_body_size setting controls the maximum upload size for attachments in AyaNova
# it is a good security precaution to set this value only as high as absolutely needed by your staff for
# file attachment uploads
# AyaNova can handle up to 10GB maximum so the highest setting allowed here would be:
# client_max_body_size 10GB;
client_max_body_size 25M;
}
listen 443 ssl; # managed by Certbot
ssl_certificate /etc/letsencrypt/live/test.onayanova.com/fullchain.pem; # managed by Certbot
ssl_certificate_key /etc/letsencrypt/live/test.onayanova.com/privkey.pem; # managed by Certbot
include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot
}
server {
if ($host = test.onayanova.com) {
return 301 https://$host$request_uri;
} # managed by Certbot
listen 80;
server_name test.onayanova.com;
return 404; # managed by Certbot
}
```
to this:
```yml
server {
server_name test.onayanova.com sockeye.onayanova.com;
location / {
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always;
add_header X-XSS-Protection "1; mode=block" always;
add_header X-Content-Type-Options "nosniff" always;
add_header X-Frame-Options "SAMEORIGIN" always;
add_header Referrer-Policy "strict-origin" always;
gzip on;
gzip_vary on;
gzip_min_length 10240;
gzip_proxied expired no-cache no-store private auth;
gzip_http_version 1.1;
gzip_types application/javascript text/css application/json text/plain;
proxy_pass http://127.0.0.1:7575;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection keep-alive;
proxy_set_header Host $host;
proxy_cache_bypass $http_upgrade;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_connect_timeout 3600;
proxy_send_timeout 3600;
proxy_read_timeout 3600;
send_timeout 3600;
# Note: the client_max_body_size setting controls the maximum upload size for attachments in AyaNova
# it is a good security precaution to set this value only as high as absolutely needed by your staff for
# file attachment uploads
# AyaNova can handle up to 10GB maximum so the highest setting allowed here would be:
# client_max_body_size 10GB;
client_max_body_size 25M;
}
listen 443 ssl; # managed by Certbot
ssl_certificate /etc/letsencrypt/live/test.onayanova.com/fullchain.pem; # managed by Certbot
ssl_certificate_key /etc/letsencrypt/live/test.onayanova.com/privkey.pem; # managed by Certbot
include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot
}
server {
if ($host = test.onayanova.com) {
return 301 https://$host$request_uri;
} # managed by Certbot
listen 80;
server_name test.onayanova.com;
return 404; # managed by Certbot
}
```
Test and reload nginx the request new certificate:
(note no spaces in subdomain names or it balks)
```bash
certbot --nginx --cert-name helloayanova.com -d test.helloayanova.com,helloayanova.com,www.helloayanova.com,1665.helloayanova.com,7331.helloayanova.com,8888.helloayanova.com,a261.helloayanova.com
root@devops:/etc/nginx/sites-available# nginx -t
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful
root@devops:/etc/nginx/sites-available# nginx -s reload
root@devops:/etc/nginx/sites-available# certbot --nginx --cert-name test.onayanova.com -d test.onayanova.com,sockeye.onayanova.com
Saving debug log to /var/log/letsencrypt/letsencrypt.log
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
You are updating certificate test.onayanova.com to include new domain(s):
+ sockeye.onayanova.com
You are also removing previously included domain(s):
(None)
Did you intend to make this change?
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
(U)pdate certificate/(C)ancel: u
Renewing an existing certificate for test.onayanova.com and 1 more domains
Successfully received certificate.
Certificate is saved at: /etc/letsencrypt/live/test.onayanova.com/fullchain.pem
Key is saved at: /etc/letsencrypt/live/test.onayanova.com/privkey.pem
This certificate expires on 2023-04-04.
These files will be updated when the certificate renews.
Certbot has set up a scheduled task to automatically renew this certificate in the background.
Deploying certificate
Successfully deployed certificate for test.onayanova.com to /etc/nginx/sites-enabled/default
Successfully deployed certificate for sockeye.onayanova.com to /etc/nginx/sites-enabled/default
Your existing certificate has been successfully renewed, and the new certificate has been installed.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
```
## NGINX
@@ -123,18 +288,26 @@ Open sql console as postgres admin user:
sudo -u postgres psql
```
Connect to the AyaNova db and run a command:
```sql
\\c AyaNova
update alicense set licenseagree=false;
select * from alicense;
```
#### Restore AyaNova from backup
- Ensure have the db-xxxxxx.backup database backup and the at-xxxxx.zip attachments file
- Make a backup of the data folders first for insurance
- restart ayanova with permanently erase database set, this will erase the db adn also all attachments
- Stop the AyaNova server `systemctl stop ayanova.service`
- Upload the attachments to the root home folder
- Upload the database backup to `/var/lib/postgresql`
- Unzip attachments: from ayanova data attachments folder run `unzip ~/at-20220920220001750`
- Restore the database from anywhere with this command: `sudo -u postgres pg_restore -U postgres -c -d AyaNova /var/lib/postgresql/db-20220920220000302.backup`
- Start the AyaNova server `systemctl start ayanova.service`
- confirm can login all is well
- Ensure have the db-xxxxxx.backup database backup and the at-xxxxx.zip attachments file
- Make a backup of the data folders first for insurance
- restart ayanova with permanently erase database set, this will erase the db adn also all attachments
- Stop the AyaNova server `systemctl stop ayanova.service`
- Upload the attachments to the root home folder
- Upload the database backup to `/var/lib/postgresql`
- Unzip attachments: from ayanova data attachments folder run `unzip ~/at-20220920220001750`
- Restore the database from anywhere with this command: `sudo -u postgres pg_restore -U postgres -c -d AyaNova /var/lib/postgresql/db-20220920220000302.backup`
- Start the AyaNova server `systemctl start ayanova.service`
- confirm can login all is well
#### List all dbs
@@ -235,17 +408,17 @@ In a pinch the keys could be moved / removed to another computer but this is mos
How to generate a key and upload to digitalocean for using with droplet and saving to keepass
- open puttygen
- keep RSA change bits from 2048 to 4096
- click generate
- mouse around
- change key comment to serversubdomainname.onayanova.com (or whatever the actual subdomain / domain is for this key)
- save the private key temporarily to a folder (it will end up in keepass as an attachment)
- DO NOT SET A PASSWORD HERE, keepass will secure the key, there's no need for the extra password and this is all about saving time
- copy the public key box text and go to digitalocean Settings -> Security SSH keys section and add it as a new saved public key named same subdomina.onayanova.com or as appropriate
- can close puttygen at this point if ever need it can get teh public key from the private key file again in future
- Use this when creating a droplet, OR you can manually add it later via text editor: https://docs.digitalocean.com/products/droplets/how-to/add-ssh-keys/to-existing-droplet/
(note, the public key format displayed in puttygen when you open or generate the private key in the public key box is the only one that works with ssh, not the format used when it's saved to a file from puttygen )
- open puttygen
- keep RSA change bits from 2048 to 4096
- click generate
- mouse around
- change key comment to serversubdomainname.onayanova.com (or whatever the actual subdomain / domain is for this key)
- save the private key temporarily to a folder (it will end up in keepass as an attachment)
- DO NOT SET A PASSWORD HERE, keepass will secure the key, there's no need for the extra password and this is all about saving time
- copy the public key box text and go to digitalocean Settings -> Security SSH keys section and add it as a new saved public key named same subdomina.onayanova.com or as appropriate
- can close puttygen at this point if ever need it can get teh public key from the private key file again in future
- Use this when creating a droplet, OR you can manually add it later via text editor: https://docs.digitalocean.com/products/droplets/how-to/add-ssh-keys/to-existing-droplet/
(note, the public key format displayed in puttygen when you open or generate the private key in the public key box is the only one that works with ssh, not the format used when it's saved to a file from puttygen )
### KeePass / KeeAgent
@@ -409,14 +582,14 @@ Updates done outside the hours of 8am to 6pm in each data centers location
4:00pm our local Courtenay time is good for almost everyone except san francisco data center
- New York, USA 7:00 pm EDT
- Amsterdam, Netherlands 1:00 am CEST
- Victoria, Canada 4:00 pm PDT
- Singapore, Singapore 7:00 am SGT
- London, United Kingdom 12:00 midn BST
- Frankfurt, Germany 1:00 am CEST
- Bengaluru, India 4:30 am IST
- San Francisco 7am
- New York, USA 7:00 pm EDT
- Amsterdam, Netherlands 1:00 am CEST
- Victoria, Canada 4:00 pm PDT
- Singapore, Singapore 7:00 am SGT
- London, United Kingdom 12:00 midn BST
- Frankfurt, Germany 1:00 am CEST
- Bengaluru, India 4:30 am IST
- San Francisco 7am
## Website general

View File

@@ -1,7 +1,6 @@
# title
# Subscription Service info
## section
## Data centers
### detail
blah blah blah
Subscriptions available in data centers located in:
San Francisco, New York, Toronto, Amsterdam, London, Frankfurt, Singapore, Bangalore, Sydney Australia

View File

@@ -0,0 +1,89 @@
# how to do discounts if company "moves up" to another level (larger # of users)
Single $159:
First year 103.35 license + 55.65 support/update for the year
Renewal year support/updates $55.65
Up to 5 $695
First year $451.75 license only + $243.25 support/update for the year
Renewal year support/updates $243.25
Up to 10 $1190
First year $773.50 license + $416.50 support/update for the year
Renewal year support/updates $416.50
Up to 15 $1650
First year $1072.50 license + $577.50 support/update for the year
Renewal year support/updates $577.50
Up to 20 $1980
First year $1287 license + $693 support/update for the year
Renewal year support/updates $693
Up to 50 $3950
First year $2567.50 license + $1382.50 support/update for the year
Renewal year support/updates $1382.50
Discounts are offered when moving up a level. Refunds are not issued to move down a level.
Originally purchased Single.
Discount is ($103.35 Single license component + (55.65/12 \* remaining months))
Originally purchased Up to 5
Discount is ($451.75 Up to 5 license component + (243.25/12 \* remaining months))
Originally purchased Up to 10
Discount is ($773.50 Up to 10 license component + ($416.50/12 \* remaining months)
Originally purchased Up to 15
Discount is ($1072.50 Up to 15 license component + ($577.50/12 \* remaining months)
Originally purchased Up to 20
Discount is ($1287 Up to 20 license component + ($693.00/12 \* remaining months)
(nothing here for Up to 50 as there is no larger number than 50)
Info to get:
What did they pay for their original license+supportupdates?
How many full months remaining of their existing 12 month supportupdates subscription? (give 'valid until date' for the coupon off based on renewal date so we don't rip ourselves off for a month)
Discount = ( originallicense$portion + ( $supportupdates/12 \* months remaining)
EXAMPLE:
Company purchased Up to 5 for $695.00 ($451.50 license + 243.25 supportupdates for year) July 1 2020
Company contacts that wants to purchase Up to 15 in Oct before Nov 1 (has 8 months remaining of existing subscription):
Has "used up" support and updates for four months -- July supportupdate$20.27, Aug supportupdates$20.27, Sept supportupdates$20.27, Oct supportupdate$20.27 (4 months of support/updates used up, has 8 months @ $20.27/month “credit”)
Discount to give: $613.66
derived from $451.50license component + (243.25supportupdates/12 \* 8 months remaining of this years subscription support/updates)
EXAMPLE
Company purchased Up to 20 for $1980
Into third year (4 months remaining on subscription) needs to go to Up to 50
Give discount $1518 off (their price for Up to 50 will be $2432 = 3950 - 1518 if purchased with 4 months remaining)
$1518 = $1287 origlicensecomponent + (693supportupdates/12 \* 4 months remaining in subscription)

View File

@@ -31,6 +31,8 @@ nav:
- 'Extending trial manually': 'license-extend-trial.md'
- 'Revoking': 'license-revoke.md'
- 'V7 to Raven discounting': 'v7discount.md'
- '7.3 or older purchase': '73-license-purchase.md'
- 'v7 how to discount upgrade': 'v7-discount-upgrade.md'
- Hosting:
- 'Setup': 'host-setup.md'
- Build:

View File

@@ -5,7 +5,7 @@
1) SET VERSION
SET app.api RFVERSION property
RENAME ?rfv=6.27 parameter in default.htm to the new version so all files update on mobile
RENAME ?rfv=6.29 parameter in default.htm to the new version so all files update on mobile
1.5) Run buildtemplates.bat if handlebars templates have changed at all

View File

@@ -2,7 +2,7 @@ namespace rockfishCore.Util
{
public static class RfVersion
{
public const string NumberOnly="6.27";
public const string NumberOnly="6.29";
public const string Full = "Rockfish server " + NumberOnly;
}
}

View File

@@ -11,76 +11,76 @@
<title>Rockfish loading....</title>
<!-- ICONS / MANIFEST -->
<link rel="apple-touch-icon" sizes="180x180" href="/apple-touch-icon.png?rfv=6.27">
<link rel="icon" type="image/png" sizes="32x32" href="/favicon-32x32.png?rfv=6.27">
<link rel="icon" type="image/png" sizes="16x16" href="/favicon-16x16.png?rfv=6.27">
<link rel="manifest" href="/manifest.json?rfv=6.27">
<link rel="mask-icon" href="/safari-pinned-tab.svg?rfv=6.27" color="#5bbad5">
<link rel="apple-touch-icon" sizes="180x180" href="/apple-touch-icon.png?rfv=6.29">
<link rel="icon" type="image/png" sizes="32x32" href="/favicon-32x32.png?rfv=6.29">
<link rel="icon" type="image/png" sizes="16x16" href="/favicon-16x16.png?rfv=6.29">
<link rel="manifest" href="/manifest.json?rfv=6.29">
<link rel="mask-icon" href="/safari-pinned-tab.svg?rfv=6.29" color="#5bbad5">
<meta name="theme-color" content="#ffffff">
<!-- 3rd party components fonts and icons -->
<link href="css/materialdesignicons.min.css?rfv=6.27" media="all" rel="stylesheet" type="text/css" />
<link rel="stylesheet" href="css/bootstrap.min.css?rfv=6.27" type="text/css" />
<link rel="stylesheet" href="css/app.css?rfv=6.27" type="text/css" />
<link rel="stylesheet" href="css/mdi-bs4-compat.css?rfv=6.27" type="text/css" />
<link href="css/materialdesignicons.min.css?rfv=6.29" media="all" rel="stylesheet" type="text/css" />
<link rel="stylesheet" href="css/bootstrap.min.css?rfv=6.29" type="text/css" />
<link rel="stylesheet" href="css/app.css?rfv=6.29" type="text/css" />
<link rel="stylesheet" href="css/mdi-bs4-compat.css?rfv=6.29" type="text/css" />
<!-- third-party javascript -->
<script src="js/lib/jquery-3.3.1.min.js?rfv=6.27"></script>
<script src="js/lib/page.js?rfv=6.27"></script>
<script src="js/lib/jquery.event.gevent.js?rfv=6.27"></script>
<script src="js/lib/jquery.gzserialize.js?rfv=6.27"></script>
<script src="js/lib/handlebars.runtime.min-v4.7.6.js?rfv=6.27"></script>
<script src="js/lib/store.min.js?rfv=6.27"></script>
<script src="js/lib/jquery.autocomplete.min.js?rfv=6.27"></script>
<script src="js/lib/moment.min.js?rfv=6.27"></script>
<script src="js/lib/jquery-3.3.1.min.js?rfv=6.29"></script>
<script src="js/lib/page.js?rfv=6.29"></script>
<script src="js/lib/jquery.event.gevent.js?rfv=6.29"></script>
<script src="js/lib/jquery.gzserialize.js?rfv=6.29"></script>
<script src="js/lib/handlebars.runtime.min-v4.7.6.js?rfv=6.29"></script>
<script src="js/lib/store.min.js?rfv=6.29"></script>
<script src="js/lib/jquery.autocomplete.min.js?rfv=6.29"></script>
<script src="js/lib/moment.min.js?rfv=6.29"></script>
<!-- our javascript -->
<script src="js/index.js?rfv=6.27"></script>
<script src="js/app.util.js?rfv=6.27"></script>
<script src="js/app.api.js?rfv=6.27"></script>
<script src="js/app.utilB.js?rfv=6.27"></script>
<script src="js/app.nav.js?rfv=6.27"></script>
<script src="js/app.shell.js?rfv=6.27"></script>
<script src="js/app.fourohfour.js?rfv=6.27"></script>
<script src="js/app.authenticate.js?rfv=6.27"></script>
<script src="js/app.customers.js?rfv=6.27"></script>
<script src="js/app.customerEdit.js?rfv=6.27"></script>
<script src="js/app.customerSites.js?rfv=6.27"></script>
<script src="js/app.customerSiteEdit.js?rfv=6.27"></script>
<script src="js/app.purchases.js?rfv=6.27"></script>
<script src="js/app.purchaseEdit.js?rfv=6.27"></script>
<script src="js/app.license.js?rfv=6.27"></script>
<script src="js/app.licenseTemplates.js?rfv=6.27"></script>
<script src="js/app.licenseRequestEdit.js?rfv=6.27"></script>
<script src="js/app.licenses.js?rfv=6.27"></script>
<script src="js/app.licenseView.js?rfv=6.27"></script>
<script src="js/app.reportData.js?rfv=6.27"></script>
<script src="js/app.reportDataProdEmail.js?rfv=6.27"></script>
<script src="js/app.reportDataExpires.js?rfv=6.27"></script>
<script src="js/app.search.js?rfv=6.27"></script>
<script src="js/app.subscription.js?rfv=6.27"></script>
<script src="js/app.subnotify.js?rfv=6.27"></script>
<script src="js/app.templates.js?rfv=6.27"></script>
<script src="js/app.templateEdit.js?rfv=6.27"></script>
<script src="js/app.inbox.js?rfv=6.27"></script>
<script src="js/app.mailEdit.js?rfv=6.27"></script>
<script src="js/app.rfcaseEdit.js?rfv=6.27"></script>
<script src="js/app.rfcases.js?rfv=6.27"></script>
<script src="js/app.rfsettings.js?rfv=6.27"></script>
<script src="js/app.ops.js?rfv=6.27"></script>
<script src="js/app.trials.js?rfv=6.27"></script>
<script src="js/app.trialEdit.js?rfv=6.27"></script>
<script src="js/app.ravLicenses.js?rfv=6.27"></script>
<script src="js/app.ravLicense.js?rfv=6.27"></script>
<script src="js/app.vendorNotifications.js?rfv=6.27"></script>
<script src="js/app.vendorNotification.js?rfv=6.27"></script>
<script src="js/index.js?rfv=6.29"></script>
<script src="js/app.util.js?rfv=6.29"></script>
<script src="js/app.api.js?rfv=6.29"></script>
<script src="js/app.utilB.js?rfv=6.29"></script>
<script src="js/app.nav.js?rfv=6.29"></script>
<script src="js/app.shell.js?rfv=6.29"></script>
<script src="js/app.fourohfour.js?rfv=6.29"></script>
<script src="js/app.authenticate.js?rfv=6.29"></script>
<script src="js/app.customers.js?rfv=6.29"></script>
<script src="js/app.customerEdit.js?rfv=6.29"></script>
<script src="js/app.customerSites.js?rfv=6.29"></script>
<script src="js/app.customerSiteEdit.js?rfv=6.29"></script>
<script src="js/app.purchases.js?rfv=6.29"></script>
<script src="js/app.purchaseEdit.js?rfv=6.29"></script>
<script src="js/app.license.js?rfv=6.29"></script>
<script src="js/app.licenseTemplates.js?rfv=6.29"></script>
<script src="js/app.licenseRequestEdit.js?rfv=6.29"></script>
<script src="js/app.licenses.js?rfv=6.29"></script>
<script src="js/app.licenseView.js?rfv=6.29"></script>
<script src="js/app.reportData.js?rfv=6.29"></script>
<script src="js/app.reportDataProdEmail.js?rfv=6.29"></script>
<script src="js/app.reportDataExpires.js?rfv=6.29"></script>
<script src="js/app.search.js?rfv=6.29"></script>
<script src="js/app.subscription.js?rfv=6.29"></script>
<script src="js/app.subnotify.js?rfv=6.29"></script>
<script src="js/app.templates.js?rfv=6.29"></script>
<script src="js/app.templateEdit.js?rfv=6.29"></script>
<script src="js/app.inbox.js?rfv=6.29"></script>
<script src="js/app.mailEdit.js?rfv=6.29"></script>
<script src="js/app.rfcaseEdit.js?rfv=6.29"></script>
<script src="js/app.rfcases.js?rfv=6.29"></script>
<script src="js/app.rfsettings.js?rfv=6.29"></script>
<script src="js/app.ops.js?rfv=6.29"></script>
<script src="js/app.trials.js?rfv=6.29"></script>
<script src="js/app.trialEdit.js?rfv=6.29"></script>
<script src="js/app.ravLicenses.js?rfv=6.29"></script>
<script src="js/app.ravLicense.js?rfv=6.29"></script>
<script src="js/app.vendorNotifications.js?rfv=6.29"></script>
<script src="js/app.vendorNotification.js?rfv=6.29"></script>
<!-- handlebars templates -->
<script src="js/templates/templates.js?rfv=6.27"></script>
<script src="js/templates/templates.js?rfv=6.29"></script>
<script>
@@ -110,7 +110,7 @@ window.onerror = function ( error ) {
<body class="rf-body">
<div id="app" class="container"></div>
<script src="js/lib/bootstrap.min.js?rfv=6.27"></script>
<script src="js/lib/bootstrap.min.js?rfv=6.29"></script>
</body>
</html>

View File

@@ -30,7 +30,7 @@ app.api = (function () {
licenseEmailResponse,
test;
RockFishVersion = "6.27";
RockFishVersion = "6.29";
//////////////////////////////////////////////////////////////////////////////////////
// NOT AUTHORIZED ERROR HANDLER

View File

@@ -7,269 +7,267 @@
/*global $, app */
app.purchaseEdit = (function() {
"use strict";
//---------------- BEGIN MODULE SCOPE VARIABLES --------------
var stateMap = {},
onSave,
onDelete,
onRenew,
configModule,
initModule,
onPasteNotes;
//----------------- END MODULE SCOPE VARIABLES ---------------
app.purchaseEdit = (function () {
"use strict";
//---------------- BEGIN MODULE SCOPE VARIABLES --------------
var stateMap = {},
onSave,
onDelete,
onRenew,
configModule,
initModule,
onPasteNotes;
//----------------- END MODULE SCOPE VARIABLES ---------------
//------------------- BEGIN UTILITY METHODS ------------------
//-------------------- END UTILITY METHODS -------------------
//------------------- BEGIN UTILITY METHODS ------------------
//-------------------- END UTILITY METHODS -------------------
//------------------- BEGIN EVENT HANDLERS -------------------
//------------------- BEGIN EVENT HANDLERS -------------------
onSave = function(event) {
event.preventDefault();
$.gevent.publish("app-clear-error");
//get form data
var formData = $("form").serializeArray({
checkboxesAsBools: true
});
var submitData = app.utilB.objectifyFormDataArray(formData);
//is this a new record?
if (stateMap.id != "new") {
//put id into the form data
submitData.id = stateMap.id;
app.api.update("purchase", submitData, function(res) {
if (res.error) {
$.gevent.publish("app-show-error", res.msg);
}
});
} else {
//create new record
app.api.create("purchase", submitData, function(res) {
if (res.error) {
$.gevent.publish("app-show-error", res.msg);
} else {
page(
"#!/purchaseEdit/" + res.id + "/" + stateMap.context.params.site_id
);
return false;
}
});
}
return false; //prevent default
};
onRenew = function(event) {
event.preventDefault();
$.gevent.publish("app-clear-error");
if (stateMap.id == "new") {
$.gevent.publish(
"app-show-error",
"Save this record before attempting to renew it"
);
return false;
}
stateMap.id = "new";
//case 3396, no more renewal or dupe names
// var nm = $('#name').val();
// nm = "DUPE-" + nm;
// $('#name').val(nm);
//case 3396, set values accordingly
//Clear salesOrderNumber
$("#salesOrderNumber").val("");
//set purchaseDate to today
$("#purchaseDate").val(
moment()
.toISOString()
.substring(0, 10)
);
//set expireDate to plus one year from today
$("#expireDate").val(
moment()
.add(1, "years")
.toISOString()
.substring(0, 10)
);
//clear the couponCode
$("#couponCode").val("");
//clear the notes
$("#notes").val("");
$("#renewNoticeSent").prop("checked", false);
$("#cancelDate").val("");
return false; //prevent default
};
//ONDELETE
//
onDelete = function(event) {
event.preventDefault();
$.gevent.publish("app-clear-error");
var r = confirm("Are you sure you want to delete this record?");
if (r == true) {
//==== DELETE ====
app.api.remove("purchase/" + stateMap.id, function(res) {
if (res.error) {
$.gevent.publish("app-show-error", res.msg);
} else {
//deleted, return to master list
page("#!/purchases/" + stateMap.context.params.site_id);
return false;
}
});
} else {
return false;
}
return false; //prevent default?
};
onPasteNotes = function(event) {
var clipboardData, pastedData;
var e = event.originalEvent;
// // Stop data actually being pasted into div
// e.stopPropagation();
// e.preventDefault();
// Get pasted data via clipboard API
clipboardData = e.clipboardData || window.clipboardData;
pastedData = clipboardData.getData("Text");
//Iterate through the lines looking for the SHareIt name=value lines (they all contain equal signs)
var lines = pastedData.split("\n"); // lines is an array of strings
var purchaseData = {};
// Loop through all lines
for (var j = 0; j < lines.length; j++) {
var thisLine = lines[j];
if (thisLine.includes("=")) {
var thisElement = thisLine.split("=");
purchaseData[thisElement[0].trim()] = thisElement[1].trim();
}
}
//Now have an object with the value pairs in it
if (purchaseData["ShareIt Ref #"]) {
$("#salesOrderNumber").val(purchaseData["ShareIt Ref #"]);
}
// if (purchaseData["E-Mail"]) {
// $("#email").val(purchaseData["E-Mail"]);
// }
};
//-------------------- END EVENT HANDLERS --------------------
//------------------- BEGIN PUBLIC METHODS -------------------
//CONFIGMODULE
//
configModule = function(context) {
stateMap.context = context.context;
if (stateMap.context.params.id) {
stateMap.id = stateMap.context.params.id;
}
};
//INITMODULE
//
initModule = function($container) {
if (typeof $container === "undefined") {
$container = $("#app-shell-main-content");
}
$container.html(Handlebars.templates["app.purchaseEdit"]({}));
var title = "Purchase";
if (!stateMap.context.params.site_id) {
throw "app.purchaseEdit.js::initModule - There is no stateMap.context.params.site_id!";
}
//Append master record id as a hidden form field for referential integrity
$("<input />")
.attr("type", "hidden")
.attr("name", "siteId")
.attr("value", stateMap.context.params.site_id)
.appendTo("#frm");
//fetch entire site record to get name *and* customer id which is required for redundancy
//RFC - get site name and customer name for form
app.api.get("site/" + stateMap.context.params.site_id, function(res) {
if (res.error) {
$.gevent.publish("app-show-error", res.msg);
} else {
//Also append customer ID redundantly
$("<input />")
.attr("type", "hidden")
.attr("name", "customerId")
.attr("value", res.customerId)
.appendTo("#frm");
title = "Purchase - " + res.name;
onSave = function (event) {
event.preventDefault();
$.gevent.publish("app-clear-error");
//get form data
var formData = $("form").serializeArray({
checkboxesAsBools: true
});
var submitData = app.utilB.objectifyFormDataArray(formData);
//serializeArray method doesn't handle "Number" type inputs at all
//just ignores them so we need to do it here manually
submitData['quantity']=Number($("#quantity").val());
//I know, it's weird, but it wasn't required way back in the day and the plan is to replace rockfish with a Vue/vuetify app anyway.
console.log({ formData: formData, submitData: submitData });
//is this a new record?
if (stateMap.id != "new") {
//fetch existing record
app.api.get("purchase/" + stateMap.id, function(res) {
if (res.error) {
$.gevent.publish("app-show-error", res.msg);
} else {
//fill out form
app.utilB.formData(res);
}
});
//put id into the form data
submitData.id = stateMap.id;
app.api.update("purchase", submitData, function (res) {
if (res.error) {
$.gevent.publish("app-show-error", res.msg);
}
});
} else {
//it's a new record, set default
$("#quantity").val(1);
$("#purchaseDate").val(new Date().toISOString().substring(0, 10));
$("#expireDate").val(
moment()
.add(1, "years")
.toISOString()
.substring(0, 10)
);
$("#vendorName").val("ShareIt");
//create new record
app.api.create("purchase", submitData, function (res) {
if (res.error) {
$.gevent.publish("app-show-error", res.msg);
} else {
page(
"#!/purchaseEdit/" +
res.id +
"/" +
stateMap.context.params.site_id
);
return false;
}
});
}
}
});
return false; //prevent default
};
//Context menu
app.nav.contextClear();
app.nav.contextAddLink(
"purchases/" + stateMap.context.params.site_id,
"Purchases",
"basket"
);
onRenew = function (event) {
event.preventDefault();
$.gevent.publish("app-clear-error");
// bind actions
$("#btn-save").bind("click", onSave);
$("#btn-delete").bind("click", onDelete);
$("#btn-renew").bind("click", onRenew);
$("#notes").bind("paste", onPasteNotes);
if (stateMap.id == "new") {
$.gevent.publish(
"app-show-error",
"Save this record before attempting to renew it"
);
return false;
}
stateMap.id = "new";
//Autocomplete
app.utilB.autoComplete("name", "purchase.name");
app.utilB.autoComplete("productCode", "purchase.productCode");
app.utilB.autoComplete("vendorName", "purchase.vendorName");
};
//case 3396, no more renewal or dupe names
// var nm = $('#name').val();
// nm = "DUPE-" + nm;
// $('#name').val(nm);
// return public methods
return {
configModule: configModule,
initModule: initModule
};
//------------------- END PUBLIC METHODS ---------------------
//case 3396, set values accordingly
//Clear salesOrderNumber
$("#salesOrderNumber").val("");
//set purchaseDate to today
$("#purchaseDate").val(moment().toISOString().substring(0, 10));
//set expireDate to plus one year from today
$("#expireDate").val(
moment().add(1, "years").toISOString().substring(0, 10)
);
//clear the couponCode
$("#couponCode").val("");
//clear the notes
$("#notes").val("");
$("#renewNoticeSent").prop("checked", false);
$("#cancelDate").val("");
return false; //prevent default
};
//ONDELETE
//
onDelete = function (event) {
event.preventDefault();
$.gevent.publish("app-clear-error");
var r = confirm("Are you sure you want to delete this record?");
if (r == true) {
//==== DELETE ====
app.api.remove("purchase/" + stateMap.id, function (res) {
if (res.error) {
$.gevent.publish("app-show-error", res.msg);
} else {
//deleted, return to master list
page("#!/purchases/" + stateMap.context.params.site_id);
return false;
}
});
} else {
return false;
}
return false; //prevent default?
};
onPasteNotes = function (event) {
var clipboardData, pastedData;
var e = event.originalEvent;
// // Stop data actually being pasted into div
// e.stopPropagation();
// e.preventDefault();
// Get pasted data via clipboard API
clipboardData = e.clipboardData || window.clipboardData;
pastedData = clipboardData.getData("Text");
//Iterate through the lines looking for the SHareIt name=value lines (they all contain equal signs)
var lines = pastedData.split("\n"); // lines is an array of strings
var purchaseData = {};
// Loop through all lines
for (var j = 0; j < lines.length; j++) {
var thisLine = lines[j];
if (thisLine.includes("=")) {
var thisElement = thisLine.split("=");
purchaseData[thisElement[0].trim()] = thisElement[1].trim();
}
}
//Now have an object with the value pairs in it
if (purchaseData["ShareIt Ref #"]) {
$("#salesOrderNumber").val(purchaseData["ShareIt Ref #"]);
}
// if (purchaseData["E-Mail"]) {
// $("#email").val(purchaseData["E-Mail"]);
// }
};
//-------------------- END EVENT HANDLERS --------------------
//------------------- BEGIN PUBLIC METHODS -------------------
//CONFIGMODULE
//
configModule = function (context) {
stateMap.context = context.context;
if (stateMap.context.params.id) {
stateMap.id = stateMap.context.params.id;
}
};
//INITMODULE
//
initModule = function ($container) {
if (typeof $container === "undefined") {
$container = $("#app-shell-main-content");
}
$container.html(Handlebars.templates["app.purchaseEdit"]({}));
var title = "Purchase";
if (!stateMap.context.params.site_id) {
throw "app.purchaseEdit.js::initModule - There is no stateMap.context.params.site_id!";
}
//Append master record id as a hidden form field for referential integrity
$("<input />")
.attr("type", "hidden")
.attr("name", "siteId")
.attr("value", stateMap.context.params.site_id)
.appendTo("#frm");
//fetch entire site record to get name *and* customer id which is required for redundancy
//RFC - get site name and customer name for form
app.api.get("site/" + stateMap.context.params.site_id, function (res) {
if (res.error) {
$.gevent.publish("app-show-error", res.msg);
} else {
//Also append customer ID redundantly
$("<input />")
.attr("type", "hidden")
.attr("name", "customerId")
.attr("value", res.customerId)
.appendTo("#frm");
title = "Purchase - " + res.name;
if (stateMap.id != "new") {
//fetch existing record
app.api.get("purchase/" + stateMap.id, function (res) {
if (res.error) {
$.gevent.publish("app-show-error", res.msg);
} else {
//fill out form
app.utilB.formData(res);
}
});
} else {
//it's a new record, set default
$("#quantity").val(1);
$("#purchaseDate").val(
new Date().toISOString().substring(0, 10)
);
$("#expireDate").val(
moment().add(1, "years").toISOString().substring(0, 10)
);
$("#vendorName").val("ShareIt");
}
}
});
//Context menu
app.nav.contextClear();
app.nav.contextAddLink(
"purchases/" + stateMap.context.params.site_id,
"Purchases",
"basket"
);
// bind actions
$("#btn-save").bind("click", onSave);
$("#btn-delete").bind("click", onDelete);
$("#btn-renew").bind("click", onRenew);
$("#notes").bind("paste", onPasteNotes);
//Autocomplete
app.utilB.autoComplete("name", "purchase.name");
app.utilB.autoComplete("productCode", "purchase.productCode");
app.utilB.autoComplete("vendorName", "purchase.vendorName");
};
// return public methods
return {
configModule: configModule,
initModule: initModule
};
//------------------- END PUBLIC METHODS ---------------------
})();

View File

@@ -1,88 +1,153 @@
<div>
<form id="frm" method="post" action="index.html">
<div class="row">
<div class="col-sm-6">
<div class="form-group">
<label for="name">Product name</label>
<input class="form-control" type="text" id="name" name="name" value="">
<input
class="form-control"
type="text"
id="name"
name="name"
value=""
/>
</div>
</div>
<div class="col-sm-6">
<div class="form-group">
<label for="productCode">Product code</label>
<input class="form-control" type="text" id="productCode" name="productCode" value="">
</div>
</div>
<div class="col-sm-6">
<div class="form-group">
<label for="quantity">Quantity</label>
<input class="form-control" type="number" id="quantity" name="quantity" value="">
<input
class="form-control"
type="text"
id="productCode"
name="productCode"
value=""
/>
</div>
</div>
<div class="col-sm-6">
<div class="form-group">
<label for="quantity">Quantity</label>
<input
class="form-control"
type="number"
id="quantity"
name="quantity"
value=""
/>
</div>
</div>
<div class="col-sm-6">
<div class="form-group">
<label for="salesOrderNumber">Sales order number</label>
<input class="form-control" type="text" id="salesOrderNumber" name="salesOrderNumber" value="">
<input
class="form-control"
type="text"
id="salesOrderNumber"
name="salesOrderNumber"
value=""
/>
</div>
</div>
<div class="col-sm-6">
<div class="form-group">
<label for="vendorName">Vendor</label>
<input class="form-control" type="text" id="vendorName" name="vendorName" value="">
<input
class="form-control"
type="text"
id="vendorName"
name="vendorName"
value=""
/>
</div>
</div>
<div class="col-sm-6">
<div class="form-group">
<label for="purchaseDate">Purchased</label>
<input class="form-control" type="date" id="purchaseDate" name="purchaseDate" value="">
<input
class="form-control"
type="date"
id="purchaseDate"
name="purchaseDate"
value=""
/>
</div>
</div>
<div class="col-sm-6">
<div class="form-check">
<label class="form-check-label" for="renewNoticeSent">
<input class="form-check-input" type="checkbox" name="renewNoticeSent" id="renewNoticeSent">
Renew notice sent</label>
<input
class="form-check-input"
type="checkbox"
name="renewNoticeSent"
id="renewNoticeSent"
/>
Renew notice sent</label>
</div>
</div>
<div class="col-sm-6">
<div class="form-group">
<label for="expireDate">Subscription expire</label>
<input class="form-control" type="date" id="expireDate" name="expireDate" value="">
<input
class="form-control"
type="date"
id="expireDate"
name="expireDate"
value=""
/>
</div>
</div>
<div class="col-sm-6">
<div class="form-group">
<label for="cancelDate">Cancel date</label>
<input class="form-control" type="date" id="cancelDate" name="cancelDate" value="">
<input
class="form-control"
type="date"
id="cancelDate"
name="cancelDate"
value=""
/>
</div>
</div>
{{!-- <div class="col-sm-6">
{{! <div class="col-sm-6">
<div class="form-group">
<label for="email">Email</label>
<input class="form-control" type="text" id="email" name="email" value="">
</div>
</div> --}}
</div> }}
<div class="col-sm-6">
<div class="form-group">
<label for="couponCode">Coupon code</label>
<input class="form-control" type="text" id="couponCode" name="couponCode" value="">
<input
class="form-control"
type="text"
id="couponCode"
name="couponCode"
value=""
/>
</div>
</div>
<div class="col-sm-12">
<div class="form-group">
<label for="notes">ShareIt Order</label>
<textarea class="form-control" id="notes" name="notes" rows="10"/>
<textarea
class="form-control"
id="notes"
name="notes"
rows="10"
></textarea>
</div>
</div>
</div>
<div class="app-frm-buttons mt-5">
<button id="btn-save" class="btn btn-success">Save</button>
<button id="btn-delete" class="btn btn-outline-dark">Delete</button>
<button id="btn-renew" class="btn btn-outline-primary">Renew</button>
<button
id="btn-renew"
class="btn btn-outline-primary"
>Renew</button>
</div>
</form>
</div>

View File

@@ -1,3 +1,3 @@
<div>
<div>
<ul id="rf-list" class="rf-list" />
</div>

View File

@@ -1,5 +1,5 @@
<div>
<div class="alert alert-success mb-5" id="about"></div>
<div class="alert mb-5" id="about"></div>
<form id="frm" method="post" action="index.html">

View File

@@ -1,7 +1,7 @@
<nav
id="rf-nav"
class="navbar fixed-top navbar-expand-lg navbar-dark"
style="background-color: #6d00b6;"
style="background-color: #1810ff;"
>
{{! navbar-dark bg-success }}
<button
@@ -67,12 +67,12 @@
<a class="rfac nav-link mdi mdi-help" href="https://rfuser:mypasswordforrfuser2022@rockfish.ayanova.com/docs/index.html">Docs </a>
</li>
<li id="rfops" class="nav-item">
{{!-- <li id="rfops" class="nav-item">
<a
class="rfac nav-link mdi mdi-server-network"
href="#!/ops"
>Server Ops </a>
</li>
</li> --}}
<li id="rfsettings" class="nav-item">
<a