First Commit
This commit is contained in:
File diff suppressed because it is too large
Load Diff
597
html/sternwarte/intern/access.php
Executable file
597
html/sternwarte/intern/access.php
Executable file
@@ -0,0 +1,597 @@
|
||||
<?
|
||||
/* *************************************************** *\
|
||||
| |
|
||||
| .htaccess - Generator v2.0 |
|
||||
| |
|
||||
| Copyright <20> 1999-2000 by Alexander Mieland |
|
||||
| Copyright <20> 2000- by APP - Another PHP Programs |
|
||||
| |
|
||||
| Homepage: http://www.php-zentrale.de |
|
||||
| Contact: amieland@php-zentrale.de |
|
||||
| |
|
||||
\* *************************************************** */
|
||||
|
||||
|
||||
$version="v2.0";
|
||||
function error($text) {
|
||||
echo"<table width=\"100%\" border=\"0\" cellspacing=\"0\" cellpadding=\"0\"><tr><td><div align=\"center\"><p><font face=\"Geneva, Arial, Helvetica, san-serif\" size=\"4\" color=\"#FF0000\"><b><font color=\"#FF3300\">ERROR:</font></b></font></p>
|
||||
<p><b><font face=\"Geneva, Arial, Helvetica, san-serif\" size=\"2\" color=\"#333333\">Das Script meldet folgenden Fehler:<br>"<font size=\"3\" color=\"#FF3300\">".$text."</font>" </font></b></p>
|
||||
<p><b><font face=\"Geneva, Arial, Helvetica, san-serif\" size=\"2\" color=\"#333333\"><br>[ - <a href=\"./access.php\">Index</a> - <a href=\"javascript:history.go(-1)\">Zurück</a> - ]</font></b></p><br><br><br>
|
||||
</div></td></tr></table>";
|
||||
}
|
||||
?>
|
||||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"><html><head><title>htaccess-Generator <? echo $version; ?></title><style type="text/css">
|
||||
a:link { color:#0033FF; text-decoration:none; }
|
||||
a:visited { color:#0033FF; text-decoration:none; }
|
||||
a:active { color:#FF3300; text-decoration:none; }
|
||||
a:hover { color:#FF3300; text-decoration:none; }
|
||||
</style></head><body bgcolor="#666666" text="#333333" link="#0033FF" vlink="#0033CC" alink="#FF3300" topmargin="30"><br><br><br><table width="550" border="1" cellspacing="0" cellpadding="0" align="center" bgcolor="#FFFFFF">
|
||||
<tr><td><table width="100%" border="0" cellspacing="0" cellpadding="0"><tr bgcolor="#CCCCCC"><td width="2%" height="31"> </td><td width="96%" height="31" bgcolor="#CCCCCC">
|
||||
<div align="center"><font face="Geneva, Arial, Helvetica, san-serif" size="3" color="#666666"><b><font size="4">DMA`s <font color="#FF3300">htaccess</font>-Generator <? echo $version; ?></font></b></font></div>
|
||||
</td><td width="2%" height="31"> </td></tr><tr><td width="2%" bgcolor="#CCCCCC"> </td><td width="96%"> <font face="Geneva, Arial, Helvetica, san-serif" size="1" color="#333333">
|
||||
<br>Script zum erstellen eines kompletten, passwortgeschützen Bereichs auf dem Server.<br><font color="#FF3300"><b><li>Das Verzeichnis, welches geschützt werden soll, MUSS chmod 777 haben!
|
||||
<li>Dieses Script muss IN dem, zu schützenden Verzeichnis liegen!<br><br><br><br></b></font></font></td><td width="2%" bgcolor="#CCCCCC"> </td></tr><tr><td width="2%" bgcolor="#CCCCCC"> </td><td width="96%">
|
||||
<?
|
||||
if (!isset($auswahl)):
|
||||
?>
|
||||
<div align="center"> <font face="Geneva, Arial, Helvetica, san-serif" size="2" color="#666666"><b>
|
||||
<font size="3" color="#FF3300">htaccess</font><font size="3">-Menü</font><br>
|
||||
<br>
|
||||
</b></font>
|
||||
<table width="100%" border="0" cellspacing="0" cellpadding="0">
|
||||
<tr>
|
||||
<td width="50%">
|
||||
<div align="right"><font face="Geneva, Arial, Helvetica, san-serif" size="2" color="#333333"><b><a href="./access.php?auswahl=neu">Neuen
|
||||
Admin-Bereich erstellen</a> </b></font></div>
|
||||
</td>
|
||||
<td width="50%">
|
||||
<div align="left"><font face="Geneva, Arial, Helvetica, san-serif" size="2" color="#333333"><b> <a href="./access.php?auswahl=change">Einen
|
||||
Admin-Bereich ändern</a></b></font></div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="50%">
|
||||
<div align="right"><font face="Geneva, Arial, Helvetica, san-serif" size="2" color="#333333"><b> </b></font></div>
|
||||
</td>
|
||||
<td width="50%">
|
||||
<div align="left"><font face="Geneva, Arial, Helvetica, san-serif" size="2" color="#333333"><b> </b></font></div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="50%">
|
||||
<div align="right"><font face="Geneva, Arial, Helvetica, san-serif" size="2" color="#333333"><b><a href="./access.php?auswahl=open">Einen
|
||||
Admin-Bereich wieder öffnen</a> </b></font></div>
|
||||
</td>
|
||||
<td width="50%">
|
||||
<div align="left"><font face="Geneva, Arial, Helvetica, san-serif" size="2" color="#333333"><b> <a href="http://www.php-zentrale.de">Zur
|
||||
Homepage des Generators</a></b></font></div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="50%">
|
||||
<div align="right"><font face="Geneva, Arial, Helvetica, san-serif" size="2" color="#333333"><b> </b></font></div>
|
||||
</td>
|
||||
<td width="50%">
|
||||
<div align="left"><font face="Geneva, Arial, Helvetica, san-serif" size="2" color="#333333"><b> </b></font></div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="50%">
|
||||
<div align="right"><font face="Geneva, Arial, Helvetica, san-serif" size="2" color="#333333"><b><a href="mailto:amieland@php-zentrale.de?subject=Mail%20aus%20dem%20Generator%20heraus">Dem
|
||||
Autor eine eMail schicken</a> </b></font></div>
|
||||
</td>
|
||||
<td width="50%">
|
||||
<div align="left"><font face="Geneva, Arial, Helvetica, san-serif" size="2" color="#333333"><b> <a href="http://www.php-zentrale.de/index.php?site=htaccessgenerator">Die
|
||||
neueste Version downloaden</a></b></font></div>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<br>
|
||||
<br>
|
||||
<br>
|
||||
<font face="Geneva, Arial, Helvetica, san-serif" size="2" color="#666666"><b>
|
||||
</b> </font> </div>
|
||||
<?
|
||||
elseif ($auswahl == "neu"):
|
||||
if (!isset($user)):
|
||||
?>
|
||||
<br>
|
||||
<div align="center"> <font face="Geneva, Arial, Helvetica, san-serif" size="2" color="#666666"><b>
|
||||
<font size="4" color="#FF3300">Neuen Bereich anlegen</font></b></font><font face="Geneva, Arial, Helvetica, san-serif" size="2" color="#666666">
|
||||
<br>
|
||||
<br>
|
||||
<br>
|
||||
<br>
|
||||
<a href="./access.php?auswahl=neu&user=1">Bereich mit nur einem User anlegen</a><br>
|
||||
<br>
|
||||
<a href="./access.php?auswahl=neu&user=2">Bereich mit mehreren Usern anlegen</a><br>
|
||||
<br>
|
||||
<br>
|
||||
<br>
|
||||
[ - <a href="./access.php">index</a> - ]</font>
|
||||
<br>
|
||||
<br>
|
||||
<br>
|
||||
</div>
|
||||
<?
|
||||
elseif ($user == "1"):
|
||||
if (!isset($save)):
|
||||
?>
|
||||
<form method="post" action="./access.php" name="send">
|
||||
<center>
|
||||
<font face="Geneva, Arial, Helvetica, san-serif" size="2" color="#666666"><b>
|
||||
<div align="center"><br>
|
||||
Neuen Admin-Bereich erstellen </div>
|
||||
</b></font>
|
||||
</center>
|
||||
<div align="center"><font face="Geneva, Arial, Helvetica, san-serif" size="2" color="#666666"><b><br>
|
||||
<br>
|
||||
Vergib einen Namen f<>r den Bereich (max. 30 Zeichen):<br>
|
||||
<input type="text" name="realm" maxsize=30>
|
||||
<br>
|
||||
<br>
|
||||
Gib den Usernamen ein:<br>
|
||||
<input type="text" name="name">
|
||||
<br>
|
||||
<br>
|
||||
Gib das Passwort zweimal ein:<br>
|
||||
<input type="password" name="pwd1">
|
||||
<br>
|
||||
<input type="password" name="pwd2">
|
||||
<input type="hidden" name="save" value="yes">
|
||||
<input type="hidden" name="user" value="1">
|
||||
<input type="hidden" name="auswahl" value="neu">
|
||||
<br>
|
||||
<br>
|
||||
<input type="submit" name="submit" value="speichern">
|
||||
</b></font></div>
|
||||
<font face="Geneva, Arial, Helvetica, san-serif" size="2" color="#666666"><b>
|
||||
</b></font>
|
||||
</form>
|
||||
<?php
|
||||
elseif ($save == "yes"):
|
||||
if ($name == "" || $name == " " || $pwd1 == "" || $pwd2 == "")
|
||||
{
|
||||
error("Da fehlt doch was???!!!");
|
||||
} else {
|
||||
if ($pwd1 == $pwd2) {
|
||||
$passwd = crypt($pwd2, 'rl');
|
||||
$inhalt = $name.":".$passwd;
|
||||
$i=1;
|
||||
while(!$pwfile) {
|
||||
if(file_exists("./.htpasswd0$i")) $i++;
|
||||
else $pwfile=".htpasswd0$i";
|
||||
}
|
||||
$wf = fopen ("./".$pwfile, "w+");
|
||||
if(!fwrite ($wf,$inhalt)) error($pwfile." konnte nicht geschrieben werden! Bitte das Verzeichnis auf 777 chmoden! (Info in wichtig.txt!)");
|
||||
fclose ($wf);
|
||||
$path = $SCRIPT_FILENAME;
|
||||
$path = ereg_replace('/access.php', '', $path);
|
||||
$htaccessinhalt = "AuthType Basic\nAuthName \"".$realm." - found at: http://www.php-zentrale.de\"\nAuthUserFile ".$path."/".$pwfile."\nrequire valid-user";
|
||||
$wf = fopen ("./.htaccess", "w+");
|
||||
if(!fwrite ($wf,$htaccessinhalt)) error(".htaccess konnte nicht geschrieben werden! Bitte das Verzeichnis auf 777 chmoden! (Info in wichtig.txt!)");
|
||||
fclose ($wf);
|
||||
echo "<br><br><p><font color=#FF3300>Die .htpasswd wurde mit folgendem Inhalt gespeichert:</font><br>".$inhalt."</p>
|
||||
<font color=#FF3300>Die .htaccess wurde mit folgendem Inhalt gespeichert:</font><br><pre>".$htaccessinhalt."</pre></p><br>
|
||||
<hr><br>
|
||||
Denken Sie daran, dass man versteckte Dateien auf einem Server mit einem FTP-Programm manchmal nicht sieht!<br>
|
||||
Da die Datei ".htpasswd" eine versteckte Datei ist (in Unix ist alles, mit Punkt vorne, versteckt),
|
||||
Kann es sein, dass sie sie nicht sehen. Sie k<>nnen sie sich aber dennoch runterladen, indem sie in die FTP-Console
|
||||
Ihres FTP-Clients folgendes eingeben: get .htpasswd<br><br></font>";
|
||||
} else {
|
||||
echo "<br><br><br>";
|
||||
error("Die beiden Passwort-Eingaben unterscheiden sich voneinander!");
|
||||
}
|
||||
}
|
||||
endif;
|
||||
?>
|
||||
<font face="Geneva, Arial, Helvetica, san-serif" size="1" color="#666666"><center><br>
|
||||
<br>
|
||||
[ - <a href="./access.php">Index</a> - ]<br>
|
||||
</center>
|
||||
</font><br>
|
||||
<?
|
||||
elseif ($user == "2"):
|
||||
if (!isset($save)):
|
||||
?>
|
||||
<form method="post" action="./access.php" name="send">
|
||||
<center>
|
||||
<font face="Geneva, Arial, Helvetica, san-serif" size="2" color="#666666"><b>
|
||||
<div align="center"><br>
|
||||
Neuen Admin-Bereich erstellen </div>
|
||||
</b></font>
|
||||
</center>
|
||||
<div align="center"><font face="Geneva, Arial, Helvetica, san-serif" size="2" color="#666666"><b><br>
|
||||
<br>
|
||||
Vergib einen Namen f<>r den Bereich (max. 30 Zeichen):<br>
|
||||
<input type="text" name="realm" maxsize=30>
|
||||
<br>
|
||||
<br>
|
||||
Gib den 1. Usernamen ein:<br>
|
||||
<input type="text" name="name">
|
||||
<br>
|
||||
<br>
|
||||
Gib das 1. Passwort zweimal ein:<br>
|
||||
<input type="password" name="pwd1">
|
||||
<br>
|
||||
<input type="password" name="pwd2">
|
||||
<input type="hidden" name="save" value="no">
|
||||
<input type="hidden" name="user" value="2">
|
||||
<input type="hidden" name="auswahl" value="neu">
|
||||
<br>
|
||||
<br>
|
||||
<input type="submit" name="submit" value="speichern">
|
||||
</b></font></div>
|
||||
<font face="Geneva, Arial, Helvetica, san-serif" size="2" color="#666666"><b>
|
||||
</b></font>
|
||||
</form>
|
||||
<?php
|
||||
elseif ($save == "no"):
|
||||
if ($submit == "speichern" || $submit == "weitere User"):
|
||||
if ($name == "" || $name == " " || $pwd1 == "" || $pwd2 == "")
|
||||
{
|
||||
error("Da fehlt doch was???!!!");
|
||||
} else {
|
||||
if ($pwd1 == $pwd2) {
|
||||
$passwd = crypt($pwd2);
|
||||
$inhalt1 .= $name.":".$passwd."\n";
|
||||
?>
|
||||
<form method="post" action="./access.php" name="send">
|
||||
<center>
|
||||
<font face="Geneva, Arial, Helvetica, san-serif" size="2" color="#666666"><b>
|
||||
<div align="center"><br>
|
||||
Weitere User</div>
|
||||
</b></font>
|
||||
</center>
|
||||
<div align="center"><font face="Geneva, Arial, Helvetica, san-serif" size="2" color="#666666"><b><br>
|
||||
<br>
|
||||
Gib den n<>chsten Usernamen ein:<br>
|
||||
<input type="text" name="name">
|
||||
<br>
|
||||
<br>
|
||||
Gib das n<>chste Passwort zweimal ein:<br>
|
||||
<input type="password" name="pwd1">
|
||||
<br>
|
||||
<input type="password" name="pwd2">
|
||||
<input type="hidden" name="save" value="no">
|
||||
<input type="hidden" name="user" value="2">
|
||||
<input type="hidden" name="auswahl" value="neu">
|
||||
<input type="hidden" name="inhalt1" value="<? echo $inhalt1; ?>">
|
||||
<input type="hidden" name="realm" value="<? echo $realm; ?>">
|
||||
<br>
|
||||
<br>
|
||||
<input type="submit" name="submit" value="weitere User">
|
||||
<input type="submit" name="submit" value="endg<64>ltig speichern">
|
||||
</b></font></div>
|
||||
<font face="Geneva, Arial, Helvetica, san-serif" size="2" color="#666666"><b>
|
||||
</b></font>
|
||||
</form>
|
||||
<?php
|
||||
} else {
|
||||
echo "<br><br><br>";
|
||||
error("Die beiden Passwort-Eingaben unterscheiden sich voneinander!");
|
||||
}
|
||||
}
|
||||
elseif ($submit == "endg<64>ltig speichern"):
|
||||
if ($name == "" || $name == " " || $pwd1 == "" || $pwd2 == "")
|
||||
{
|
||||
error("Da fehlt doch was???!!!");
|
||||
} else {
|
||||
if ($pwd1 == $pwd2) {
|
||||
$passwd = crypt($pwd2);
|
||||
$inhalt1 .= $name.":".$passwd."\n";
|
||||
$i=1;
|
||||
while(!$pwfile) {
|
||||
if(file_exists("./.htpasswd0$i")) $i++;
|
||||
else $pwfile=".htpasswd0$i";
|
||||
}
|
||||
$wf = fopen ("./".$pwfile, "w+");
|
||||
if(!fwrite ($wf,$inhalt1)) error($pwfile." konnte nicht geschrieben werden! Bitte das Verzeichnis auf 777 chmoden! (Info in wichtig.txt!)");
|
||||
fclose ($wf);
|
||||
$path = $SCRIPT_FILENAME;
|
||||
$path = ereg_replace('/access.php', '', $path);
|
||||
$htaccessinhalt = "AuthType Basic\nAuthName \"".$realm." - found at: http://www.php-zentrale.de\"\nAuthUserFile ".$path."/".$pwfile."\nrequire valid-user";
|
||||
$wf = fopen ("./.htaccess", "w+");
|
||||
if(!fwrite ($wf,$htaccessinhalt)) error(".htaccess konnte nicht geschrieben werden! Bitte das Verzeichnis auf 777 chmoden! (Info in wichtig.txt!)");
|
||||
fclose ($wf);
|
||||
$inhalt2 = str_replace("\n", "<br>", $inhalt1);
|
||||
echo "<br><br><p><font color=#FF3300>Die .htpasswd wurde mit folgendem Inhalt gespeichert:</font><br>".$inhalt2."</p>
|
||||
<font color=#FF3300>Die .htaccess wurde mit folgendem Inhalt gespeichert:</font><br><pre>".$htaccessinhalt."</pre></p><br>
|
||||
<hr><br>
|
||||
Denken Sie daran, dass man versteckte Dateien auf einem Server mit einem FTP-Programm manchmal nicht sieht!<br>
|
||||
Da die Datei ".htpasswd" eine versteckte Datei ist (in Unix ist alles, mit Punkt vorne, versteckt),
|
||||
Kann es sein, dass sie sie nicht sehen. Sie k<>nnen sie sich aber dennoch runterladen, indem sie in die FTP-Console
|
||||
Ihres FTP-Clients folgendes eingeben: get .htpasswd<br><br></font>";
|
||||
} else {
|
||||
echo "<br><br><br>";
|
||||
error("Die beiden Passwort-Eingaben unterscheiden sich voneinander!");
|
||||
}
|
||||
}
|
||||
endif;
|
||||
endif;
|
||||
?>
|
||||
<font face="Geneva, Arial, Helvetica, san-serif" size="1" color="#666666"><center><br>
|
||||
<br>
|
||||
[ - <a href="./access.php">Index</a> - ]<br>
|
||||
</center>
|
||||
</font><br>
|
||||
<?
|
||||
endif;
|
||||
elseif ($auswahl == "change"):
|
||||
if ($what == "" OR !isset($what)):
|
||||
?>
|
||||
<div align="center"> <font face="Geneva, Arial, Helvetica, san-serif" size="2" color="#666666"><b>
|
||||
<font size="3" color="#FF3300">htaccess</font><font size="3">-Menü</font><br>
|
||||
<br>
|
||||
</b></font>
|
||||
<table width="100%" border="0" cellspacing="0" cellpadding="0">
|
||||
<tr><td align="center"><b><font face="Geneva, Arial, Helvetica, san-serif" size="2"><a href="./access.php?what=erweitern&auswahl=change" target="_top">Hinzuf<75>gen/L<>schen von Usern</a></font></b></td></tr>
|
||||
<tr><td align="center"> </td></tr>
|
||||
<tr><td align="center"><b><font face="Geneva, Arial, Helvetica, san-serif" size="2"><a href="./access.php?what=aendern&auswahl=change" target="_top">Direktes Ändern der .ht****-Dateien</a></font></b></td></tr>
|
||||
</table>
|
||||
<br>
|
||||
<font face="Geneva, Arial, Helvetica, san-serif" size="2">
|
||||
<br>
|
||||
[ - <a href="./access.php">index</a> - ]
|
||||
</font>
|
||||
<br>
|
||||
<br>
|
||||
</div>
|
||||
<?php
|
||||
elseif ($what == "aendern"):
|
||||
?>
|
||||
<br>
|
||||
<div align="center"> <font face="Geneva, Arial, Helvetica, san-serif" size="2" color="#666666"><b>
|
||||
<font size="3">Admin-Bereich <20>ndern</font><br>
|
||||
<font size="2" color="#333333"><br>
|
||||
<font color=#ff0000><b>VORSICHT!</b><br>
|
||||
Dies sollten nur Leute machen, die auch wirklich wissen, was sie tun!<br><br></font>
|
||||
<br>
|
||||
<?
|
||||
if (!isset($pwdatei)):
|
||||
?>
|
||||
<form method=post action=access.php>
|
||||
Folgende Datei <20>ndern:<br>
|
||||
<?
|
||||
echo "<select name=pwdatei>";
|
||||
$handle=opendir('.');
|
||||
while ($file = readdir ($handle)) {
|
||||
if ($file == ".htaccess" || eregi(".htpasswd", $file)) {
|
||||
echo "<option>".$file."</option>";
|
||||
}
|
||||
}
|
||||
closedir($handle);
|
||||
echo "</select>";
|
||||
?>
|
||||
<br><br>
|
||||
<input type="hidden" name="auswahl" value="change">
|
||||
<input type="hidden" name="what" value="aendern">
|
||||
<input type="submit" name="submit" value="<22>ndern">
|
||||
<input type="submit" name="submit" value="l<>schen">
|
||||
</form>
|
||||
<?
|
||||
elseif (isset($pwdatei)):
|
||||
if ($submit == "<22>ndern"):
|
||||
if (!isset($save)):
|
||||
?>
|
||||
<form method=post action=access.php>
|
||||
Folgende Datei <20>ndern:<br>
|
||||
<?
|
||||
echo $pwdatei."<br>";
|
||||
$fp = fopen ("./".$pwdatei, "r");
|
||||
$inhalt = fread ($fp, filesize("./".$pwdatei));
|
||||
echo "<TEXTAREA NAME=\"inhalt\" cols=\"60\" rows=\"14\">".$inhalt."</TEXTAREA>";
|
||||
fclose ($fp);
|
||||
?>
|
||||
<br><br>
|
||||
<input type="hidden" name="pwdatei" value="<? echo $pwdatei; ?>">
|
||||
<input type="hidden" name="save" value="1">
|
||||
<input type="hidden" name="what" value="aendern">
|
||||
<input type="hidden" name="auswahl" value="change">
|
||||
<input type="submit" name="submit" value="Datei speichern">
|
||||
</form>
|
||||
<?
|
||||
elseif ($save == "1"):
|
||||
$fp = fopen ("./".$pwdatei, "w+");
|
||||
if (!fwrite ($fp, $inhalt)) {
|
||||
error ("Datei konnte nicht geschrieben werden!");
|
||||
} else {
|
||||
echo"<b>Datei erfolgreich gespeichert!</b><br>[ - <a href=access.php>Index</a> - ]<br>";
|
||||
}
|
||||
fclose ($fp);
|
||||
endif;
|
||||
elseif ($submit == "l<>schen"):
|
||||
if (!isset($del)):
|
||||
echo "Die Datei ".$pwdatei." wirklich l<>schen?<br><br>";
|
||||
echo "[ - <a href=\"./access.php?what=aendern&auswahl=change&pwdatei=".$pwdatei."&submit=l<>schen&del=JA\">JA</a> - <a href=\"./access.php\">NEIN!</a> - ]";
|
||||
elseif ($del == "JA"):
|
||||
if(file_exists("./".$pwdatei)) {
|
||||
if (!unlink("./".$pwdatei)) {
|
||||
error($pwdatei." konnte nicht gel<65>scht werden! Bitte manuell, per FTP l<>schen.");
|
||||
} else {
|
||||
echo "<br>Datei ".$pwdatei." wurde erfolgreich gel<65>scht!<br>[<a href=access.php>Index</a>]<br><br>";
|
||||
}
|
||||
} else {
|
||||
error("Diese Datei ist nicht vorhanden!!??");
|
||||
}
|
||||
endif;
|
||||
endif;
|
||||
endif;
|
||||
?>
|
||||
<br><br>
|
||||
</font></b> </font> <font face="Geneva, Arial, Helvetica, san-serif" size="1" color="#666666"><br>
|
||||
[ - <a href="javascript:history.go(-1)">zurück</a> - ]<br>
|
||||
<br>
|
||||
<br>
|
||||
<br>
|
||||
<b> </b> </font> </div>
|
||||
<?
|
||||
elseif ($what == "erweitern"):
|
||||
if (!isset($del)):
|
||||
?>
|
||||
<div align="center"><b>
|
||||
</b>
|
||||
<table width="100%" border="0" cellspacing="0" cellpadding="0">
|
||||
<tr><td align="center"><font face="Geneva, Arial, Helvetica, san-serif" size="2">
|
||||
<?
|
||||
if (file_exists(".htaccess"))
|
||||
{
|
||||
$content = file(".htaccess");
|
||||
$passwdfile = explode (" ", $content[2]);
|
||||
$passwdfile = trim($passwdfile[1]);
|
||||
unset($content);
|
||||
if (file_exists($passwdfile))
|
||||
{
|
||||
if (isset($action) AND $action == "add")
|
||||
{
|
||||
$thisnew_content = "".$thisnewcontent.$newuser.":".crypt($newpasswd);
|
||||
$fp = fopen($passwdfile, "w+");
|
||||
fwrite($fp, $thisnew_content);
|
||||
fclose($fp);
|
||||
}
|
||||
$content = file($passwdfile);
|
||||
echo "<table width=\"55%\" align=\"center\" border=\"0\" cellspacing=\"0\" cellpadding=\"0\">";
|
||||
echo "<tr><td><b><font face=\"Geneva, Arial, Helvetica, san-serif\" size=\"2\">Einen der folgenden User l<>schen?</font></b></td></tr>";
|
||||
echo "<tr><td><b><font face=\"Geneva, Arial, Helvetica, san-serif\" size=\"2\"> </font></b></td></tr>";
|
||||
$thisnewcontent = "";
|
||||
for ( $a=0; $a < count($content); $a++ )
|
||||
{
|
||||
$user1 = explode(":", $content[$a]);
|
||||
$user = $user1[0];
|
||||
unset($user1);
|
||||
$b = $a + 1;
|
||||
echo "<tr><td><b><font face=\"Geneva, Arial, Helvetica, san-serif\" size=\"2\">$b. <a href=\"./access.php?what=erweitern&del=$user&auswahl=change\">$user</a></font></b></td></tr>";
|
||||
$thisnewcontent .= $content[$a];
|
||||
}
|
||||
echo "<tr><td><b><font face=\"Geneva, Arial, Helvetica, san-serif\" size=\"2\"> </font></b></td></tr>";
|
||||
echo "<tr><td><b><font face=\"Geneva, Arial, Helvetica, san-serif\" size=\"2\"><b><font color=\"#FF0000\">Achtung:</font> Es gibt keine Sicherheitsabfrage!</b></font></b></td></tr>";
|
||||
echo "<tr><td><b><font face=\"Geneva, Arial, Helvetica, san-serif\" size=\"2\"> </font></b></td></tr>";
|
||||
echo "<tr><td><b><font face=\"Geneva, Arial, Helvetica, san-serif\" size=\"2\"> </font></b></td></tr>";
|
||||
echo "<tr><td><b><font face=\"Geneva, Arial, Helvetica, san-serif\" size=\"2\">Einen neuen User hinzufügen?</font></b></td></tr>";
|
||||
echo "<tr><td><b><font face=\"Geneva, Arial, Helvetica, san-serif\" size=\"2\"> </font></b></td></tr>";
|
||||
echo "<tr><td><b><font face=\"Geneva, Arial, Helvetica, san-serif\" size=\"2\">";
|
||||
echo "<form action=\"\" method=\"post\">";
|
||||
echo "<center><b><font face=\"Geneva, Arial, Helvetica, san-serif\" size=\"2\">";
|
||||
echo "Gib einen Usernamen ein:<br>";
|
||||
echo "<input type=\"text\" name=\"newuser\"><br>";
|
||||
echo "<br>Gib ein Passwort ein:<br>";
|
||||
echo "<input type=\"password\" name=\"newpasswd\"><br>";
|
||||
echo "<input type=\"hidden\" name=\"what\" value=\"erweitern\">";
|
||||
echo "<input type=\"hidden\" name=\"auswahl\" value=\"change\">";
|
||||
echo "<input type=\"hidden\" name=\"action\" value=\"add\">";
|
||||
echo "<input type=\"hidden\" name=\"thisnewcontent\" value=\"".$thisnewcontent."\">";
|
||||
echo "<br><input type=\"submit\" name=\"submit\" value=\"speichern\">";
|
||||
echo "</font></b></center></form>";
|
||||
echo "</font></b></td></tr>";
|
||||
echo "</table>";
|
||||
}
|
||||
else
|
||||
{
|
||||
error("Es wurde keine Passwort-Datei gefunden.");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
error("Es wurde keine .htaccess-Datei gefunden.");
|
||||
}
|
||||
?>
|
||||
</font></td></tr>
|
||||
</table>
|
||||
<br>
|
||||
<font face="Geneva, Arial, Helvetica, san-serif" size="2">
|
||||
<br>
|
||||
[ - <a href="./access.php">index</a> - ]
|
||||
</font>
|
||||
<br>
|
||||
<br>
|
||||
</div>
|
||||
<?
|
||||
elseif (trim($del) != ""):
|
||||
?>
|
||||
<div align="center"><b>
|
||||
</b>
|
||||
<table width="100%" border="0" cellspacing="0" cellpadding="0">
|
||||
<tr><td align="center"><font face="Geneva, Arial, Helvetica, san-serif" size="2">
|
||||
<?
|
||||
if (file_exists(".htaccess"))
|
||||
{
|
||||
$content = file(".htaccess");
|
||||
$passwdfile = explode (" ", $content[2]);
|
||||
$passwdfile = trim($passwdfile[1]);
|
||||
unset($content);
|
||||
if (file_exists($passwdfile))
|
||||
{
|
||||
$content = file($passwdfile);
|
||||
$new_content = "";
|
||||
for ( $a=0; $a < count($content); $a++ )
|
||||
{
|
||||
$user1 = explode(":", $content[$a]);
|
||||
$user = $user1[0];
|
||||
unset($user1);
|
||||
if ($user != $del)
|
||||
{
|
||||
$new_content .= $content[$a];
|
||||
}
|
||||
}
|
||||
$fp = fopen($passwdfile, "w+");
|
||||
fwrite($fp, $new_content);
|
||||
fclose($fp);
|
||||
echo "<b>Der User "$del" wurde gelöscht.</b>";
|
||||
}
|
||||
else
|
||||
{
|
||||
error("Es wurde keine Passwort-Datei gefunden.");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
error("Es wurde keine .htaccess-Datei gefunden.");
|
||||
}
|
||||
?>
|
||||
</font></td></tr>
|
||||
</table>
|
||||
<br>
|
||||
<font face="Geneva, Arial, Helvetica, san-serif" size="2">
|
||||
<br>
|
||||
[ - <a href="./access.php">index</a> - ]
|
||||
</font>
|
||||
<br>
|
||||
<br>
|
||||
</div>
|
||||
<?
|
||||
endif;
|
||||
endif;
|
||||
elseif ($auswahl == "open"):
|
||||
?>
|
||||
<br>
|
||||
<div align="center"> <font face="Geneva, Arial, Helvetica, san-serif" size="2" color="#666666"><b>
|
||||
<font size="3">Admin-Bereich wieder <20>ffnen</font><br>
|
||||
<font size="2" color="#333333"><br>
|
||||
<?
|
||||
if (!isset($del)):
|
||||
echo "Den gesch<63>tzen Bereich wirklich wieder f<>r alle freigeben?<br>(Datei .htaccess wirklich l<>schen?)<br><br>";
|
||||
echo "[ - <a href=\"./access.php?auswahl=open&del=JA\">JA</a> - <a href=\"./access.php\">NEIN!</a> - ]";
|
||||
elseif ($del == "JA"):
|
||||
if(file_exists("./.htaccess")) {
|
||||
if (!unlink("./.htaccess")) {
|
||||
error(".htaccess konnte nicht gel<65>scht werden! Bitte manuell, per FTP l<>schen.");
|
||||
} else {
|
||||
echo "<br>Datei .htaccess wurde erfolgreich gel<65>scht!<br>[<a href=access.php>Index</a>]<br><br>";
|
||||
}
|
||||
} else {
|
||||
error("Keine .htaccess - Datei zum l<>schen vorhanden!!??");
|
||||
}
|
||||
endif;
|
||||
?>
|
||||
<br>
|
||||
</font></b> </font> <font face="Geneva, Arial, Helvetica, san-serif" size="1" color="#666666"><br>
|
||||
[ - <a href="javascript:history.go(-1)">zurück</a> - ]<br>
|
||||
<br>
|
||||
<br>
|
||||
<br>
|
||||
<b> </b> </font> </div>
|
||||
<?
|
||||
endif;
|
||||
?>
|
||||
</td><td width="2%" bgcolor="#CCCCCC"> </td></tr><tr bgcolor="#CCCCCC"><td width="2%"> </td><td width="96%"><div align="right"><font face="Geneva, Arial, Helvetica, san-serif" size="1" color="#666666"><br>
|
||||
<font color="#FF3300">htaccess</font>-Generator Copyright © 2000+2001 by <a href="http://www.php-zentrale.de">APP - Another PHP Programs</a></font></div></td><td width="2%"> </td></tr></table></td></tr></table></body></html>
|
||||
67
html/sternwarte/intern/anleitungen.php
Executable file
67
html/sternwarte/intern/anleitungen.php
Executable file
@@ -0,0 +1,67 @@
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
||||
<html xmlns="http://www.w3.org/1999/xhtml">
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
||||
<title>Sternwarte Welzheim</title>
|
||||
<!--[if IE 5]>
|
||||
<link href="css/ie5.css" rel="stylesheet" type="text/css" />
|
||||
<![endif]--><!--[if IE]>
|
||||
<style type="text/css">
|
||||
<link href="css/ie.css" rel="stylesheet" type="text/css" />
|
||||
</style>
|
||||
<![endif]-->
|
||||
<link href="../css/sternwarte1.css" rel="stylesheet" type="text/css" />
|
||||
</head>
|
||||
|
||||
<body class="thrColFixHdr">
|
||||
|
||||
<div id="container">
|
||||
<div id="header"><img src="../bilder/header1.jpg" width="960" height="150" alt="Sternwarte Welzheim"/><!-- end #header --></div>
|
||||
<?php include '../navi.php'; ?>
|
||||
<div id="sidebar2">
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
<div id="mainContent">
|
||||
|
||||
<h1>Anleitungen</h1>
|
||||
<table width="450px"><tr style="font-weight: bold;"><td>Anleitung</td> <td>Download</td> </tr>
|
||||
<?php
|
||||
foreach(glob("../Anleitungen/*.pdf") as $filename) {
|
||||
$index = strpos($filename,"_");
|
||||
$name = substr($filename,15, $index-15);
|
||||
echo "<tr><td>$name</td><td><a href='$filename'>pdf</a></td> </tr> ";
|
||||
}
|
||||
echo "<tr><td>Wireguard (VPN)</td><td><a href='./download/Wireguard/Wireguard.pdf'>pdf</a></td> </tr> ";
|
||||
echo "<tr><td>Sternwarte.conf</td><td><a href='./download/Wireguard/Sternwarte.conf' download>conf</a></td> </tr> ";
|
||||
echo "<tr><td></td><td></td> </tr> ";
|
||||
echo "<tr><td>10micron Gebrauchsanleitung</td><td><a href='./download/GM4000HPS-II_3.1-DE.pdf' download>pdf</a></td> </tr> ";
|
||||
echo "<tr><td>10micron Schnellanleitung</td><td><a href='./download/D_HPS_Schnellstart-Anleitung_A5_RGB_LR_0517.pdf' download>pdf</a></td> </tr> ";
|
||||
?>
|
||||
|
||||
<?php include '../config_stern.php';
|
||||
|
||||
# $sql_selkat="SELECT id, jahr, monat, name, datum FROM beoprotokolle order by name DESC" ;
|
||||
|
||||
# $sel=mysqli_query($db,"$sql_selkat");
|
||||
# if ($sel)
|
||||
# {
|
||||
# #Kategorie aus der Datenbank holen --------------------------------------------------
|
||||
# while($row=mysqli_fetch_row($sel))
|
||||
# {
|
||||
#
|
||||
# echo "<tr><td>$row[2] $row[1]</td> <td>$row[4]</td><td><a href='pdf_beo/$row[3]'>pdf</a></td> </tr> ";
|
||||
#
|
||||
# }
|
||||
# }
|
||||
?>
|
||||
|
||||
</table>
|
||||
</p>
|
||||
<!-- end #mainContent --></div>
|
||||
<!-- Dieses clear-Element sollte direkt auf das #mainContent-div folgen, um das #container-div anzuweisen, alle untergeordneten Floats aufzunehmen. --><br class="clearfloat" />
|
||||
|
||||
<!-- end #container --></div>
|
||||
</body>
|
||||
</html>
|
||||
16
html/sternwarte/intern/anmeld/.vscode/launch.json
vendored
Normal file
16
html/sternwarte/intern/anmeld/.vscode/launch.json
vendored
Normal file
@@ -0,0 +1,16 @@
|
||||
{
|
||||
// Verwendet IntelliSense zum Ermitteln möglicher Attribute.
|
||||
// Zeigen Sie auf vorhandene Attribute, um die zugehörigen Beschreibungen anzuzeigen.
|
||||
// Weitere Informationen finden Sie unter https://go.microsoft.com/fwlink/?linkid=830387
|
||||
"version": "0.2.0",
|
||||
"configurations": [
|
||||
{
|
||||
"name": "Python: Aktuelle Datei",
|
||||
"type": "python",
|
||||
"request": "launch",
|
||||
"program": "${file}",
|
||||
"console": "integratedTerminal",
|
||||
"env":{"STWANMELD": "1"}
|
||||
}
|
||||
]
|
||||
}
|
||||
88
html/sternwarte/intern/anmeld/anmeld.php
Normal file
88
html/sternwarte/intern/anmeld/anmeld.php
Normal file
@@ -0,0 +1,88 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1"/>
|
||||
<title>Anmeldungen</title>
|
||||
<link rel="stylesheet" type="text/css" media="screen" href="css/bootstrap.min.css"/>
|
||||
<link rel="stylesheet" type="text/css" media="screen" href="../sofue/css/jquery-ui.min.css"/>
|
||||
<link rel="stylesheet" type="text/css" media="screen" href="../sofue/css/ui.jqgrid.css"/>
|
||||
<link rel="stylesheet" type="text/css" media="screen" href="../sofue/css/jquery-ui-timepicker-addon.css"/>
|
||||
<link rel="stylesheet" type="text/css" media="screen" href="css/anmeld.css"/>
|
||||
<script type="text/javascript" src="../sofue/js/jquery-1.11.0.min.js"></script>
|
||||
<script type="text/javascript" src="../sofue/js/i18n/grid.locale-de.js"></script>
|
||||
<script type="text/javascript" src="../sofue/js/jquery.jqGrid.min.js"></script>
|
||||
<script type="text/javascript" src="../sofue/js/jquery-ui-1.10.0.custom.min.js"></script>
|
||||
<script type="text/javascript" src="../sofue/js/jquery-ui-timepicker-addon.js"></script>
|
||||
<script type="text/javascript" src="../sofue/js/moment.js"></script>
|
||||
<script type="text/javascript" src="../sofue/js/de.js"></script>
|
||||
<script type="text/javascript" src="../sofue/js/ajax.js"></script>
|
||||
<script type="text/javascript" src="js/version.js"></script>
|
||||
<script type="text/javascript" src="js/anmeld.js"></script>
|
||||
</head>
|
||||
<?php
|
||||
$ok = "false";
|
||||
$nm = "Null";
|
||||
$dbl = "false";
|
||||
if ((isset($_GET['storno'])) && ($_GET['storno'] == "true")) {
|
||||
$ok = "true";
|
||||
}
|
||||
if (isset($_GET['name'])) {
|
||||
$nm = $_GET['name'];
|
||||
}
|
||||
if ((isset($_GET['double'])) && ($_GET['double'] == "true")) {
|
||||
$dbl = "true";
|
||||
}
|
||||
?>
|
||||
<script type="text/javascript">
|
||||
var params = getAuthorisation('<?php echo "$ok,$nm,$dbl"?>');
|
||||
</script>
|
||||
|
||||
<body>
|
||||
<div id="container" class="anmeld">
|
||||
<div class="col-12 text-center">
|
||||
<h3>Führungs-Anmeldungen</h3>
|
||||
</div>
|
||||
<div class="col-12 col-xm-8 text-center">
|
||||
<div class="col-12" id="auswahl"><h5>Führung am</h5></div>
|
||||
</div>
|
||||
<br/>
|
||||
<div class="col-12 col-xm-8 text-center">
|
||||
<table id="tabAnmeld" class="table table-bordered table-sm"></table>
|
||||
<br/>
|
||||
<div class="row">
|
||||
<div class="col-sm-1 text-left"></div>
|
||||
<div class="col-12 col-sm-4 text-center">
|
||||
<button type="button" val="OK" id="absagen" class="btn btn-primary">Absage <br/>senden</button>
|
||||
</div>
|
||||
<div class="col-sm-1 text-center"></div>
|
||||
<div class="col-12 col-sm-4 text-center">
|
||||
<button type="button" val="OK" id="uebernehmen" class="btn btn-primary">Teilnahme<br/>übernehmen
|
||||
</button>
|
||||
</div>
|
||||
<div class="col-sm-1 text-right"></div>
|
||||
</div>
|
||||
<div id="absagedialog">
|
||||
<div id="absagetext"></div>
|
||||
</div>
|
||||
<div id="eintragedialog">
|
||||
<div id="eintragetext"></div>
|
||||
</div>
|
||||
<div id="detail">
|
||||
<div id="detailtext"></div>
|
||||
</div>
|
||||
<!-- Info unter Tabelle -->
|
||||
<div class="row" id="author">
|
||||
<div class="col-6 text-left">
|
||||
<a href="mailto:rxf@gmx.de">mailto:rxf@gmx.de</a>
|
||||
</div>
|
||||
<div id="versn" class="col-6 text-right"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- container -->
|
||||
<div id="names" class="col-12 col-xm-8 text-center anmeld">
|
||||
<table id="tnames" class="table table-bordered table-sm"></table>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
79
html/sternwarte/intern/anmeld/checkanmeld.js
Normal file
79
html/sternwarte/intern/anmeld/checkanmeld.js
Normal file
@@ -0,0 +1,79 @@
|
||||
// Anmeldung überprüfen und ggf. austragen
|
||||
|
||||
|
||||
const mysql = require('mysql2')
|
||||
const util = require('util')
|
||||
|
||||
const MYSQLHOST = process.env.MYSQLHOST || 'localhost'
|
||||
const MYSQLPORT = process.env.MYSQLPORT || 3306
|
||||
// const MYSQLUSER = process.env.MYSQLUSER || 'db310927'
|
||||
// const MYSQLPASSWD = process.env.MYSQLPASSWD || 'ArktUhr'
|
||||
// const MYSQLDB = process.env.MYSQLDB || 'db310927'
|
||||
const MYSQLUSER = process.env.MYSQLUSER || 'root'
|
||||
const MYSQLPASSWD = process.env.MYSQLPASSWD || 'SFluorit'
|
||||
const MYSQLDB = process.env.MYSQLDB || 'sternwarte'
|
||||
|
||||
|
||||
|
||||
const dbConnect = () => {
|
||||
// console.log("host:", MYSQLHOST,
|
||||
// "port:", MYSQLPORT,
|
||||
// "user:", MYSQLUSER,
|
||||
// "password:", MYSQLPASSWD,
|
||||
// "database:", MYSQLDB)
|
||||
//
|
||||
const connect = mysql.createConnection({
|
||||
host: MYSQLHOST,
|
||||
// socketPath: '/var/lib/mysql/mysql.sock',
|
||||
port: MYSQLPORT,
|
||||
user: MYSQLUSER,
|
||||
password: MYSQLPASSWD,
|
||||
database: MYSQLDB
|
||||
})
|
||||
return connect;
|
||||
}
|
||||
|
||||
const doTheQuery = async (qstr) => {
|
||||
let retur = { error: false, values: []}
|
||||
const conn = dbConnect()
|
||||
const query = util.promisify(conn.query).bind(conn)
|
||||
try {
|
||||
const rows = await query(qstr)
|
||||
retur.values = rows
|
||||
} catch(e) {
|
||||
console.log(e)
|
||||
retur.error = true
|
||||
retur.errortext = "Problems reading from database (query)"
|
||||
}
|
||||
finally{
|
||||
conn.end()
|
||||
}
|
||||
return retur
|
||||
}
|
||||
|
||||
const holIDs = async () => {
|
||||
let ids = []
|
||||
let qstr = 'SELECT id FROM anmeldungen where name != "-" and fdatum <= 20221002'
|
||||
let erg = await doTheQuery(qstr)
|
||||
for (let x of erg.values) {
|
||||
ids.push(x)
|
||||
}
|
||||
return ids
|
||||
}
|
||||
|
||||
const remove4WeekOlds = async (ids) => {
|
||||
for(x of ids) {
|
||||
let qstr = `UPDATE anmeldungen SET name='-', vorname='-', email='-', telefon='-', plz=0, stadt='-', strasse='-' WHERE id=${x.id}`
|
||||
let erg = await doTheQuery(qstr)
|
||||
console.log(`id: ${x.id} => ${JSON.stringify(erg)}`)
|
||||
}
|
||||
}
|
||||
|
||||
async function main() {
|
||||
let idarray = await holIDs()
|
||||
await remove4WeekOlds(idarray)
|
||||
console.log("Alle durch")
|
||||
}
|
||||
|
||||
main().catch(console.error);
|
||||
|
||||
94
html/sternwarte/intern/anmeld/css/anmeld.css
Normal file
94
html/sternwarte/intern/anmeld/css/anmeld.css
Normal file
@@ -0,0 +1,94 @@
|
||||
@CHARSET "UTF-8";
|
||||
|
||||
body {
|
||||
font-family: Arial, Verdana, Helevetica, sans-serif;
|
||||
font-size: 80%;
|
||||
position:relative;
|
||||
margin: 3px 0 3px 0;
|
||||
padding: 0;
|
||||
background-color: #FFFFDD;
|
||||
}
|
||||
|
||||
#container, #names {
|
||||
max-width: 800px;
|
||||
width: 95%;
|
||||
height: 100%;
|
||||
margin: 5px auto;
|
||||
border: solid 2px black;
|
||||
background: #EEEEEE;
|
||||
}
|
||||
|
||||
h3 {
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
h5 {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
#auswahl {
|
||||
margin-top: 15px;
|
||||
}
|
||||
|
||||
#gesamtsumme {
|
||||
margin-top: 5px;
|
||||
font-size: 85%;
|
||||
}
|
||||
|
||||
#author {
|
||||
font-size:90%;
|
||||
margin: auto;
|
||||
padding-bottom: 8px;
|
||||
margin-top: 8px;
|
||||
}
|
||||
|
||||
#tabAnmeld, #tnames {
|
||||
margin: auto;
|
||||
border-collapse: collapse;
|
||||
}
|
||||
|
||||
#tnames {
|
||||
margin-top: 10px;
|
||||
margin-bottom: 10px;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
#names {
|
||||
display: none;
|
||||
}
|
||||
|
||||
#absagedialog {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
#absagen, #uebernehmen {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.det {
|
||||
border: 1px solid black;
|
||||
padding-left: 10px;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.ui-dialog {
|
||||
max-width: 800px !important;
|
||||
width: 80% !important;
|
||||
}
|
||||
|
||||
.findit {
|
||||
box-shadow: none;
|
||||
height: 20px;
|
||||
width: 20px;
|
||||
border-radius: 10px;
|
||||
margin-right: 5px;
|
||||
}
|
||||
|
||||
#anmeldung {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
#nixda {
|
||||
color: red;
|
||||
padding-bottom: 15px;
|
||||
}
|
||||
7
html/sternwarte/intern/anmeld/css/bootstrap.min.css
vendored
Normal file
7
html/sternwarte/intern/anmeld/css/bootstrap.min.css
vendored
Normal file
File diff suppressed because one or more lines are too long
459
html/sternwarte/intern/anmeld/js/anmeld.js
Normal file
459
html/sternwarte/intern/anmeld/js/anmeld.js
Normal file
@@ -0,0 +1,459 @@
|
||||
// Vanilla JS Migration of anmeld.js (jQuery removed)
|
||||
|
||||
async function ladeAbsagegruende() {
|
||||
const res = await fetch('data/absagegruende.txt');
|
||||
const text = await res.text();
|
||||
return text
|
||||
.split('\n')
|
||||
.map(line => line.trim())
|
||||
.filter(line => line.length > 0);
|
||||
}
|
||||
|
||||
document.addEventListener('DOMContentLoaded', async () => {
|
||||
|
||||
// URL-Parameter lesen
|
||||
const urlParams = new URLSearchParams(window.location.search);
|
||||
const query = {
|
||||
typ: urlParams.get('typ') || 'regular',
|
||||
storno: urlParams.get('storno') === 'true',
|
||||
double: urlParams.get('double') === 'true',
|
||||
name: urlParams.get('name') || 'Null'
|
||||
};
|
||||
|
||||
const absagegrundListe = await ladeAbsagegruende();
|
||||
const fuehrung = query.typ === 'sonnen' ? 'Sonnenführung' : 'Sternführung';
|
||||
let absagegrund = "";
|
||||
|
||||
const ajaxURL = "php/anmeldDB.php";
|
||||
const ANZAHL_DATES = query.typ === 'sonnen' ? 25 : 50;
|
||||
const TEXTE = {
|
||||
|
||||
absagetext: "Absage an alle angemeldeten Besucher senden.",
|
||||
bittegrund: "Die Führung wird abgesagt wegen:",
|
||||
schonabgesagt: "Absage schon gesendet. Nochmal senden?",
|
||||
subject: `Absage der heutigen ${fuehrung}`,
|
||||
bodytext: `Sehr geehrte Dame, sehr geehrter Herr,
|
||||
|
||||
Sie haben sich über unsere Webseite www.sternwarte-welzheim.de zur heutigen ${fuehrung} angemeldet.
|
||||
Aufgrund {absagegrund} können wir heute keine Sternführung anbieten.
|
||||
Bitte melden Sie sich für einen anderen Termin neu an.
|
||||
|
||||
Mit freundlichen Grüßen
|
||||
Beobachtergruppe Sternwarte Welzheim`,
|
||||
};
|
||||
|
||||
const liste = {
|
||||
emails: [],
|
||||
ids: []
|
||||
};
|
||||
|
||||
let abgesagt = false;
|
||||
let actualdate;
|
||||
let isSmallScreen = false
|
||||
let DateTime = luxon.DateTime
|
||||
|
||||
|
||||
function $(selector) {
|
||||
return document.querySelector(selector);
|
||||
}
|
||||
|
||||
function $all(selector) {
|
||||
return document.querySelectorAll(selector);
|
||||
}
|
||||
|
||||
async function fetchFromDbase(body) {
|
||||
body.typ = query.typ;
|
||||
const response = await fetch(ajaxURL, {
|
||||
method: 'POST',
|
||||
headers: {'Content-Type': 'application/js'},
|
||||
body: JSON.stringify(body)
|
||||
});
|
||||
return await response.json();
|
||||
}
|
||||
|
||||
async function putToDbase(body) {
|
||||
body.typ = query.typ;
|
||||
const response = await fetch(ajaxURL, {
|
||||
method: 'POST',
|
||||
headers: {'Content-Type': 'application/js'},
|
||||
body: JSON.stringify(body)
|
||||
});
|
||||
return await response.json();
|
||||
}
|
||||
|
||||
function clearElement(el) {
|
||||
el.innerHTML = '';
|
||||
}
|
||||
|
||||
function appendHtml(el, html) {
|
||||
el.insertAdjacentHTML('beforeend', html);
|
||||
}
|
||||
|
||||
function setVisibility(id, visible) {
|
||||
$(id).style.visibility = visible ? 'visible' : 'hidden';
|
||||
}
|
||||
|
||||
async function storeAbsage(ids) {
|
||||
const update = { cmd: 'UPDATE', field: 'abgesagt', ids: ids, values: [1] };
|
||||
await putToDbase(update);
|
||||
abgesagt = true;
|
||||
}
|
||||
|
||||
async function getDetailText(id) {
|
||||
const nbr = parseInt(id);
|
||||
const holit = await fetchFromDbase({cmd:'GET_TEILN_ID', id:nbr});
|
||||
const entry = holit[0];
|
||||
return `
|
||||
<div class="det">${entry.name} ${entry.vorname}<br /></div>
|
||||
<div class="det">${entry.email}<br /></div>
|
||||
<div class="det">${entry.plz} ${entry.stadt}<br /></div>
|
||||
<div class="det">${entry.strasse}<br /></div>
|
||||
<div class="det">${entry.telefon}<br /></div>
|
||||
<div class="det">${entry.remarks}<br /></div>`;
|
||||
}
|
||||
|
||||
|
||||
// Teilnehmer aus 'anmeldungen' austragen und den count in 'fdatum1' anpassen
|
||||
const austragen = async (teilnehmer) => {
|
||||
let update = {cmd: 'DELETEONE', id: parseInt(teilnehmer.id)}
|
||||
const erg1 = await putToDbase(update)
|
||||
// update = {cmd: 'UPDATECOUNT',date: parseInt(teilnehmer.fdatum), anzahl: parseInt(teilnehmer.anzahl)}
|
||||
const erg2 = await putToDbase(update)
|
||||
console.log("Storno Ergebisse: ",erg1,erg2)
|
||||
showAktAnmeldungen(actualdate)
|
||||
}
|
||||
|
||||
|
||||
async function showAktAnmeldungen(date) {
|
||||
actualdate = date;
|
||||
liste.emails = [];
|
||||
liste.ids = [];
|
||||
abgesagt = true;
|
||||
let column = query.storno ? "col-2" : "col-3";
|
||||
const anmeldungen = await fetchFromDbase({cmd:'GET_ANMELD', id:date});
|
||||
let besucher = 0;
|
||||
|
||||
clearElement($('tbody'));
|
||||
|
||||
for (let e of anmeldungen) {
|
||||
besucher += parseInt(e.anzahl);
|
||||
liste.emails.push(e.email);
|
||||
liste.ids.push(e.id);
|
||||
if (e.abgesagt !== '1') {
|
||||
abgesagt = false;
|
||||
}
|
||||
|
||||
// const selected = e.teilgenommen === "1" ? "checked" : "";
|
||||
const row = document.createElement('tr');
|
||||
row.classList.add('d-flex');
|
||||
|
||||
row.innerHTML = `
|
||||
<td class="tdname col-6">${e.name} ${e.vorname}</td>
|
||||
<td class=${column}>${e.anzahl}</td>`
|
||||
if (query.storno) {
|
||||
row.innerHTML += `<td class="col-2 tdstorno"><input type="checkbox" value="${e.id}" </td>`
|
||||
}
|
||||
|
||||
row.querySelector('.tdname').addEventListener('click', async () => {
|
||||
const detail = await getDetailText(e.id);
|
||||
$('#detailtext').innerHTML = detail;
|
||||
$('#detaildialog').showModal();
|
||||
});
|
||||
|
||||
if(query.storno) {
|
||||
row.querySelector('.tdstorno').addEventListener('click', function() {
|
||||
const tr = this.closest("tr") // Finds the closest row <tr>
|
||||
const index = tr.rowIndex-1
|
||||
austragen(anmeldungen[index])
|
||||
});
|
||||
}
|
||||
|
||||
$('#tabAnmeld tbody').appendChild(row);
|
||||
}
|
||||
if (abgesagt) {
|
||||
$('#absagen').innerHTML = 'Absage<br />wurde gesendet';
|
||||
}
|
||||
|
||||
if (besucher !== 0) {
|
||||
const sumRow = document.createElement('tr');
|
||||
sumRow.id = 'summe';
|
||||
sumRow.classList.add('d-flex');
|
||||
sumRow.innerHTML = `
|
||||
<td class="col-6">Summe der Anmeldungen</td>`
|
||||
if (query.storno) {
|
||||
sumRow.innerHTML += `<td style="text-align: center;" class="col-4">${besucher}</td>`;
|
||||
} else {
|
||||
sumRow.innerHTML += `<td class="col-3">${besucher}</td>`;
|
||||
}
|
||||
$('#tabAnmeld tbody').appendChild(sumRow);
|
||||
}
|
||||
}
|
||||
|
||||
async function findName(name) {
|
||||
const update = { cmd: 'GET_TEILN_NAME', name: name };
|
||||
let erg = await putToDbase(update);
|
||||
clearElement($('#tnames'));
|
||||
|
||||
appendHtml($('#tnames'), `
|
||||
<thead><tr>
|
||||
<th class="col-6">Name</th>
|
||||
<th class="col-2">Anzahl</th>
|
||||
<th class="col-2">Datum</th>
|
||||
<th class="col-2">Finden</th>
|
||||
</tr></thead><tbody>`);
|
||||
|
||||
for (let x of erg) {
|
||||
appendHtml($('#tnames'), `
|
||||
<tr>
|
||||
<td class="tdname col-6">${x.name} ${x.vorname}</td>
|
||||
<td class="col-2">${x.anzahl}</td>
|
||||
<td class="col-2">${DateTime.fromISO(x.fdatum).toFormat('yyyy-LL-dd')}</td>
|
||||
<td class="tdfind col-2"><button type="button" class="findit" value="${x.id}">🔍</button></td>
|
||||
</tr>`);
|
||||
}
|
||||
appendHtml($('#tnames'), `</tbody>`);
|
||||
$('#names').style.display = 'block';
|
||||
|
||||
$all('.findit').forEach(btn => {
|
||||
btn.addEventListener('click', async () => {
|
||||
const id = btn.value;
|
||||
const detail = await getDetailText(id);
|
||||
$('#detailtext').innerHTML = detail;
|
||||
$('#detaildialog').showModal();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
$('#absagen').addEventListener('click', () => {
|
||||
$('#absagetext').innerHTML = abgesagt ? TEXTE.schonabgesagt : TEXTE.absagetext;
|
||||
$('#bittegrund').innerHTML = TEXTE.bittegrund
|
||||
$('#absagedialog').showModal();
|
||||
|
||||
const container = $('#absagegrund');
|
||||
clearElement(container);
|
||||
absagegrundListe.forEach((g, i) => {
|
||||
const line = document.createElement('div');
|
||||
line.className = 'absageline';
|
||||
const radio = document.createElement('input');
|
||||
radio.type = 'radio';
|
||||
radio.name = 'grund';
|
||||
radio.value = i;
|
||||
radio.id = `grund${i}`;
|
||||
radio.checked = i === 0; // Default to the first option
|
||||
|
||||
const label = document.createElement('label');
|
||||
label.setAttribute('for', `grund${i}`);
|
||||
const span = document.createElement('span');
|
||||
span.textContent = g;
|
||||
span.style.marginLeft = "20px"
|
||||
|
||||
line.appendChild(radio);
|
||||
line.appendChild(span);
|
||||
line.appendChild(document.createElement('br'));
|
||||
container.appendChild(line);
|
||||
});
|
||||
});
|
||||
|
||||
$('#absagedialog-send').addEventListener('click', async () => {
|
||||
const grundIndex = Array.from($all('input[name=grund]')).find(el => el.checked)?.value || 0;
|
||||
absagegrund = absagegrundListe[grundIndex];
|
||||
|
||||
await storeAbsage(liste.ids);
|
||||
await fetch('https://laufschrift.rexfue.de/switch/switch_on')
|
||||
|
||||
const bodyText = TEXTE.bodytext.replace("{absagegrund}", absagegrund);
|
||||
await fetchFromDbase({
|
||||
cmd: 'SENDMYMAIL',
|
||||
to: ['rexfue@gmail.com'],
|
||||
betreff: TEXTE.subject,
|
||||
body: bodyText,
|
||||
bcc: liste.emails
|
||||
});
|
||||
console.log("Gesendet an: ", liste.emails)
|
||||
$('#absagen').innerHTML = 'Absage<br />wurde gesendet';
|
||||
$('#absagedialog').close();
|
||||
});
|
||||
|
||||
$('#absagedialog-cancel').addEventListener('click', () => {
|
||||
$('#absagedialog').close();
|
||||
});
|
||||
|
||||
async function getDoubles(date) {
|
||||
const update = { cmd: 'GET_ANMELDNEW', date: date, special: "alllater" };
|
||||
let { data } = await putToDbase(update);
|
||||
|
||||
data.sort((a, b) => a.name.localeCompare(b.name));
|
||||
data.push({name: '', vorname: '', email: ''});
|
||||
|
||||
let i;
|
||||
for(i = 0; i < data.length - 1; i++) {
|
||||
data[i].single = false;
|
||||
if(data[i].name !== data[i+1].name) {
|
||||
data[i].single = true;
|
||||
} else {
|
||||
while((i < data.length - 1) && (data[i].name === data[i+1].name)) {
|
||||
if (data[i].strasse.slice(0,6).toUpperCase() !== data[i+1].strasse.slice(0,6).toUpperCase()
|
||||
|| data[i].plz !== data[i+1].plz) {
|
||||
data[i].single = true;
|
||||
break;
|
||||
} else {
|
||||
i++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
data[i].single = true;
|
||||
return data;
|
||||
}
|
||||
|
||||
async function showDoubles(date) {
|
||||
const erg = await getDoubles(date);
|
||||
const container = $('#tnames');
|
||||
clearElement(container);
|
||||
|
||||
appendHtml(container, `
|
||||
<thead><tr>
|
||||
<th class="col-2">Name</th>
|
||||
<th class="col-2">Vorname</th>
|
||||
<th class="col-3">Email</th>
|
||||
<th class="col-1">Anz</th>
|
||||
<th class="col-2">Datum</th>
|
||||
<th class="col-2">Anmeldung</th>
|
||||
</tr></thead><tbody>`);
|
||||
|
||||
for (let x of erg) {
|
||||
if (x.single) continue;
|
||||
appendHtml(container, `
|
||||
<tr>
|
||||
<td class="tdname col-2">${x.name}</td>
|
||||
<td class="tdname col-2">${x.vorname}</td>
|
||||
<td class="tdname col-3">${x.email}</td>
|
||||
<td class="col-1">${x.anzahl}</td>
|
||||
<td class="col-2">${DateTime.fromISO(x.fdatum).toFormat('yyyy-LL-dd')}</td>
|
||||
<td class="col-2">${DateTime.fromISO(x.angemeldet).toFormat('yyyy-LL-dd')}</td>
|
||||
</tr>`);
|
||||
}
|
||||
|
||||
appendHtml(container, `</tbody>`);
|
||||
$('#names').style.display = 'block';
|
||||
}
|
||||
|
||||
function switchText() {
|
||||
const thead = document.createElement('thead');
|
||||
const row = document.createElement('tr');
|
||||
let column = query.storno ? "col-2" : "col-3"
|
||||
row.className = 'd-flex';
|
||||
|
||||
row.innerHTML = `
|
||||
<th class="col-6">Name</th>
|
||||
<th class=${column}>${isSmallScreen ? 'Anz' : 'Personen'}</th>`
|
||||
if (query.storno) {
|
||||
row.innerHTML += `<th class="col-2">Storno</th>`;
|
||||
}
|
||||
$('#versn').innerHTML = "Version: " + VERSION + ' vom ' + VDATE
|
||||
|
||||
|
||||
thead.appendChild(row);
|
||||
const table = $('#tabAnmeld');
|
||||
clearElement(table); // Leert sowohl thead als auch tbody
|
||||
table.appendChild(thead);
|
||||
table.appendChild(document.createElement('tbody'));
|
||||
}
|
||||
|
||||
// Aus dem rohen Führungsdatum von der Datenbank ein besser
|
||||
// leserliches Format erzeugen
|
||||
// Params:
|
||||
// w -> Wochentag
|
||||
// d -> Datum in DBase-Format
|
||||
// t -> Uhrzeit
|
||||
// Return
|
||||
// neu formatierter Datums-String
|
||||
const bauDate = (w,d,t) => {
|
||||
let dd = d.replace(/^(\d{4})(\d{2})(\d{2})$/, '$3.$2.$1',);
|
||||
let dt = w.substr(0,2) + ', ' + dd + ' ' + t.substr(0,2) + ':00';
|
||||
return dt;
|
||||
}
|
||||
|
||||
|
||||
async function buildFuehrungsDates(dates, last) {
|
||||
let n = 0;
|
||||
let i = 0;
|
||||
let summ = 0;
|
||||
let select = `<select name='ftermin' id='ftermin'>`;
|
||||
let selectedNext = false;
|
||||
const today = DateTime.now().startOf('day');
|
||||
|
||||
for (let d of dates) {
|
||||
let isselected = "";
|
||||
const fday = DateTime.fromISO(d.datum);
|
||||
if (!selectedNext && (isSameorAfter = fday >= today)) {
|
||||
selectedNext = true;
|
||||
isselected = "selected";
|
||||
n = i;
|
||||
}
|
||||
const count = await fetchFromDbase({cmd: 'GET_COUNTS', fdate: d.datum});
|
||||
const isFuehrung = (count && count > 0) ? '' : 'disabled';
|
||||
let datstr
|
||||
let grpstr
|
||||
if (query.typ == 'regular') {
|
||||
datstr = bauDate(d.wtag, d.datum, d.uhrzeit)
|
||||
grpstr = `(${d.grp})`
|
||||
} else {
|
||||
datstr = bauDate('So', d.datum, '11')
|
||||
grpstr = " "
|
||||
}
|
||||
if (isSmallScreen) {
|
||||
select += `
|
||||
<option value="${d.datum}" ${isselected} ${isFuehrung}> ${datstr} ${count || 0}B</option>`;
|
||||
} else {
|
||||
select += `
|
||||
<option value="${d.datum}" ${isselected} ${isFuehrung}> ${datstr} ${grpstr} ${count || 0} Besucher</option>`;
|
||||
}
|
||||
i++;
|
||||
summ += count ? parseInt(count) : 0;
|
||||
if (d.datum >= last) break;
|
||||
}
|
||||
select += `</select>
|
||||
<div id="gesamtsumme">Gesamtzahl der Anmeldungen (ab heute): ${summ}</div>`;
|
||||
|
||||
$('#auswahl').innerHTML = select;
|
||||
|
||||
$('#ftermin').addEventListener('change', async () => {
|
||||
const date = $('#ftermin').value;
|
||||
const index = $('#ftermin').selectedIndex;
|
||||
setVisibility('#absagen', index === 0);
|
||||
await showAktAnmeldungen(date);
|
||||
});
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
async function main(n) {
|
||||
let index = 0
|
||||
const today = DateTime.now().minus({ days: 14 }).toFormat("yyyyLLdd");
|
||||
const dates = await fetchFromDbase({cmd:'GET_DATES', anzahl:n, date: today});
|
||||
const last = await fetchFromDbase({cmd:'GET_LASTANMELDUNG', date: today});
|
||||
|
||||
let mq = window.matchMedia('(max-width: 800px)');
|
||||
isSmallScreen = mq.matches
|
||||
switchText();
|
||||
mq.addEventListener('change', async (e) => {
|
||||
isSmallScreen = e.matches
|
||||
switchText();
|
||||
await buildFuehrungsDates(dates, last);
|
||||
showAktAnmeldungen(actualdate);
|
||||
});
|
||||
|
||||
index = await buildFuehrungsDates(dates, last);
|
||||
|
||||
await showAktAnmeldungen(dates[index].datum);
|
||||
if (query.name !== 'Null') {
|
||||
await findName(query.name);
|
||||
}
|
||||
if (query.double) {
|
||||
await showDoubles(DateTime.now().toFormat("yyyyLLdd"));
|
||||
}
|
||||
}
|
||||
|
||||
main(ANZAHL_DATES).catch(console.error);
|
||||
});
|
||||
459
html/sternwarte/intern/anmeld/js/anmeld.js_o
Normal file
459
html/sternwarte/intern/anmeld/js/anmeld.js_o
Normal file
@@ -0,0 +1,459 @@
|
||||
// Vanilla JS Migration of anmeld.js (jQuery removed)
|
||||
|
||||
async function ladeAbsagegruende() {
|
||||
const res = await fetch('data/absagegruende.txt');
|
||||
const text = await res.text();
|
||||
return text
|
||||
.split('\n')
|
||||
.map(line => line.trim())
|
||||
.filter(line => line.length > 0);
|
||||
}
|
||||
|
||||
document.addEventListener('DOMContentLoaded', async () => {
|
||||
|
||||
// URL-Parameter lesen
|
||||
const urlParams = new URLSearchParams(window.location.search);
|
||||
const query = {
|
||||
typ: urlParams.get('typ') || 'regular',
|
||||
storno: urlParams.get('storno') === 'true',
|
||||
double: urlParams.get('double') === 'true',
|
||||
name: urlParams.get('name') || 'Null'
|
||||
};
|
||||
|
||||
const absagegrundListe = await ladeAbsagegruende();
|
||||
const fuehrung = query.typ === 'sonnen' ? 'Sonnenführung' : 'Sternführung';
|
||||
let absagegrund = "";
|
||||
|
||||
const ajaxURL = "php/anmeldDB.php";
|
||||
const ANZAHL_DATES = query.typ === 'sonnen' ? 25 : 50;
|
||||
const TEXTE = {
|
||||
|
||||
absagetext: "Absage an alle angemeldeten Besucher senden.",
|
||||
bittegrund: "Die Führung wird abgesagt wegen:",
|
||||
schonabgesagt: "Absage schon gesendet. Nochmal senden?",
|
||||
subject: `Absage der heutigen ${fuehrung}`,
|
||||
bodytext: `Sehr geehrte Dame, sehr geehrter Herr,
|
||||
|
||||
Sie haben sich über unsere Webseite www.sternwarte-welzheim.de zur heutigen ${fuehrung} angemeldet.
|
||||
Aufgrund {absagegrund} können wir heute keine Sternführung anbieten.
|
||||
Bitte melden Sie sich für einen anderen Termin neu an.
|
||||
|
||||
Mit freundlichen Grüßen
|
||||
Beobachtergruppe Sternwarte Welzheim`,
|
||||
};
|
||||
|
||||
const liste = {
|
||||
emails: [],
|
||||
ids: []
|
||||
};
|
||||
|
||||
let abgesagt = false;
|
||||
let actualdate;
|
||||
let isSmallScreen = false
|
||||
let DateTime = luxon.DateTime
|
||||
|
||||
|
||||
function $(selector) {
|
||||
return document.querySelector(selector);
|
||||
}
|
||||
|
||||
function $all(selector) {
|
||||
return document.querySelectorAll(selector);
|
||||
}
|
||||
|
||||
async function fetchFromDbase(body) {
|
||||
body.typ = query.typ;
|
||||
const response = await fetch(ajaxURL, {
|
||||
method: 'POST',
|
||||
headers: {'Content-Type': 'application/js'},
|
||||
body: JSON.stringify(body)
|
||||
});
|
||||
return await response.json();
|
||||
}
|
||||
|
||||
async function putToDbase(body) {
|
||||
body.typ = query.typ;
|
||||
const response = await fetch(ajaxURL, {
|
||||
method: 'POST',
|
||||
headers: {'Content-Type': 'application/js'},
|
||||
body: JSON.stringify(body)
|
||||
});
|
||||
return await response.json();
|
||||
}
|
||||
|
||||
function clearElement(el) {
|
||||
el.innerHTML = '';
|
||||
}
|
||||
|
||||
function appendHtml(el, html) {
|
||||
el.insertAdjacentHTML('beforeend', html);
|
||||
}
|
||||
|
||||
function setVisibility(id, visible) {
|
||||
$(id).style.visibility = visible ? 'visible' : 'hidden';
|
||||
}
|
||||
|
||||
async function storeAbsage(ids) {
|
||||
const update = { cmd: 'UPDATE', field: 'abgesagt', ids: ids, values: [1] };
|
||||
await putToDbase(update);
|
||||
abgesagt = true;
|
||||
}
|
||||
|
||||
async function getDetailText(id) {
|
||||
const nbr = parseInt(id);
|
||||
const holit = await fetchFromDbase({cmd:'GET_TEILN_ID', id:nbr});
|
||||
const entry = holit[0];
|
||||
return `
|
||||
<div class="det">${entry.name} ${entry.vorname}<br /></div>
|
||||
<div class="det">${entry.email}<br /></div>
|
||||
<div class="det">${entry.plz} ${entry.stadt}<br /></div>
|
||||
<div class="det">${entry.strasse}<br /></div>
|
||||
<div class="det">${entry.telefon}<br /></div>
|
||||
<div class="det">${entry.remarks}<br /></div>`;
|
||||
}
|
||||
|
||||
|
||||
// Teilnehmer aus 'anmeldungen' austragen und den count in 'fdatum1' anpassen
|
||||
const austragen = async (teilnehmer) => {
|
||||
let update = {cmd: 'DELETEONE', id: parseInt(teilnehmer.id)}
|
||||
const erg1 = await putToDbase(update)
|
||||
// update = {cmd: 'UPDATECOUNT',date: parseInt(teilnehmer.fdatum), anzahl: parseInt(teilnehmer.anzahl)}
|
||||
const erg2 = await putToDbase(update)
|
||||
console.log("Storno Ergebisse: ",erg1,erg2)
|
||||
showAktAnmeldungen(actualdate)
|
||||
}
|
||||
|
||||
|
||||
async function showAktAnmeldungen(date) {
|
||||
actualdate = date;
|
||||
liste.emails = [];
|
||||
liste.ids = [];
|
||||
abgesagt = true;
|
||||
let column = query.storno ? "col-2" : "col-3";
|
||||
const anmeldungen = await fetchFromDbase({cmd:'GET_ANMELD', id:date});
|
||||
let besucher = 0;
|
||||
|
||||
clearElement($('tbody'));
|
||||
|
||||
for (let e of anmeldungen) {
|
||||
besucher += parseInt(e.anzahl);
|
||||
liste.emails.push(e.email);
|
||||
liste.ids.push(e.id);
|
||||
if (e.abgesagt !== '1') {
|
||||
abgesagt = false;
|
||||
}
|
||||
|
||||
// const selected = e.teilgenommen === "1" ? "checked" : "";
|
||||
const row = document.createElement('tr');
|
||||
row.classList.add('d-flex');
|
||||
|
||||
row.innerHTML = `
|
||||
<td class="tdname col-6">${e.name} ${e.vorname}</td>
|
||||
<td class=${column}>${e.anzahl}</td>`
|
||||
if (query.storno) {
|
||||
row.innerHTML += `<td class="col-2 tdstorno"><input type="checkbox" value="${e.id}" </td>`
|
||||
}
|
||||
|
||||
row.querySelector('.tdname').addEventListener('click', async () => {
|
||||
const detail = await getDetailText(e.id);
|
||||
$('#detailtext').innerHTML = detail;
|
||||
$('#detaildialog').showModal();
|
||||
});
|
||||
|
||||
if(query.storno) {
|
||||
row.querySelector('.tdstorno').addEventListener('click', function() {
|
||||
const tr = this.closest("tr") // Finds the closest row <tr>
|
||||
const index = tr.rowIndex-1
|
||||
austragen(anmeldungen[index])
|
||||
});
|
||||
}
|
||||
|
||||
$('#tabAnmeld tbody').appendChild(row);
|
||||
}
|
||||
if (abgesagt) {
|
||||
$('#absagen').innerHTML = 'Absage<br />wurde gesendet';
|
||||
}
|
||||
|
||||
if (besucher !== 0) {
|
||||
const sumRow = document.createElement('tr');
|
||||
sumRow.id = 'summe';
|
||||
sumRow.classList.add('d-flex');
|
||||
sumRow.innerHTML = `
|
||||
<td class="col-6">Summe der Anmeldungen</td>`
|
||||
if (query.storno) {
|
||||
sumRow.innerHTML += `<td style="text-align: center;" class="col-4">${besucher}</td>`;
|
||||
} else {
|
||||
sumRow.innerHTML += `<td class="col-3">${besucher}</td>`;
|
||||
}
|
||||
$('#tabAnmeld tbody').appendChild(sumRow);
|
||||
}
|
||||
}
|
||||
|
||||
async function findName(name) {
|
||||
const update = { cmd: 'GET_TEILN_NAME', name: name };
|
||||
let erg = await putToDbase(update);
|
||||
clearElement($('#tnames'));
|
||||
|
||||
appendHtml($('#tnames'), `
|
||||
<thead><tr>
|
||||
<th class="col-6">Name</th>
|
||||
<th class="col-2">Anzahl</th>
|
||||
<th class="col-2">Datum</th>
|
||||
<th class="col-2">Finden</th>
|
||||
</tr></thead><tbody>`);
|
||||
|
||||
for (let x of erg) {
|
||||
appendHtml($('#tnames'), `
|
||||
<tr>
|
||||
<td class="tdname col-6">${x.name} ${x.vorname}</td>
|
||||
<td class="col-2">${x.anzahl}</td>
|
||||
<td class="col-2">${DateTime.fromISO(x.fdatum).toFormat('yyyy-LL-dd')}</td>
|
||||
<td class="tdfind col-2"><button type="button" class="findit" value="${x.id}">🔍</button></td>
|
||||
</tr>`);
|
||||
}
|
||||
appendHtml($('#tnames'), `</tbody>`);
|
||||
$('#names').style.display = 'block';
|
||||
|
||||
$all('.findit').forEach(btn => {
|
||||
btn.addEventListener('click', async () => {
|
||||
const id = btn.value;
|
||||
const detail = await getDetailText(id);
|
||||
$('#detailtext').innerHTML = detail;
|
||||
$('#detaildialog').showModal();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
$('#absagen').addEventListener('click', () => {
|
||||
$('#absagetext').innerHTML = abgesagt ? TEXTE.schonabgesagt : TEXTE.absagetext;
|
||||
$('#bittegrund').innerHTML = TEXTE.bittegrund
|
||||
$('#absagedialog').showModal();
|
||||
|
||||
const container = $('#absagegrund');
|
||||
clearElement(container);
|
||||
absagegrundListe.forEach((g, i) => {
|
||||
const line = document.createElement('div');
|
||||
line.className = 'absageline';
|
||||
const radio = document.createElement('input');
|
||||
radio.type = 'radio';
|
||||
radio.name = 'grund';
|
||||
radio.value = i;
|
||||
radio.id = `grund${i}`;
|
||||
radio.checked = i === 0; // Default to the first option
|
||||
|
||||
const label = document.createElement('label');
|
||||
label.setAttribute('for', `grund${i}`);
|
||||
const span = document.createElement('span');
|
||||
span.textContent = g;
|
||||
span.style.marginLeft = "20px"
|
||||
|
||||
line.appendChild(radio);
|
||||
line.appendChild(span);
|
||||
line.appendChild(document.createElement('br'));
|
||||
container.appendChild(line);
|
||||
});
|
||||
});
|
||||
|
||||
$('#absagedialog-send').addEventListener('click', async () => {
|
||||
const grundIndex = Array.from($all('input[name=grund]')).find(el => el.checked)?.value || 0;
|
||||
absagegrund = absagegrundListe[grundIndex];
|
||||
|
||||
await storeAbsage(liste.ids);
|
||||
await fetch('https://laufschrift.rexfue.de/switch/switch_on')
|
||||
|
||||
const bodyText = TEXTE.bodytext.replace("{absagegrund}", absagegrund);
|
||||
await fetchFromDbase({
|
||||
cmd: 'SENDMYMAIL',
|
||||
to: ['rexfue@gmail.com'],
|
||||
betreff: TEXTE.subject,
|
||||
body: bodyText,
|
||||
bcc: liste.emails
|
||||
});
|
||||
console.log("Gesendet an: ", liste.emails)
|
||||
$('#absagen').innerHTML = 'Absage<br />wurde gesendet';
|
||||
$('#absagedialog').close();
|
||||
});
|
||||
|
||||
$('#absagedialog-cancel').addEventListener('click', () => {
|
||||
$('#absagedialog').close();
|
||||
});
|
||||
|
||||
async function getDoubles(date) {
|
||||
const update = { cmd: 'GET_ANMELDNEW', date: date, special: "alllater" };
|
||||
let { data } = await putToDbase(update);
|
||||
|
||||
data.sort((a, b) => a.name.localeCompare(b.name));
|
||||
data.push({name: '', vorname: '', email: ''});
|
||||
|
||||
let i;
|
||||
for(i = 0; i < data.length - 1; i++) {
|
||||
data[i].single = false;
|
||||
if(data[i].name !== data[i+1].name) {
|
||||
data[i].single = true;
|
||||
} else {
|
||||
while((i < data.length - 1) && (data[i].name === data[i+1].name)) {
|
||||
if (data[i].strasse.slice(0,6).toUpperCase() !== data[i+1].strasse.slice(0,6).toUpperCase()
|
||||
|| data[i].plz !== data[i+1].plz) {
|
||||
data[i].single = true;
|
||||
break;
|
||||
} else {
|
||||
i++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
data[i].single = true;
|
||||
return data;
|
||||
}
|
||||
|
||||
async function showDoubles(date) {
|
||||
const erg = await getDoubles(date);
|
||||
const container = $('#tnames');
|
||||
clearElement(container);
|
||||
|
||||
appendHtml(container, `
|
||||
<thead><tr>
|
||||
<th class="col-2">Name</th>
|
||||
<th class="col-2">Vorname</th>
|
||||
<th class="col-3">Email</th>
|
||||
<th class="col-1">Anz</th>
|
||||
<th class="col-2">Datum</th>
|
||||
<th class="col-2">Anmeldung</th>
|
||||
</tr></thead><tbody>`);
|
||||
|
||||
for (let x of erg) {
|
||||
if (x.single) continue;
|
||||
appendHtml(container, `
|
||||
<tr>
|
||||
<td class="tdname col-2">${x.name}</td>
|
||||
<td class="tdname col-2">${x.vorname}</td>
|
||||
<td class="tdname col-3">${x.email}</td>
|
||||
<td class="col-1">${x.anzahl}</td>
|
||||
<td class="col-2">${DateTime.fromISO(x.fdatum).toFormat('yyyy-LL-dd')}</td>
|
||||
<td class="col-2">${DateTime.fromISO(x.angemeldet).toFormat('yyyy-LL-dd')}</td>
|
||||
</tr>`);
|
||||
}
|
||||
|
||||
appendHtml(container, `</tbody>`);
|
||||
$('#names').style.display = 'block';
|
||||
}
|
||||
|
||||
function switchText() {
|
||||
const thead = document.createElement('thead');
|
||||
const row = document.createElement('tr');
|
||||
let column = query.storno ? "col-2" : "col-3"
|
||||
row.className = 'd-flex';
|
||||
|
||||
row.innerHTML = `
|
||||
<th class="col-6">Name</th>
|
||||
<th class=${column}>${isSmallScreen ? 'Anz' : 'Personen'}</th>`
|
||||
if (query.storno) {
|
||||
row.innerHTML += `<th class="col-2">Storno</th>`;
|
||||
}
|
||||
$('#versn').innerHTML = "Version: " + VERSION + ' vom ' + VDATE
|
||||
|
||||
|
||||
thead.appendChild(row);
|
||||
const table = $('#tabAnmeld');
|
||||
clearElement(table); // Leert sowohl thead als auch tbody
|
||||
table.appendChild(thead);
|
||||
table.appendChild(document.createElement('tbody'));
|
||||
}
|
||||
|
||||
// Aus dem rohen Führungsdatum von der Datenbank ein besser
|
||||
// leserliches Format erzeugen
|
||||
// Params:
|
||||
// w -> Wochentag
|
||||
// d -> Datum in DBase-Format
|
||||
// t -> Uhrzeit
|
||||
// Return
|
||||
// neu formatierter Datums-String
|
||||
const bauDate = (w,d,t) => {
|
||||
let dd = d.replace(/^(\d{4})(\d{2})(\d{2})$/, '$3.$2.$1',);
|
||||
let dt = w.substr(0,2) + ', ' + dd + ' ' + t.substr(0,2) + ':00';
|
||||
return dt;
|
||||
}
|
||||
|
||||
|
||||
async function buildFuehrungsDates(dates, last) {
|
||||
let n = 0;
|
||||
let i = 0;
|
||||
let summ = 0;
|
||||
let select = `<select name='ftermin' id='ftermin'>`;
|
||||
let selectedNext = false;
|
||||
const today = DateTime.now().startOf('day');
|
||||
|
||||
for (let d of dates) {
|
||||
let isselected = "";
|
||||
const fday = DateTime.fromISO(d.datum);
|
||||
if (!selectedNext && (isSameorAfter = fday >= today)) {
|
||||
selectedNext = true;
|
||||
isselected = "selected";
|
||||
n = i;
|
||||
}
|
||||
const count = await fetchFromDbase({cmd: 'GET_COUNTS', fdate: d.datum});
|
||||
const isFuehrung = (count && count > 0) ? '' : 'disabled';
|
||||
let datstr
|
||||
let grpstr
|
||||
if (query.typ == 'regular') {
|
||||
datstr = bauDate(d.wtag, d.datum, d.uhrzeit)
|
||||
grpstr = `(${d.grp})`
|
||||
} else {
|
||||
datstr = bauDate('So', d.datum, '11')
|
||||
grpstr = " "
|
||||
}
|
||||
if (isSmallScreen) {
|
||||
select += `
|
||||
<option value="${d.datum}" ${isselected} ${isFuehrung}> ${datstr} ${count || 0}B</option>`;
|
||||
} else {
|
||||
select += `
|
||||
<option value="${d.datum}" ${isselected} ${isFuehrung}> ${datstr} ${grpstr} ${count || 0} Besucher</option>`;
|
||||
}
|
||||
i++;
|
||||
summ += count ? parseInt(count) : 0;
|
||||
if (d.datum >= last) break;
|
||||
}
|
||||
select += `</select>
|
||||
<div id="gesamtsumme">Gesamtzahl der Anmeldungen (ab heute): ${summ}</div>`;
|
||||
|
||||
$('#auswahl').innerHTML = select;
|
||||
|
||||
$('#ftermin').addEventListener('change', async () => {
|
||||
const date = $('#ftermin').value;
|
||||
const index = $('#ftermin').selectedIndex;
|
||||
setVisibility('#absagen', index === 0);
|
||||
await showAktAnmeldungen(date);
|
||||
});
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
async function main(n) {
|
||||
let index = 0
|
||||
const today = DateTime.now().minus({ days: 14 }).toFormat("yyyyLLdd");
|
||||
const dates = await fetchFromDbase({cmd:'GET_DATES', anzahl:n, date: today});
|
||||
const last = await fetchFromDbase({cmd:'GET_LASTANMELDUNG', date: today});
|
||||
|
||||
let mq = window.matchMedia('(max-width: 800px)');
|
||||
isSmallScreen = mq.matches
|
||||
switchText();
|
||||
mq.addEventListener('change', async (e) => {
|
||||
isSmallScreen = e.matches
|
||||
switchText();
|
||||
await buildFuehrungsDates(dates, last);
|
||||
showAktAnmeldungen(actualdate);
|
||||
});
|
||||
|
||||
index = await buildFuehrungsDates(dates, last);
|
||||
|
||||
await showAktAnmeldungen(dates[index].datum);
|
||||
if (query.name !== 'Null') {
|
||||
await findName(query.name);
|
||||
}
|
||||
if (query.double) {
|
||||
await showDoubles(DateTime.now().toFormat("yyyyLLdd"));
|
||||
}
|
||||
}
|
||||
|
||||
main(ANZAHL_DATES).catch(console.error);
|
||||
});
|
||||
98
html/sternwarte/intern/anmeld/js/version.js
Normal file
98
html/sternwarte/intern/anmeld/js/version.js
Normal file
@@ -0,0 +1,98 @@
|
||||
// VersiosNummern und -Geschichte
|
||||
|
||||
const VERSION="1.8.1";
|
||||
const VDATE="2025-10-20";
|
||||
|
||||
/* History
|
||||
|
||||
Rev. Datum Entwickler
|
||||
|
||||
1.8.1 2025-10-19 rxf
|
||||
- Errormeldung, wenn bei 'anmeld.js' die Abmeldung nicht rausgeht
|
||||
|
||||
1.8.0 2025-10-17 rxf
|
||||
- intern Anmeldung kann nun mit Datum versehen werden (in der URL: &dateum=true), dass wird die
|
||||
Abmeldungn mit dem Datum versehen und es kann auch schon füher abgemeldet werden.
|
||||
- zusätzlicher Abmeldetext
|
||||
- der Mailer arbeitet nun mit der Adresse: sternwarte.welzheim@gmx.de (!)
|
||||
|
||||
1.7.3 2025-09-07 rxf
|
||||
- 'Laufschrift einschalten' wieder reingebaut, aber nicht bei Sonnenführung
|
||||
|
||||
1.7.2 2025-07-27 rxf
|
||||
- Selectzeile einfacher bei kleinem Display
|
||||
- statt moment nun luxor verwendet
|
||||
|
||||
1.7.1 2025-07-21 rxf
|
||||
- sonnef komplett entfernt - das ist nun komplett in anmeld.js mit drin
|
||||
- anmled.php umbenannt in index.php
|
||||
- Aufruf auf der internen Seite angepasst:
|
||||
- ../intern/anmeld/index.php - Anmeldungen zu regulären Führungen
|
||||
- ../intern/anmeld/index.php?typ=sonnen - Anmeldungen zu den Sonnenführungen
|
||||
|
||||
1.7.0 2025-07-07 rxf
|
||||
- umgestellt, so dass kein jquery und kein bootstrap mehr nötig ist (mit Hilfe von ChatGPT)
|
||||
- Absagegrund kann angewählt werden
|
||||
- Absagegrund liegt in der textDatei data/absagegruende.txt
|
||||
|
||||
1.63 2024-02-20 rxf
|
||||
- Erkennung von Dubletten verbessert
|
||||
|
||||
1.62 2024-02-04 rxf
|
||||
- Laufschrift einschalten, wenn Absage gesendet wird
|
||||
|
||||
1.61 2023-10-04 rxf
|
||||
- Anzeiger der Teilnehmer-Datails funktioniert wieder
|
||||
|
||||
1.60 2022-10-15 rxf
|
||||
- Probleme mit der Besucheranzahl gelöst (Anzahl IMMER aus der DB holen)
|
||||
|
||||
1.59 2022-05-29 rxf
|
||||
- bei sofianmeld.js 14 Tage vorher mit auswählen lassen
|
||||
|
||||
1.58 2021-12-01 rxf
|
||||
- Astroseminar Protokolle im internen bereich
|
||||
|
||||
1.57 2021-11-28 rxf
|
||||
- 'storniert' bei Anmeldungen eingeführt
|
||||
|
||||
1.56 2021-11-25 rxf
|
||||
- Senden von Mails nun via phpmailer (SMTP)
|
||||
|
||||
1.55 2021-09-21 rxf
|
||||
- Aufruf weiter schneller
|
||||
|
||||
1.54 2021-08-19 rxf
|
||||
- Aufbau der DB angepasst, damit schnellerer Aufruf
|
||||
- Anzeige der Gesamzanzahl der zukünftigen Anmeldungen
|
||||
- Daten ohne Führung hellgrau anzeigen
|
||||
1.53 2021-08-08 rxf
|
||||
- Absage-Mail per PHP-Call
|
||||
|
||||
1.52 2021-08-03 rxf
|
||||
- Anzeige von 30 Führungstagen
|
||||
|
||||
1.5 2021-07-29 rxf
|
||||
- Name der führenden Gruppe dazu
|
||||
|
||||
1.4 2021-07-25 rxf
|
||||
- Anzahl der angemeldeten Besucher mit anzeigen
|
||||
|
||||
1.3 2020-10-11 rxf
|
||||
- Anzeige-Dialog bei teilgenonnen Speicher nun OK
|
||||
|
||||
1.3 2020-10-11 rxf
|
||||
- 'teilgenommen' wird nun richtig angezeigt
|
||||
|
||||
1.2 2020-10-07 rxf
|
||||
- Wenn die Absage-Mail schon raus ist, dann dieses melden
|
||||
|
||||
1.1 2020-10-05 rxf
|
||||
- Möglichkeit, an Alle eine Absage-Mail zu senden, eingebaut
|
||||
|
||||
1.0 2020-10-09 rxf
|
||||
- Erste fertige Version. Geht so zum Testen an rexfue.de
|
||||
|
||||
0.00 2020-09-20 rxf
|
||||
- Los gehts
|
||||
*/
|
||||
89
html/sternwarte/intern/anmeld/js/version.js_o
Normal file
89
html/sternwarte/intern/anmeld/js/version.js_o
Normal file
@@ -0,0 +1,89 @@
|
||||
// VersiosNummern und -Geschichte
|
||||
|
||||
const VERSION="1.7.3";
|
||||
const VDATE="2025-09-06";
|
||||
|
||||
/* History
|
||||
|
||||
Rev. Datum Entwickler
|
||||
|
||||
1.7.3 2025-09-06 rxf
|
||||
- 'Laufschrift einschalten' wieder reingebaut
|
||||
|
||||
1.7.2 2025-07-27 rxf
|
||||
- Selectzeile einfacher bei kleinem Display
|
||||
- statt moment nun luxor verwendet
|
||||
|
||||
1.7.1 2025-07-21 rxf
|
||||
- sonnef komplett entfernt - das ist nun komplett in anmeld.js mit drin
|
||||
- anmled.php umbenannt in index.php
|
||||
- Aufruf auf der internen Seite angepasst:
|
||||
- ../intern/anmeld/index.php - Anmeldungen zu regulären Führungen
|
||||
- ../intern/anmeld/index.php?typ=sonnen - Anmeldungen zu den Sonnenführungen
|
||||
|
||||
1.7.0 2025-07-07 rxf
|
||||
- umgestellt, so dass kein jquery und kein bootstrap mehr nötig ist (mit Hilfe von ChatGPT)
|
||||
- Absagegrund kann angewählt werden
|
||||
- Absagegrund liegt in der textDatei data/absagegruende.txt
|
||||
|
||||
1.63 2024-02-20 rxf
|
||||
- Erkennung von Dubletten verbessert
|
||||
|
||||
1.62 2024-02-04 rxf
|
||||
- Laufschrift einschalten, wenn Absage gesendet wird
|
||||
|
||||
1.61 2023-10-04 rxf
|
||||
- Anzeiger der Teilnehmer-Datails funktioniert wieder
|
||||
|
||||
1.60 2022-10-15 rxf
|
||||
- Probleme mit der Besucheranzahl gelöst (Anzahl IMMER aus der DB holen)
|
||||
|
||||
1.59 2022-05-29 rxf
|
||||
- bei sofianmeld.js 14 Tage vorher mit auswählen lassen
|
||||
|
||||
1.58 2021-12-01 rxf
|
||||
- Astroseminar Protokolle im internen bereich
|
||||
|
||||
1.57 2021-11-28 rxf
|
||||
- 'storniert' bei Anmeldungen eingeführt
|
||||
|
||||
1.56 2021-11-25 rxf
|
||||
- Senden von Mails nun via phpmailer (SMTP)
|
||||
|
||||
1.55 2021-09-21 rxf
|
||||
- Aufruf weiter schneller
|
||||
|
||||
1.54 2021-08-19 rxf
|
||||
- Aufbau der DB angepasst, damit schnellerer Aufruf
|
||||
- Anzeige der Gesamzanzahl der zukünftigen Anmeldungen
|
||||
- Daten ohne Führung hellgrau anzeigen
|
||||
1.53 2021-08-08 rxf
|
||||
- Absage-Mail per PHP-Call
|
||||
|
||||
1.52 2021-08-03 rxf
|
||||
- Anzeige von 30 Führungstagen
|
||||
|
||||
1.5 2021-07-29 rxf
|
||||
- Name der führenden Gruppe dazu
|
||||
|
||||
1.4 2021-07-25 rxf
|
||||
- Anzahl der angemeldeten Besucher mit anzeigen
|
||||
|
||||
1.3 2020-10-11 rxf
|
||||
- Anzeige-Dialog bei teilgenonnen Speicher nun OK
|
||||
|
||||
1.3 2020-10-11 rxf
|
||||
- 'teilgenommen' wird nun richtig angezeigt
|
||||
|
||||
1.2 2020-10-07 rxf
|
||||
- Wenn die Absage-Mail schon raus ist, dann dieses melden
|
||||
|
||||
1.1 2020-10-05 rxf
|
||||
- Möglichkeit, an Alle eine Absage-Mail zu senden, eingebaut
|
||||
|
||||
1.0 2020-10-09 rxf
|
||||
- Erste fertige Version. Geht so zum Testen an rexfue.de
|
||||
|
||||
0.00 2020-09-20 rxf
|
||||
- Los gehts
|
||||
*/
|
||||
366
html/sternwarte/intern/anmeld/php/anmeldDB.php
Normal file
366
html/sternwarte/intern/anmeld/php/anmeldDB.php
Normal file
@@ -0,0 +1,366 @@
|
||||
<?php
|
||||
# Hier werden die Anfragen vom Javascript verarbeitet und die
|
||||
# Datenbank bedient
|
||||
|
||||
include '../../../config_stern.php';
|
||||
include '../../../phpmailer/dosendmail.php';
|
||||
|
||||
$table = 'SoFue2';
|
||||
|
||||
// Holen der Einträge in der anmelde-Datenbank für den selektierten Tag
|
||||
// Parameter
|
||||
// $special -> was muss geholt werden
|
||||
// $date -> Datum, für das geholt wird
|
||||
//
|
||||
// Return:
|
||||
// Array mit den Einträgen
|
||||
function getAnmeldungenNew($special, $date)
|
||||
{
|
||||
global $db;
|
||||
$retur = [];
|
||||
$retur['error'] = false;
|
||||
$retur['errortext'] = '';
|
||||
$erg = array();
|
||||
if ($special == 'total') {
|
||||
$sql_stmt = "SELECT * FROM anmeldungen";
|
||||
} else if ($special == 'all') {
|
||||
$sql_stmt = "SELECT * FROM anmeldungen WHERE name != '-'";
|
||||
} else if ($special == 'abgesagt') {
|
||||
$sql_stmt = "SELECT * FROM anmeldungen WHERE abgesagt=1 AND name != '-'";
|
||||
} else if ($special == 'nichtda') {
|
||||
$sql_stmt = "SELECT * FROM anmeldungen WHERE DATE_ADD(DATE(fdatum),INTERVAL 1 DAY)<=DATE(NOW()) AND teilgenommen = 0 AND name != '-'";
|
||||
} else if ($special == 'zualt') {
|
||||
$sql_stmt = "SELECT * FROM anmeldungen WHERE DATE_ADD(DATE(fdatum),INTERVAL $date DAY)<=DATE(NOW()) AND name != '-'";
|
||||
} else if ($special == 'alllater'){
|
||||
$sql_stmt = "SELECT * FROM anmeldungen WHERE fdatum > '$date' AND name != '-' ORDER BY fdatum";
|
||||
} else if ($special == 'normal'){
|
||||
$sql_stmt = "SELECT * FROM anmeldungen WHERE fdatum = '$date'";
|
||||
} else {
|
||||
$retur['error'] = 'false';
|
||||
$retur['errortext'] = 'Falsches SELECT Statement!';
|
||||
$retur['data'] = [];
|
||||
return $retur;
|
||||
}
|
||||
$result = mysqli_query($db, $sql_stmt) or die(mysqli_error($db));
|
||||
while ($row = mysqli_fetch_assoc($result)) {
|
||||
foreach($row as $key => $value) {
|
||||
$entry[$key] = $value;
|
||||
}
|
||||
$erg[] = $entry;
|
||||
}
|
||||
$retur['data'] = $erg;
|
||||
return $retur;
|
||||
}
|
||||
|
||||
// Holen der Einträge in der anmelde-Datenbank für den selektierten Tag
|
||||
// Parameter
|
||||
// $special -> was muss geholt werden
|
||||
// $date -> Datum, für das geholt wird
|
||||
//
|
||||
// Return:
|
||||
// Array mit den Einträgen
|
||||
function getSonderNew($special, $date)
|
||||
{
|
||||
global $db;
|
||||
$retur = [];
|
||||
$retur['error'] = false;
|
||||
$retur['errortext'] = '';
|
||||
$erg = array();
|
||||
/* if ($special == 'total') {
|
||||
$sql_stmt = "SELECT * FROM anmeldungen";
|
||||
} else if ($special == 'all') {
|
||||
$sql_stmt = "SELECT * FROM anmeldungen WHERE name != '-'";
|
||||
} else if ($special == 'abgesagt') {
|
||||
$sql_stmt = "SELECT * FROM anmeldungen WHERE abgesagt=1 AND name != '-'";
|
||||
} else if ($special == 'nichtda') {
|
||||
$sql_stmt = "SELECT * FROM anmeldungen WHERE DATE_ADD(DATE(fdatum),INTERVAL 1 DAY)<=DATE(NOW()) AND teilgenommen = 0 AND name != '-'";
|
||||
} else if ($special == 'zualt') {
|
||||
$sql_stmt = "SELECT * FROM anmeldungen WHERE DATE_ADD(DATE(fdatum),INTERVAL $date DAY)<=DATE(NOW()) AND name != '-'";
|
||||
} else
|
||||
*/ if ($special == 'alllater'){
|
||||
$sql_stmt = "SELECT * FROM SoFue2 WHERE wtermin > '$date' ORDER BY wtermin";
|
||||
// } else if ($special == 'normal'){
|
||||
// $sql_stmt = "SELECT * FROM anmeldungen WHERE fdatum = '$date'";
|
||||
} else {
|
||||
$retur['error'] = 'false';
|
||||
$retur['errortext'] = 'Falsches SELECT Statement!';
|
||||
$retur['data'] = [];
|
||||
return $retur;
|
||||
}
|
||||
$result = mysqli_query($db, $sql_stmt) or die(mysqli_error($db));
|
||||
while ($row = mysqli_fetch_assoc($result)) {
|
||||
foreach($row as $key => $value) {
|
||||
$entry[$key] = $value;
|
||||
}
|
||||
$erg[] = $entry;
|
||||
}
|
||||
$retur['data'] = $erg;
|
||||
return $retur;
|
||||
}
|
||||
|
||||
// Holen der Einträge in der anmelde-Datenbank für den selektierten Tag
|
||||
// Parameter
|
||||
// $date -> so für dieses Datum die Einträge holen
|
||||
// Retunrn:
|
||||
// Array mit den Einträgen
|
||||
function getAnmeldungen($date)
|
||||
{
|
||||
global $db;
|
||||
$erg = array();
|
||||
$sql_stmt = "SELECT * FROM anmeldungen WHERE fdatum = '$date'";
|
||||
$result = mysqli_query($db, $sql_stmt) or die(mysqli_error($db));
|
||||
while ($row = mysqli_fetch_assoc($result)) {
|
||||
foreach($row as $key => $value) {
|
||||
$entry[$key] = $value;
|
||||
}
|
||||
$erg[] = $entry;
|
||||
}
|
||||
return $erg;
|
||||
}
|
||||
|
||||
// Daten eines Teilnehmers abholen
|
||||
// Parameter:
|
||||
// $id: Teilnehmer - ID
|
||||
// Return:
|
||||
// Dict mit allen Daten des Teilnehmers
|
||||
function getTeilnehmer($id)
|
||||
{
|
||||
global $db;
|
||||
$erg = array();
|
||||
$sql_stmt = "SELECT * FROM anmeldungen WHERE id='$id'";
|
||||
$result = mysqli_query($db, $sql_stmt) or die(mysqli_error($db));
|
||||
while ($row = mysqli_fetch_assoc($result)) {
|
||||
foreach ($row as $key => $value) {
|
||||
$entry[$key] = $value;
|
||||
}
|
||||
$erg[] = $entry;
|
||||
}
|
||||
return $erg;
|
||||
}
|
||||
|
||||
// Daten eines Teilnehmers abholen
|
||||
// Parameter:
|
||||
// $name: Name oder Vorname des Teilnehmers
|
||||
// Return:
|
||||
// Dict mit allen Daten des Teilnehmers
|
||||
function getTeilnehmerByName($name)
|
||||
{
|
||||
global $db;
|
||||
$erg = array();
|
||||
$sql_stmt = "SELECT * FROM anmeldungen WHERE name ='$name' || vorname = '$name'";
|
||||
$result = mysqli_query($db, $sql_stmt) or die(mysqli_error($db));
|
||||
while ($row = mysqli_fetch_assoc($result)) {
|
||||
foreach ($row as $key => $value) {
|
||||
$entry[$key] = $value;
|
||||
}
|
||||
$erg[] = $entry;
|
||||
}
|
||||
return $erg;
|
||||
}
|
||||
|
||||
// Die Daten der nächsten $soviel Führungen ab dem Datum $ab in ein Array holen
|
||||
// Parameter
|
||||
// $soviel -> so viele Einträge ab jetzt holen
|
||||
// $ab -> Startdatum
|
||||
// Retunrn:
|
||||
// Array mit allen Werte aus der Table
|
||||
function getNextFuehrungen($soviel, $ab) {
|
||||
global $db;
|
||||
$erg = array();
|
||||
// $datum_heute = date("Ymd",strtotime("-1 days"));
|
||||
$sql_sel = "SELECT * FROM fdatum1 where datum >='$ab' order by datum ASC LIMIT $soviel";
|
||||
$result = mysqli_query($db, $sql_sel) or die(mysqli_error($db));
|
||||
while ($row = mysqli_fetch_assoc($result)) {
|
||||
foreach ($row as $key => $value) {
|
||||
$entry[$key] = $value;
|
||||
}
|
||||
$erg[] = $entry;
|
||||
}
|
||||
return $erg;
|
||||
}
|
||||
|
||||
// Das Datum der letzen Anmeldung suchen und übergeben
|
||||
// Parameter
|
||||
// $date -> Startdatum
|
||||
// Retunrn:
|
||||
// Datum der letzten Anmeldung
|
||||
function getLastAnmeldung($date) {
|
||||
global $db;
|
||||
$erg = array();
|
||||
// $datum_heute = date("Ymd",strtotime("-1 days"));
|
||||
$sql_sel = "SELECT MAX(fdatum) AS lastdate FROM anmeldungen WHERE fdatum >= '$date' and anzahl != 0";
|
||||
$result = mysqli_query($db, $sql_sel) or die(mysqli_error($db));
|
||||
$row = mysqli_fetch_row($result);
|
||||
return $row[0];
|
||||
}
|
||||
|
||||
// Bezeichnung der Gruppe für das übergeben Datum holen
|
||||
// Parameter:
|
||||
// $date -> Datum/Zeit (YYY-MM-DD HH:mm:ss), für das die Gruppe geholt werden soll
|
||||
// Return: Bezeichnung der Gruppe
|
||||
function getGroup($date) {
|
||||
global $db;
|
||||
global $db;
|
||||
$sql_stmt = "SELECT grp FROM fdates WHERE dateTime = '$date'";
|
||||
$result = mysqli_query($db, $sql_stmt) or die(mysqli_error($db));
|
||||
$data = mysqli_fetch_assoc($result);
|
||||
return $data['grp'] ;
|
||||
}
|
||||
|
||||
// Zählen, wieviele Personen zu einem Führungstermin angemeldet sind
|
||||
// Parameter:
|
||||
// $fid -> id des Führungsdatum
|
||||
// Return: Anzahl der Personen
|
||||
function getCountsPerDate($fdate) {
|
||||
global $db;
|
||||
$sql_stmt = "SELECT SUM(anzahl) AS count FROM anmeldungen WHERE fdatum='$fdate'";
|
||||
$result = mysqli_query($db, $sql_stmt) or die(mysqli_error($db));
|
||||
$data = mysqli_fetch_assoc($result);
|
||||
return $data['count'] ;
|
||||
}
|
||||
|
||||
function updateentries($nr,$val,$field)
|
||||
{
|
||||
global $db;
|
||||
$result = false;
|
||||
for ($i = 0; $i < count($nr); $i++) {
|
||||
$sql_stmt = "UPDATE anmeldungen SET $field=$val[0] where id=$nr[$i]";
|
||||
$result = mysqli_query($db, $sql_stmt) or die(mysqli_error($db));
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
function updateCount($date, $anzahl) {
|
||||
global $db;
|
||||
$sql_stmt = "UPDATE fdatum1 SET count=count-$anzahl WHERE datum=$date AND count >0";
|
||||
$result = mysqli_query($db, $sql_stmt) or die(mysqli_error($db));
|
||||
return $result;
|
||||
}
|
||||
|
||||
function deleteOne($id) {
|
||||
global $db;
|
||||
$sql_stmt = "DELETE FROM anmeldungen WHERE id=$id";
|
||||
$result = mysqli_query($db, $sql_stmt) or die(mysqli_error($db));
|
||||
return $result;
|
||||
}
|
||||
|
||||
function findDoubles($dat) {
|
||||
global $db;
|
||||
$sql_stmt = "SELECT * FROM anmeldungen INNER JOIN (SELECT vorname,name FROM anmeldungen " .
|
||||
"GROUP BY vorname,name HAVING COUNT(id) > 1 ) dup ON anmeldungen.name = dup.name && anmeldungen.vorname = dup.vorname";
|
||||
$result = mysqli_query($db, $sql_stmt) or die(mysqli_error($db));
|
||||
while ($row = mysqli_fetch_assoc($result)) {
|
||||
foreach ($row as $key => $value) {
|
||||
$entry[$key] = $value;
|
||||
}
|
||||
$erg[] = $entry;
|
||||
}
|
||||
return $erg;
|
||||
}
|
||||
|
||||
function sendmymail($to, $betreff, $body, $bcc)
|
||||
{
|
||||
$absender = "noreply@sternwarte-welzheim.de";
|
||||
$lst = "";
|
||||
foreach($bcc as $b) {
|
||||
$lst = $lst . trim($b) . ',';
|
||||
}
|
||||
$lst = substr($lst,0,-1);
|
||||
|
||||
$headers = array();
|
||||
$headers[] = "MIME-Version: 1.0";
|
||||
$headers[] = "Content-type: text/plain; charset=utf-8";
|
||||
$headers[] = "From: {$absender}";
|
||||
$headers[] = "X-Mailer: PHP/" . phpversion();
|
||||
$headers[] = "Reply-To: {$absender}";
|
||||
$headers[] = "Bcc: {$lst}" . ",rxf@fuerst-stuttgart.de";
|
||||
|
||||
mail($to, $betreff, $body, implode("\r\n", $headers), "-f noreply@sternwarte-welzheim.de");
|
||||
return "OK";
|
||||
}
|
||||
|
||||
|
||||
$_POST = json_decode(file_get_contents('php://input'), true);
|
||||
|
||||
$erg = "";
|
||||
$cmd = $_POST["cmd"];
|
||||
|
||||
/*
|
||||
$x = "#-->";
|
||||
foreach ($_POST as $key => $value) {
|
||||
$x = $x . $key . " <> " . $value . "\n";
|
||||
}
|
||||
$x = $x . '# ';
|
||||
echo $x;
|
||||
var_dump($_POST);
|
||||
*/
|
||||
|
||||
switch ($cmd) {
|
||||
case 'GET_ANMELD':
|
||||
$erg = getAnmeldungen($_POST['id']);
|
||||
break;
|
||||
|
||||
case 'GET_ANMELDNEW':
|
||||
$erg = getAnmeldungenNew($_POST['special'], $_POST['date']);
|
||||
break;
|
||||
|
||||
case 'GET_SONDERNEW':
|
||||
$erg = getSonderNew($_POST['special'], $_POST['date']);
|
||||
break;
|
||||
|
||||
case 'GET_TEILN_ID':
|
||||
$erg = getTeilnehmer($_POST['id']);
|
||||
break;
|
||||
|
||||
case 'GET_TEILN_NAME':
|
||||
$erg = getTeilnehmerByName($_POST['name']);
|
||||
break;
|
||||
|
||||
case 'GET_GROUP':
|
||||
$erg = getGroup($_POST['date']);
|
||||
break;
|
||||
|
||||
case 'GET_DATES':
|
||||
$erg = getNextFuehrungen($_POST['anzahl'], $_POST['date']);
|
||||
break;
|
||||
|
||||
case 'GET_COUNTS':
|
||||
$erg = getCountsPerDate($_POST['fdate']);
|
||||
break;
|
||||
|
||||
case 'GET_LASTANMELDUNG':
|
||||
$erg = getLastAnmeldung($_POST['date']);
|
||||
break;
|
||||
|
||||
case 'UPDATE':
|
||||
$erg = "Nix gut";
|
||||
if ((count($_POST['ids']) != 0) and (count($_POST['values']) != 0)) {
|
||||
$rows = $_POST['ids'];
|
||||
$values = $_POST['values'];
|
||||
$erg = updateEntries($rows, $values, $_POST['field']);
|
||||
}
|
||||
break;
|
||||
case 'UPDATECOUNT':
|
||||
$erg = updateCount($_POST['date'], $_POST['anzahl']);
|
||||
break;
|
||||
|
||||
case 'DELETEONE':
|
||||
$erg = deleteOne($_POST['id']);
|
||||
break;
|
||||
|
||||
case 'DOUBLE':
|
||||
$erg = findDoubles($_POST['date']);
|
||||
break;
|
||||
|
||||
case 'SENDMYMAIL':
|
||||
$erg = sendmail($_POST['betreff'], $defaultabsender, $_POST['body'], [], $_POST['bcc'], $_POST['to']);
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
header("Content-type: text/json;charset=utf-8");
|
||||
|
||||
echo json_encode($erg);
|
||||
|
||||
|
||||
|
||||
2
html/sternwarte/intern/anmeld/php/input
Normal file
2
html/sternwarte/intern/anmeld/php/input
Normal file
@@ -0,0 +1,2 @@
|
||||
cmd=GET_DATES
|
||||
anzahl=10
|
||||
8
html/sternwarte/intern/anmeld/remove4weeks/.idea/.gitignore
generated
vendored
Normal file
8
html/sternwarte/intern/anmeld/remove4weeks/.idea/.gitignore
generated
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
# Default ignored files
|
||||
/shelf/
|
||||
/workspace.xml
|
||||
# Datasource local storage ignored files
|
||||
/dataSources/
|
||||
/dataSources.local.xml
|
||||
# Editor-based HTTP Client requests
|
||||
/httpRequests/
|
||||
6
html/sternwarte/intern/anmeld/remove4weeks/.idea/encodings.xml
generated
Normal file
6
html/sternwarte/intern/anmeld/remove4weeks/.idea/encodings.xml
generated
Normal file
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="Encoding">
|
||||
<file url="PROJECT" charset="UTF-8" />
|
||||
</component>
|
||||
</project>
|
||||
12
html/sternwarte/intern/anmeld/remove4weeks/.idea/inspectionProfiles/Project_Default.xml
generated
Normal file
12
html/sternwarte/intern/anmeld/remove4weeks/.idea/inspectionProfiles/Project_Default.xml
generated
Normal file
@@ -0,0 +1,12 @@
|
||||
<component name="InspectionProjectProfileManager">
|
||||
<profile version="1.0">
|
||||
<option name="myName" value="Project Default" />
|
||||
<inspection_tool class="PyPep8Inspection" enabled="true" level="WEAK WARNING" enabled_by_default="true">
|
||||
<option name="ignoredErrors">
|
||||
<list>
|
||||
<option value="E501" />
|
||||
</list>
|
||||
</option>
|
||||
</inspection_tool>
|
||||
</profile>
|
||||
</component>
|
||||
7
html/sternwarte/intern/anmeld/remove4weeks/.idea/misc.xml
generated
Normal file
7
html/sternwarte/intern/anmeld/remove4weeks/.idea/misc.xml
generated
Normal file
@@ -0,0 +1,7 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="JavaScriptSettings">
|
||||
<option name="languageLevel" value="ES6" />
|
||||
</component>
|
||||
<component name="ProjectRootManager" version="2" project-jdk-name="Python 3.7 (remove4weeks)" project-jdk-type="Python SDK" />
|
||||
</project>
|
||||
8
html/sternwarte/intern/anmeld/remove4weeks/.idea/modules.xml
generated
Normal file
8
html/sternwarte/intern/anmeld/remove4weeks/.idea/modules.xml
generated
Normal file
@@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ProjectModuleManager">
|
||||
<modules>
|
||||
<module fileurl="file://$PROJECT_DIR$/.idea/remove4weeks.iml" filepath="$PROJECT_DIR$/.idea/remove4weeks.iml" />
|
||||
</modules>
|
||||
</component>
|
||||
</project>
|
||||
13
html/sternwarte/intern/anmeld/remove4weeks/.idea/remove4weeks.iml
generated
Normal file
13
html/sternwarte/intern/anmeld/remove4weeks/.idea/remove4weeks.iml
generated
Normal file
@@ -0,0 +1,13 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module type="PYTHON_MODULE" version="4">
|
||||
<component name="NewModuleRootManager">
|
||||
<content url="file://$MODULE_DIR$">
|
||||
<excludeFolder url="file://$MODULE_DIR$/venv" />
|
||||
</content>
|
||||
<orderEntry type="inheritedJdk" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
</component>
|
||||
<component name="TestRunnerService">
|
||||
<option name="PROJECT_TEST_RUNNER" value="Unittests" />
|
||||
</component>
|
||||
</module>
|
||||
7
html/sternwarte/intern/anmeld/remove4weeks/.idea/sqldialects.xml
generated
Normal file
7
html/sternwarte/intern/anmeld/remove4weeks/.idea/sqldialects.xml
generated
Normal file
@@ -0,0 +1,7 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="SqlDialectMappings">
|
||||
<file url="file://$PROJECT_DIR$/main.py" dialect="GenericSQL" />
|
||||
<file url="PROJECT" dialect="MySQL" />
|
||||
</component>
|
||||
</project>
|
||||
6
html/sternwarte/intern/anmeld/remove4weeks/.idea/vcs.xml
generated
Normal file
6
html/sternwarte/intern/anmeld/remove4weeks/.idea/vcs.xml
generated
Normal file
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="VcsDirectoryMappings">
|
||||
<mapping directory="$PROJECT_DIR$" vcs="Git" />
|
||||
</component>
|
||||
</project>
|
||||
2
html/sternwarte/intern/anmeld/remove4weeks/Read.me
Normal file
2
html/sternwarte/intern/anmeld/remove4weeks/Read.me
Normal file
@@ -0,0 +1,2 @@
|
||||
Das scriopt dp_cron.sh wird per ssh von 'nuccy' aus gestartet
|
||||
|
||||
7
html/sternwarte/intern/anmeld/remove4weeks/do_cron.sh
Executable file
7
html/sternwarte/intern/anmeld/remove4weeks/do_cron.sh
Executable file
@@ -0,0 +1,7 @@
|
||||
#! /bin/bash
|
||||
cd /kunden/310927_70173/sternwarte/intern/anmeld/remove4weeks
|
||||
source ./virtenv/bin/activate
|
||||
python3 main.py >>main_py.log 2>&1
|
||||
deactivate
|
||||
cd
|
||||
|
||||
174
html/sternwarte/intern/anmeld/remove4weeks/main.py
Normal file
174
html/sternwarte/intern/anmeld/remove4weeks/main.py
Normal file
@@ -0,0 +1,174 @@
|
||||
"""
|
||||
main.py für remove4weeks
|
||||
|
||||
Checked per cron jeden Tag die 'anmeldungen'-Tabelle in der Datenbank.
|
||||
Prüft für jeden Teilnehmer ob
|
||||
- entweder die Führung abgesagt wurde
|
||||
- oder 4 Wochen seit der teilgenommenen Führung vergangen sind.
|
||||
Ist das der Fall, werden die persönlichen Daten des Teilnehmers mit '-' in der
|
||||
Datenbank überschrieben.
|
||||
|
||||
TODO
|
||||
- Statistik-Daten behalten: Anzahl der Anfragen, davon zugesagt, davon abgesagt und
|
||||
ggf. in eine eigenen Tabelle merken
|
||||
|
||||
|
||||
Versions:
|
||||
V 1.3 2022-12-08 rxf
|
||||
- 'abgesagte' werden nicht mehgr gelöscht
|
||||
|
||||
V 1.2 2022-11-03 rxf
|
||||
- 'nicht teilgenomme' werden nicht mehr behandelt
|
||||
- SELECT nun nur noch über fdatum der anmelden-Tabelle
|
||||
|
||||
V 1.1 2020-10-14 rxf
|
||||
- Löschen der reihe nach: erst abgesagt, dann 'nicht teolgenommen' und
|
||||
dann älter als 4 Wochen
|
||||
|
||||
V 1.0 2020-10-10 rxf
|
||||
- erste live gestellte Version
|
||||
|
||||
V 0.0 2020-10-08 rxf
|
||||
- Start
|
||||
"""
|
||||
|
||||
from datetime import datetime, timedelta, date
|
||||
import mysql.connector
|
||||
from mysql.connector import errorcode
|
||||
import os
|
||||
|
||||
# Versionsnummer und Date
|
||||
VERSION="1.3"
|
||||
VDATE="2022-12-08"
|
||||
|
||||
# Wie viele Tage müssen vergangen sein, damit gelöscht wird?
|
||||
# default = 28
|
||||
VTAGE = 28
|
||||
|
||||
# $host = 'localhost';
|
||||
# $user = 'db310927';
|
||||
# $pass = 'ArktUhr';
|
||||
# $dbase = 'db310927';
|
||||
|
||||
|
||||
# Definitionen für die Datenbank
|
||||
unix_socket=" /var/lib/mysql/mysql.sock"
|
||||
host = 'localhost'
|
||||
user = 'db310927'
|
||||
#password = 'ArktUhr'
|
||||
password = 'vetivene-albarco-earner'
|
||||
dbase = 'db310927'
|
||||
|
||||
if os.environ.get('STWANMELD') == '1':
|
||||
host = "localhost"
|
||||
user = "root"
|
||||
password = "SFluorit"
|
||||
dbase = "sternwarte"
|
||||
|
||||
|
||||
def updateentry(db, id):
|
||||
""" Update den Eintrag mit der ID id: es werden alle
|
||||
persönlichen Daten mit '-' überschreiben"""
|
||||
|
||||
mycursor = db.cursor()
|
||||
dash = '"-"'
|
||||
sql = "UPDATE anmeldungen SET " + \
|
||||
"name=" + dash + ", vorname=" + dash + ", email=" + dash + ", telefon=" + dash + ", plz=0, strasse=" + dash + ", stadt=" + dash + \
|
||||
", remarks = '' WHERE id=\"" + str(id) + "\""
|
||||
# logit(sql)
|
||||
mycursor.execute(sql)
|
||||
db.commit()
|
||||
return mycursor.rowcount
|
||||
|
||||
|
||||
|
||||
def removeabgesagte(db):
|
||||
""" Alle abgesagten Teilnehmer finden und deren IDs übergeben """
|
||||
abgesagte = []
|
||||
mycursor = db.cursor()
|
||||
delcount = 0
|
||||
|
||||
sql = "SELECT id FROM anmeldungen WHERE abgesagt=1 AND name != '-'"
|
||||
mycursor.execute(sql)
|
||||
myresult = mycursor.fetchall()
|
||||
logstr = "Abgesagt: "
|
||||
for x in myresult:
|
||||
logstr += str(x[0]) + ','
|
||||
abgesagte.append(x[0])
|
||||
delcount += updateentry(db, x[0])
|
||||
logit(logstr)
|
||||
logit('Anzahl Abgesagte: ' + str(delcount))
|
||||
return delcount
|
||||
|
||||
# def removeNICHTteilgenommene(db):
|
||||
# """ Alle Teilnehmer holen, die bei der gestrigen Führung
|
||||
# zwar angemeldet waren aber nicht teilgenommen haben. """
|
||||
# nichtteilg = []
|
||||
# mycursor = db.cursor()
|
||||
# delcount = 0
|
||||
# sql = "SELECT anmeldungen.id FROM anmeldungen INNER JOIN fdatum ON anmeldungen.fid=fdatum.id WHERE DATE_ADD(DATE(fdatum.datum),INTERVAL 1 DAY)<=DATE(NOW()) AND teilgenommen = 0 AND name != '-'"
|
||||
# mycursor.execute(sql)
|
||||
# myresult = mycursor.fetchall()
|
||||
# logstr = "Nicht teilgenommen: "
|
||||
# for x in myresult:
|
||||
# logstr += str(x[0]) + ','
|
||||
# nichtteilg.append(x[0])
|
||||
# delcount += updateentry(db, x[0])
|
||||
# logit(logstr)
|
||||
# return delcount
|
||||
|
||||
|
||||
def remove4weekold(db):
|
||||
""" Alle Teilnehmer IDs holen, die vor 4 Wochen bei einer Führung waren
|
||||
bzw. für eine Führung angemeldet waren"""
|
||||
mustdelete = []
|
||||
mycursor = db.cursor()
|
||||
delcount = 0
|
||||
|
||||
sql = "SELECT id FROM anmeldungen WHERE DATE_ADD(DATE(fdatum),INTERVAL " + str(VTAGE) + " DAY)<=DATE(NOW()) AND name != '-'"
|
||||
mycursor.execute(sql)
|
||||
myresult = mycursor.fetchall()
|
||||
logstr = "4 Wochen alt: "
|
||||
for x in myresult:
|
||||
logstr += str(x) + ','
|
||||
mustdelete.append(x[0])
|
||||
delcount += updateentry(db, x[0])
|
||||
logit(logstr)
|
||||
logit('Anazhl 4 Wochen alte: : ' + str(delcount))
|
||||
return delcount
|
||||
|
||||
|
||||
def logit(arg):
|
||||
""" Ausgabe der Parameter mit einen Zeitstempel"""
|
||||
now = datetime.now()
|
||||
out = now.strftime("%Y-%m-%d %H:%M:%S") + " - " + arg
|
||||
print(out)
|
||||
|
||||
|
||||
def main():
|
||||
logit('Start - Version ' + VERSION + " vom " + VDATE)
|
||||
try:
|
||||
mydb = mysql.connector.connect(
|
||||
unix_socket=unix_socket,
|
||||
# host=host,
|
||||
user=user,
|
||||
password=password,
|
||||
database=dbase
|
||||
)
|
||||
# acount = removeabgesagte(mydb)
|
||||
# count += removeNICHTteilgenommene(mydb)
|
||||
bcount = remove4weekold(mydb)
|
||||
logit('Geloescht wurden ' + str(bcount) + ' Eintraege.')
|
||||
|
||||
except mysql.connector.Error as err:
|
||||
if err.errno == errorcode.ER_ACCESS_DENIED_ERROR:
|
||||
print("Something is wrong with your user name or password")
|
||||
elif err.errno == errorcode.ER_BAD_DB_ERROR:
|
||||
print("Database does not exist")
|
||||
else:
|
||||
print(err)
|
||||
logit("End\n");
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
|
||||
6250
html/sternwarte/intern/anmeld/remove4weeks/main_py.log
Normal file
6250
html/sternwarte/intern/anmeld/remove4weeks/main_py.log
Normal file
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,76 @@
|
||||
# This file must be used with "source bin/activate" *from bash*
|
||||
# you cannot run it directly
|
||||
|
||||
deactivate () {
|
||||
# reset old environment variables
|
||||
if [ -n "${_OLD_VIRTUAL_PATH:-}" ] ; then
|
||||
PATH="${_OLD_VIRTUAL_PATH:-}"
|
||||
export PATH
|
||||
unset _OLD_VIRTUAL_PATH
|
||||
fi
|
||||
if [ -n "${_OLD_VIRTUAL_PYTHONHOME:-}" ] ; then
|
||||
PYTHONHOME="${_OLD_VIRTUAL_PYTHONHOME:-}"
|
||||
export PYTHONHOME
|
||||
unset _OLD_VIRTUAL_PYTHONHOME
|
||||
fi
|
||||
|
||||
# This should detect bash and zsh, which have a hash command that must
|
||||
# be called to get it to forget past commands. Without forgetting
|
||||
# past commands the $PATH changes we made may not be respected
|
||||
if [ -n "${BASH:-}" -o -n "${ZSH_VERSION:-}" ] ; then
|
||||
hash -r
|
||||
fi
|
||||
|
||||
if [ -n "${_OLD_VIRTUAL_PS1:-}" ] ; then
|
||||
PS1="${_OLD_VIRTUAL_PS1:-}"
|
||||
export PS1
|
||||
unset _OLD_VIRTUAL_PS1
|
||||
fi
|
||||
|
||||
unset VIRTUAL_ENV
|
||||
if [ ! "$1" = "nondestructive" ] ; then
|
||||
# Self destruct!
|
||||
unset -f deactivate
|
||||
fi
|
||||
}
|
||||
|
||||
# unset irrelevant variables
|
||||
deactivate nondestructive
|
||||
|
||||
VIRTUAL_ENV="/kunden/310927_70173/sternwarte/intern/anmeld/remove4weeks/virtenv"
|
||||
export VIRTUAL_ENV
|
||||
|
||||
_OLD_VIRTUAL_PATH="$PATH"
|
||||
PATH="$VIRTUAL_ENV/bin:$PATH"
|
||||
export PATH
|
||||
|
||||
# unset PYTHONHOME if set
|
||||
# this will fail if PYTHONHOME is set to the empty string (which is bad anyway)
|
||||
# could use `if (set -u; : $PYTHONHOME) ;` in bash
|
||||
if [ -n "${PYTHONHOME:-}" ] ; then
|
||||
_OLD_VIRTUAL_PYTHONHOME="${PYTHONHOME:-}"
|
||||
unset PYTHONHOME
|
||||
fi
|
||||
|
||||
if [ -z "${VIRTUAL_ENV_DISABLE_PROMPT:-}" ] ; then
|
||||
_OLD_VIRTUAL_PS1="${PS1:-}"
|
||||
if [ "x(virtenv) " != x ] ; then
|
||||
PS1="(virtenv) ${PS1:-}"
|
||||
else
|
||||
if [ "`basename \"$VIRTUAL_ENV\"`" = "__" ] ; then
|
||||
# special case for Aspen magic directories
|
||||
# see http://www.zetadev.com/software/aspen/
|
||||
PS1="[`basename \`dirname \"$VIRTUAL_ENV\"\``] $PS1"
|
||||
else
|
||||
PS1="(`basename \"$VIRTUAL_ENV\"`)$PS1"
|
||||
fi
|
||||
fi
|
||||
export PS1
|
||||
fi
|
||||
|
||||
# This should detect bash and zsh, which have a hash command that must
|
||||
# be called to get it to forget past commands. Without forgetting
|
||||
# past commands the $PATH changes we made may not be respected
|
||||
if [ -n "${BASH:-}" -o -n "${ZSH_VERSION:-}" ] ; then
|
||||
hash -r
|
||||
fi
|
||||
@@ -0,0 +1,37 @@
|
||||
# This file must be used with "source bin/activate.csh" *from csh*.
|
||||
# You cannot run it directly.
|
||||
# Created by Davide Di Blasi <davidedb@gmail.com>.
|
||||
# Ported to Python 3.3 venv by Andrew Svetlov <andrew.svetlov@gmail.com>
|
||||
|
||||
alias deactivate 'test $?_OLD_VIRTUAL_PATH != 0 && setenv PATH "$_OLD_VIRTUAL_PATH" && unset _OLD_VIRTUAL_PATH; rehash; test $?_OLD_VIRTUAL_PROMPT != 0 && set prompt="$_OLD_VIRTUAL_PROMPT" && unset _OLD_VIRTUAL_PROMPT; unsetenv VIRTUAL_ENV; test "\!:*" != "nondestructive" && unalias deactivate'
|
||||
|
||||
# Unset irrelevant variables.
|
||||
deactivate nondestructive
|
||||
|
||||
setenv VIRTUAL_ENV "/kunden/310927_70173/sternwarte/intern/anmeld/remove4weeks/virtenv"
|
||||
|
||||
set _OLD_VIRTUAL_PATH="$PATH"
|
||||
setenv PATH "$VIRTUAL_ENV/bin:$PATH"
|
||||
|
||||
|
||||
set _OLD_VIRTUAL_PROMPT="$prompt"
|
||||
|
||||
if (! "$?VIRTUAL_ENV_DISABLE_PROMPT") then
|
||||
if ("virtenv" != "") then
|
||||
set env_name = "virtenv"
|
||||
else
|
||||
if (`basename "VIRTUAL_ENV"` == "__") then
|
||||
# special case for Aspen magic directories
|
||||
# see http://www.zetadev.com/software/aspen/
|
||||
set env_name = `basename \`dirname "$VIRTUAL_ENV"\``
|
||||
else
|
||||
set env_name = `basename "$VIRTUAL_ENV"`
|
||||
endif
|
||||
endif
|
||||
set prompt = "[$env_name] $prompt"
|
||||
unset env_name
|
||||
endif
|
||||
|
||||
alias pydoc python -m pydoc
|
||||
|
||||
rehash
|
||||
@@ -0,0 +1,75 @@
|
||||
# This file must be used with ". bin/activate.fish" *from fish* (http://fishshell.org)
|
||||
# you cannot run it directly
|
||||
|
||||
function deactivate -d "Exit virtualenv and return to normal shell environment"
|
||||
# reset old environment variables
|
||||
if test -n "$_OLD_VIRTUAL_PATH"
|
||||
set -gx PATH $_OLD_VIRTUAL_PATH
|
||||
set -e _OLD_VIRTUAL_PATH
|
||||
end
|
||||
if test -n "$_OLD_VIRTUAL_PYTHONHOME"
|
||||
set -gx PYTHONHOME $_OLD_VIRTUAL_PYTHONHOME
|
||||
set -e _OLD_VIRTUAL_PYTHONHOME
|
||||
end
|
||||
|
||||
if test -n "$_OLD_FISH_PROMPT_OVERRIDE"
|
||||
functions -e fish_prompt
|
||||
set -e _OLD_FISH_PROMPT_OVERRIDE
|
||||
functions -c _old_fish_prompt fish_prompt
|
||||
functions -e _old_fish_prompt
|
||||
end
|
||||
|
||||
set -e VIRTUAL_ENV
|
||||
if test "$argv[1]" != "nondestructive"
|
||||
# Self destruct!
|
||||
functions -e deactivate
|
||||
end
|
||||
end
|
||||
|
||||
# unset irrelevant variables
|
||||
deactivate nondestructive
|
||||
|
||||
set -gx VIRTUAL_ENV "/kunden/310927_70173/sternwarte/intern/anmeld/remove4weeks/virtenv"
|
||||
|
||||
set -gx _OLD_VIRTUAL_PATH $PATH
|
||||
set -gx PATH "$VIRTUAL_ENV/bin" $PATH
|
||||
|
||||
# unset PYTHONHOME if set
|
||||
if set -q PYTHONHOME
|
||||
set -gx _OLD_VIRTUAL_PYTHONHOME $PYTHONHOME
|
||||
set -e PYTHONHOME
|
||||
end
|
||||
|
||||
if test -z "$VIRTUAL_ENV_DISABLE_PROMPT"
|
||||
# fish uses a function instead of an env var to generate the prompt.
|
||||
|
||||
# save the current fish_prompt function as the function _old_fish_prompt
|
||||
functions -c fish_prompt _old_fish_prompt
|
||||
|
||||
# with the original prompt function renamed, we can override with our own.
|
||||
function fish_prompt
|
||||
# Save the return status of the last command
|
||||
set -l old_status $status
|
||||
|
||||
# Prompt override?
|
||||
if test -n "(virtenv) "
|
||||
printf "%s%s" "(virtenv) " (set_color normal)
|
||||
else
|
||||
# ...Otherwise, prepend env
|
||||
set -l _checkbase (basename "$VIRTUAL_ENV")
|
||||
if test $_checkbase = "__"
|
||||
# special case for Aspen magic directories
|
||||
# see http://www.zetadev.com/software/aspen/
|
||||
printf "%s[%s]%s " (set_color -b blue white) (basename (dirname "$VIRTUAL_ENV")) (set_color normal)
|
||||
else
|
||||
printf "%s(%s)%s" (set_color -b blue white) (basename "$VIRTUAL_ENV") (set_color normal)
|
||||
end
|
||||
end
|
||||
|
||||
# Restore the return status of the previous command.
|
||||
echo "exit $old_status" | .
|
||||
_old_fish_prompt
|
||||
end
|
||||
|
||||
set -gx _OLD_FISH_PROMPT_OVERRIDE "$VIRTUAL_ENV"
|
||||
end
|
||||
11
html/sternwarte/intern/anmeld/remove4weeks/virtenv/bin/easy_install
Executable file
11
html/sternwarte/intern/anmeld/remove4weeks/virtenv/bin/easy_install
Executable file
@@ -0,0 +1,11 @@
|
||||
#!/kunden/310927_70173/sternwarte/intern/anmeld/remove4weeks/virtenv/bin/python3
|
||||
|
||||
# -*- coding: utf-8 -*-
|
||||
import re
|
||||
import sys
|
||||
|
||||
from setuptools.command.easy_install import main
|
||||
|
||||
if __name__ == '__main__':
|
||||
sys.argv[0] = re.sub(r'(-script\.pyw?|\.exe)?$', '', sys.argv[0])
|
||||
sys.exit(main())
|
||||
11
html/sternwarte/intern/anmeld/remove4weeks/virtenv/bin/easy_install-3.6
Executable file
11
html/sternwarte/intern/anmeld/remove4weeks/virtenv/bin/easy_install-3.6
Executable file
@@ -0,0 +1,11 @@
|
||||
#!/kunden/310927_70173/sternwarte/intern/anmeld/remove4weeks/virtenv/bin/python3
|
||||
|
||||
# -*- coding: utf-8 -*-
|
||||
import re
|
||||
import sys
|
||||
|
||||
from setuptools.command.easy_install import main
|
||||
|
||||
if __name__ == '__main__':
|
||||
sys.argv[0] = re.sub(r'(-script\.pyw?|\.exe)?$', '', sys.argv[0])
|
||||
sys.exit(main())
|
||||
11
html/sternwarte/intern/anmeld/remove4weeks/virtenv/bin/pip
Executable file
11
html/sternwarte/intern/anmeld/remove4weeks/virtenv/bin/pip
Executable file
@@ -0,0 +1,11 @@
|
||||
#!/kunden/310927_70173/sternwarte/intern/anmeld/remove4weeks/virtenv/bin/python3
|
||||
|
||||
# -*- coding: utf-8 -*-
|
||||
import re
|
||||
import sys
|
||||
|
||||
from pip import main
|
||||
|
||||
if __name__ == '__main__':
|
||||
sys.argv[0] = re.sub(r'(-script\.pyw?|\.exe)?$', '', sys.argv[0])
|
||||
sys.exit(main())
|
||||
11
html/sternwarte/intern/anmeld/remove4weeks/virtenv/bin/pip3
Executable file
11
html/sternwarte/intern/anmeld/remove4weeks/virtenv/bin/pip3
Executable file
@@ -0,0 +1,11 @@
|
||||
#!/kunden/310927_70173/sternwarte/intern/anmeld/remove4weeks/virtenv/bin/python3
|
||||
|
||||
# -*- coding: utf-8 -*-
|
||||
import re
|
||||
import sys
|
||||
|
||||
from pip import main
|
||||
|
||||
if __name__ == '__main__':
|
||||
sys.argv[0] = re.sub(r'(-script\.pyw?|\.exe)?$', '', sys.argv[0])
|
||||
sys.exit(main())
|
||||
11
html/sternwarte/intern/anmeld/remove4weeks/virtenv/bin/pip3.6
Executable file
11
html/sternwarte/intern/anmeld/remove4weeks/virtenv/bin/pip3.6
Executable file
@@ -0,0 +1,11 @@
|
||||
#!/kunden/310927_70173/sternwarte/intern/anmeld/remove4weeks/virtenv/bin/python3
|
||||
|
||||
# -*- coding: utf-8 -*-
|
||||
import re
|
||||
import sys
|
||||
|
||||
from pip import main
|
||||
|
||||
if __name__ == '__main__':
|
||||
sys.argv[0] = re.sub(r'(-script\.pyw?|\.exe)?$', '', sys.argv[0])
|
||||
sys.exit(main())
|
||||
1
html/sternwarte/intern/anmeld/remove4weeks/virtenv/bin/python
Symbolic link
1
html/sternwarte/intern/anmeld/remove4weeks/virtenv/bin/python
Symbolic link
@@ -0,0 +1 @@
|
||||
python3
|
||||
1
html/sternwarte/intern/anmeld/remove4weeks/virtenv/bin/python3
Symbolic link
1
html/sternwarte/intern/anmeld/remove4weeks/virtenv/bin/python3
Symbolic link
@@ -0,0 +1 @@
|
||||
/usr/bin/python3
|
||||
Binary file not shown.
@@ -0,0 +1,5 @@
|
||||
"""Run the EasyInstall command"""
|
||||
|
||||
if __name__ == '__main__':
|
||||
from setuptools.command.easy_install import main
|
||||
main()
|
||||
@@ -0,0 +1,33 @@
|
||||
# Protocol Buffers - Google's data interchange format
|
||||
# Copyright 2008 Google Inc. All rights reserved.
|
||||
# https://developers.google.com/protocol-buffers/
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions are
|
||||
# met:
|
||||
#
|
||||
# * Redistributions of source code must retain the above copyright
|
||||
# notice, this list of conditions and the following disclaimer.
|
||||
# * Redistributions in binary form must reproduce the above
|
||||
# copyright notice, this list of conditions and the following disclaimer
|
||||
# in the documentation and/or other materials provided with the
|
||||
# distribution.
|
||||
# * Neither the name of Google Inc. nor the names of its
|
||||
# contributors may be used to endorse or promote products derived from
|
||||
# this software without specific prior written permission.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
# Copyright 2007 Google Inc. All Rights Reserved.
|
||||
|
||||
__version__ = '3.19.6'
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,35 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Generated by the protocol buffer compiler. DO NOT EDIT!
|
||||
# source: google/protobuf/any.proto
|
||||
"""Generated protocol buffer code."""
|
||||
from google.protobuf import descriptor as _descriptor
|
||||
from google.protobuf import descriptor_pool as _descriptor_pool
|
||||
from google.protobuf import message as _message
|
||||
from google.protobuf import reflection as _reflection
|
||||
from google.protobuf import symbol_database as _symbol_database
|
||||
# @@protoc_insertion_point(imports)
|
||||
|
||||
_sym_db = _symbol_database.Default()
|
||||
|
||||
|
||||
|
||||
|
||||
DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x19google/protobuf/any.proto\x12\x0fgoogle.protobuf\"&\n\x03\x41ny\x12\x10\n\x08type_url\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\x0c\x42v\n\x13\x63om.google.protobufB\x08\x41nyProtoP\x01Z,google.golang.org/protobuf/types/known/anypb\xa2\x02\x03GPB\xaa\x02\x1eGoogle.Protobuf.WellKnownTypesb\x06proto3')
|
||||
|
||||
|
||||
|
||||
_ANY = DESCRIPTOR.message_types_by_name['Any']
|
||||
Any = _reflection.GeneratedProtocolMessageType('Any', (_message.Message,), {
|
||||
'DESCRIPTOR' : _ANY,
|
||||
'__module__' : 'google.protobuf.any_pb2'
|
||||
# @@protoc_insertion_point(class_scope:google.protobuf.Any)
|
||||
})
|
||||
_sym_db.RegisterMessage(Any)
|
||||
|
||||
if _descriptor._USE_C_DESCRIPTORS == False:
|
||||
|
||||
DESCRIPTOR._options = None
|
||||
DESCRIPTOR._serialized_options = b'\n\023com.google.protobufB\010AnyProtoP\001Z,google.golang.org/protobuf/types/known/anypb\242\002\003GPB\252\002\036Google.Protobuf.WellKnownTypes'
|
||||
_ANY._serialized_start=46
|
||||
_ANY._serialized_end=84
|
||||
# @@protoc_insertion_point(module_scope)
|
||||
@@ -0,0 +1,57 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Generated by the protocol buffer compiler. DO NOT EDIT!
|
||||
# source: google/protobuf/api.proto
|
||||
"""Generated protocol buffer code."""
|
||||
from google.protobuf import descriptor as _descriptor
|
||||
from google.protobuf import descriptor_pool as _descriptor_pool
|
||||
from google.protobuf import message as _message
|
||||
from google.protobuf import reflection as _reflection
|
||||
from google.protobuf import symbol_database as _symbol_database
|
||||
# @@protoc_insertion_point(imports)
|
||||
|
||||
_sym_db = _symbol_database.Default()
|
||||
|
||||
|
||||
from google.protobuf import source_context_pb2 as google_dot_protobuf_dot_source__context__pb2
|
||||
from google.protobuf import type_pb2 as google_dot_protobuf_dot_type__pb2
|
||||
|
||||
|
||||
DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x19google/protobuf/api.proto\x12\x0fgoogle.protobuf\x1a$google/protobuf/source_context.proto\x1a\x1agoogle/protobuf/type.proto\"\x81\x02\n\x03\x41pi\x12\x0c\n\x04name\x18\x01 \x01(\t\x12(\n\x07methods\x18\x02 \x03(\x0b\x32\x17.google.protobuf.Method\x12(\n\x07options\x18\x03 \x03(\x0b\x32\x17.google.protobuf.Option\x12\x0f\n\x07version\x18\x04 \x01(\t\x12\x36\n\x0esource_context\x18\x05 \x01(\x0b\x32\x1e.google.protobuf.SourceContext\x12&\n\x06mixins\x18\x06 \x03(\x0b\x32\x16.google.protobuf.Mixin\x12\'\n\x06syntax\x18\x07 \x01(\x0e\x32\x17.google.protobuf.Syntax\"\xd5\x01\n\x06Method\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\x18\n\x10request_type_url\x18\x02 \x01(\t\x12\x19\n\x11request_streaming\x18\x03 \x01(\x08\x12\x19\n\x11response_type_url\x18\x04 \x01(\t\x12\x1a\n\x12response_streaming\x18\x05 \x01(\x08\x12(\n\x07options\x18\x06 \x03(\x0b\x32\x17.google.protobuf.Option\x12\'\n\x06syntax\x18\x07 \x01(\x0e\x32\x17.google.protobuf.Syntax\"#\n\x05Mixin\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\x0c\n\x04root\x18\x02 \x01(\tBv\n\x13\x63om.google.protobufB\x08\x41piProtoP\x01Z,google.golang.org/protobuf/types/known/apipb\xa2\x02\x03GPB\xaa\x02\x1eGoogle.Protobuf.WellKnownTypesb\x06proto3')
|
||||
|
||||
|
||||
|
||||
_API = DESCRIPTOR.message_types_by_name['Api']
|
||||
_METHOD = DESCRIPTOR.message_types_by_name['Method']
|
||||
_MIXIN = DESCRIPTOR.message_types_by_name['Mixin']
|
||||
Api = _reflection.GeneratedProtocolMessageType('Api', (_message.Message,), {
|
||||
'DESCRIPTOR' : _API,
|
||||
'__module__' : 'google.protobuf.api_pb2'
|
||||
# @@protoc_insertion_point(class_scope:google.protobuf.Api)
|
||||
})
|
||||
_sym_db.RegisterMessage(Api)
|
||||
|
||||
Method = _reflection.GeneratedProtocolMessageType('Method', (_message.Message,), {
|
||||
'DESCRIPTOR' : _METHOD,
|
||||
'__module__' : 'google.protobuf.api_pb2'
|
||||
# @@protoc_insertion_point(class_scope:google.protobuf.Method)
|
||||
})
|
||||
_sym_db.RegisterMessage(Method)
|
||||
|
||||
Mixin = _reflection.GeneratedProtocolMessageType('Mixin', (_message.Message,), {
|
||||
'DESCRIPTOR' : _MIXIN,
|
||||
'__module__' : 'google.protobuf.api_pb2'
|
||||
# @@protoc_insertion_point(class_scope:google.protobuf.Mixin)
|
||||
})
|
||||
_sym_db.RegisterMessage(Mixin)
|
||||
|
||||
if _descriptor._USE_C_DESCRIPTORS == False:
|
||||
|
||||
DESCRIPTOR._options = None
|
||||
DESCRIPTOR._serialized_options = b'\n\023com.google.protobufB\010ApiProtoP\001Z,google.golang.org/protobuf/types/known/apipb\242\002\003GPB\252\002\036Google.Protobuf.WellKnownTypes'
|
||||
_API._serialized_start=113
|
||||
_API._serialized_end=370
|
||||
_METHOD._serialized_start=373
|
||||
_METHOD._serialized_end=586
|
||||
_MIXIN._serialized_start=588
|
||||
_MIXIN._serialized_end=623
|
||||
# @@protoc_insertion_point(module_scope)
|
||||
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,70 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Generated by the protocol buffer compiler. DO NOT EDIT!
|
||||
# source: google/protobuf/compiler/plugin.proto
|
||||
"""Generated protocol buffer code."""
|
||||
from google.protobuf import descriptor as _descriptor
|
||||
from google.protobuf import descriptor_pool as _descriptor_pool
|
||||
from google.protobuf import message as _message
|
||||
from google.protobuf import reflection as _reflection
|
||||
from google.protobuf import symbol_database as _symbol_database
|
||||
# @@protoc_insertion_point(imports)
|
||||
|
||||
_sym_db = _symbol_database.Default()
|
||||
|
||||
|
||||
from google.protobuf import descriptor_pb2 as google_dot_protobuf_dot_descriptor__pb2
|
||||
|
||||
|
||||
DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n%google/protobuf/compiler/plugin.proto\x12\x18google.protobuf.compiler\x1a google/protobuf/descriptor.proto\"F\n\x07Version\x12\r\n\x05major\x18\x01 \x01(\x05\x12\r\n\x05minor\x18\x02 \x01(\x05\x12\r\n\x05patch\x18\x03 \x01(\x05\x12\x0e\n\x06suffix\x18\x04 \x01(\t\"\xba\x01\n\x14\x43odeGeneratorRequest\x12\x18\n\x10\x66ile_to_generate\x18\x01 \x03(\t\x12\x11\n\tparameter\x18\x02 \x01(\t\x12\x38\n\nproto_file\x18\x0f \x03(\x0b\x32$.google.protobuf.FileDescriptorProto\x12;\n\x10\x63ompiler_version\x18\x03 \x01(\x0b\x32!.google.protobuf.compiler.Version\"\xc1\x02\n\x15\x43odeGeneratorResponse\x12\r\n\x05\x65rror\x18\x01 \x01(\t\x12\x1a\n\x12supported_features\x18\x02 \x01(\x04\x12\x42\n\x04\x66ile\x18\x0f \x03(\x0b\x32\x34.google.protobuf.compiler.CodeGeneratorResponse.File\x1a\x7f\n\x04\x46ile\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\x17\n\x0finsertion_point\x18\x02 \x01(\t\x12\x0f\n\x07\x63ontent\x18\x0f \x01(\t\x12?\n\x13generated_code_info\x18\x10 \x01(\x0b\x32\".google.protobuf.GeneratedCodeInfo\"8\n\x07\x46\x65\x61ture\x12\x10\n\x0c\x46\x45\x41TURE_NONE\x10\x00\x12\x1b\n\x17\x46\x45\x41TURE_PROTO3_OPTIONAL\x10\x01\x42W\n\x1c\x63om.google.protobuf.compilerB\x0cPluginProtosZ)google.golang.org/protobuf/types/pluginpb')
|
||||
|
||||
|
||||
|
||||
_VERSION = DESCRIPTOR.message_types_by_name['Version']
|
||||
_CODEGENERATORREQUEST = DESCRIPTOR.message_types_by_name['CodeGeneratorRequest']
|
||||
_CODEGENERATORRESPONSE = DESCRIPTOR.message_types_by_name['CodeGeneratorResponse']
|
||||
_CODEGENERATORRESPONSE_FILE = _CODEGENERATORRESPONSE.nested_types_by_name['File']
|
||||
_CODEGENERATORRESPONSE_FEATURE = _CODEGENERATORRESPONSE.enum_types_by_name['Feature']
|
||||
Version = _reflection.GeneratedProtocolMessageType('Version', (_message.Message,), {
|
||||
'DESCRIPTOR' : _VERSION,
|
||||
'__module__' : 'google.protobuf.compiler.plugin_pb2'
|
||||
# @@protoc_insertion_point(class_scope:google.protobuf.compiler.Version)
|
||||
})
|
||||
_sym_db.RegisterMessage(Version)
|
||||
|
||||
CodeGeneratorRequest = _reflection.GeneratedProtocolMessageType('CodeGeneratorRequest', (_message.Message,), {
|
||||
'DESCRIPTOR' : _CODEGENERATORREQUEST,
|
||||
'__module__' : 'google.protobuf.compiler.plugin_pb2'
|
||||
# @@protoc_insertion_point(class_scope:google.protobuf.compiler.CodeGeneratorRequest)
|
||||
})
|
||||
_sym_db.RegisterMessage(CodeGeneratorRequest)
|
||||
|
||||
CodeGeneratorResponse = _reflection.GeneratedProtocolMessageType('CodeGeneratorResponse', (_message.Message,), {
|
||||
|
||||
'File' : _reflection.GeneratedProtocolMessageType('File', (_message.Message,), {
|
||||
'DESCRIPTOR' : _CODEGENERATORRESPONSE_FILE,
|
||||
'__module__' : 'google.protobuf.compiler.plugin_pb2'
|
||||
# @@protoc_insertion_point(class_scope:google.protobuf.compiler.CodeGeneratorResponse.File)
|
||||
})
|
||||
,
|
||||
'DESCRIPTOR' : _CODEGENERATORRESPONSE,
|
||||
'__module__' : 'google.protobuf.compiler.plugin_pb2'
|
||||
# @@protoc_insertion_point(class_scope:google.protobuf.compiler.CodeGeneratorResponse)
|
||||
})
|
||||
_sym_db.RegisterMessage(CodeGeneratorResponse)
|
||||
_sym_db.RegisterMessage(CodeGeneratorResponse.File)
|
||||
|
||||
if _descriptor._USE_C_DESCRIPTORS == False:
|
||||
|
||||
DESCRIPTOR._options = None
|
||||
DESCRIPTOR._serialized_options = b'\n\034com.google.protobuf.compilerB\014PluginProtosZ)google.golang.org/protobuf/types/pluginpb'
|
||||
_VERSION._serialized_start=101
|
||||
_VERSION._serialized_end=171
|
||||
_CODEGENERATORREQUEST._serialized_start=174
|
||||
_CODEGENERATORREQUEST._serialized_end=360
|
||||
_CODEGENERATORRESPONSE._serialized_start=363
|
||||
_CODEGENERATORRESPONSE._serialized_end=684
|
||||
_CODEGENERATORRESPONSE_FILE._serialized_start=499
|
||||
_CODEGENERATORRESPONSE_FILE._serialized_end=626
|
||||
_CODEGENERATORRESPONSE_FEATURE._serialized_start=628
|
||||
_CODEGENERATORRESPONSE_FEATURE._serialized_end=684
|
||||
# @@protoc_insertion_point(module_scope)
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,177 @@
|
||||
# Protocol Buffers - Google's data interchange format
|
||||
# Copyright 2008 Google Inc. All rights reserved.
|
||||
# https://developers.google.com/protocol-buffers/
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions are
|
||||
# met:
|
||||
#
|
||||
# * Redistributions of source code must retain the above copyright
|
||||
# notice, this list of conditions and the following disclaimer.
|
||||
# * Redistributions in binary form must reproduce the above
|
||||
# copyright notice, this list of conditions and the following disclaimer
|
||||
# in the documentation and/or other materials provided with the
|
||||
# distribution.
|
||||
# * Neither the name of Google Inc. nor the names of its
|
||||
# contributors may be used to endorse or promote products derived from
|
||||
# this software without specific prior written permission.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
"""Provides a container for DescriptorProtos."""
|
||||
|
||||
__author__ = 'matthewtoia@google.com (Matt Toia)'
|
||||
|
||||
import warnings
|
||||
|
||||
|
||||
class Error(Exception):
|
||||
pass
|
||||
|
||||
|
||||
class DescriptorDatabaseConflictingDefinitionError(Error):
|
||||
"""Raised when a proto is added with the same name & different descriptor."""
|
||||
|
||||
|
||||
class DescriptorDatabase(object):
|
||||
"""A container accepting FileDescriptorProtos and maps DescriptorProtos."""
|
||||
|
||||
def __init__(self):
|
||||
self._file_desc_protos_by_file = {}
|
||||
self._file_desc_protos_by_symbol = {}
|
||||
|
||||
def Add(self, file_desc_proto):
|
||||
"""Adds the FileDescriptorProto and its types to this database.
|
||||
|
||||
Args:
|
||||
file_desc_proto: The FileDescriptorProto to add.
|
||||
Raises:
|
||||
DescriptorDatabaseConflictingDefinitionError: if an attempt is made to
|
||||
add a proto with the same name but different definition than an
|
||||
existing proto in the database.
|
||||
"""
|
||||
proto_name = file_desc_proto.name
|
||||
if proto_name not in self._file_desc_protos_by_file:
|
||||
self._file_desc_protos_by_file[proto_name] = file_desc_proto
|
||||
elif self._file_desc_protos_by_file[proto_name] != file_desc_proto:
|
||||
raise DescriptorDatabaseConflictingDefinitionError(
|
||||
'%s already added, but with different descriptor.' % proto_name)
|
||||
else:
|
||||
return
|
||||
|
||||
# Add all the top-level descriptors to the index.
|
||||
package = file_desc_proto.package
|
||||
for message in file_desc_proto.message_type:
|
||||
for name in _ExtractSymbols(message, package):
|
||||
self._AddSymbol(name, file_desc_proto)
|
||||
for enum in file_desc_proto.enum_type:
|
||||
self._AddSymbol(('.'.join((package, enum.name))), file_desc_proto)
|
||||
for enum_value in enum.value:
|
||||
self._file_desc_protos_by_symbol[
|
||||
'.'.join((package, enum_value.name))] = file_desc_proto
|
||||
for extension in file_desc_proto.extension:
|
||||
self._AddSymbol(('.'.join((package, extension.name))), file_desc_proto)
|
||||
for service in file_desc_proto.service:
|
||||
self._AddSymbol(('.'.join((package, service.name))), file_desc_proto)
|
||||
|
||||
def FindFileByName(self, name):
|
||||
"""Finds the file descriptor proto by file name.
|
||||
|
||||
Typically the file name is a relative path ending to a .proto file. The
|
||||
proto with the given name will have to have been added to this database
|
||||
using the Add method or else an error will be raised.
|
||||
|
||||
Args:
|
||||
name: The file name to find.
|
||||
|
||||
Returns:
|
||||
The file descriptor proto matching the name.
|
||||
|
||||
Raises:
|
||||
KeyError if no file by the given name was added.
|
||||
"""
|
||||
|
||||
return self._file_desc_protos_by_file[name]
|
||||
|
||||
def FindFileContainingSymbol(self, symbol):
|
||||
"""Finds the file descriptor proto containing the specified symbol.
|
||||
|
||||
The symbol should be a fully qualified name including the file descriptor's
|
||||
package and any containing messages. Some examples:
|
||||
|
||||
'some.package.name.Message'
|
||||
'some.package.name.Message.NestedEnum'
|
||||
'some.package.name.Message.some_field'
|
||||
|
||||
The file descriptor proto containing the specified symbol must be added to
|
||||
this database using the Add method or else an error will be raised.
|
||||
|
||||
Args:
|
||||
symbol: The fully qualified symbol name.
|
||||
|
||||
Returns:
|
||||
The file descriptor proto containing the symbol.
|
||||
|
||||
Raises:
|
||||
KeyError if no file contains the specified symbol.
|
||||
"""
|
||||
try:
|
||||
return self._file_desc_protos_by_symbol[symbol]
|
||||
except KeyError:
|
||||
# Fields, enum values, and nested extensions are not in
|
||||
# _file_desc_protos_by_symbol. Try to find the top level
|
||||
# descriptor. Non-existent nested symbol under a valid top level
|
||||
# descriptor can also be found. The behavior is the same with
|
||||
# protobuf C++.
|
||||
top_level, _, _ = symbol.rpartition('.')
|
||||
try:
|
||||
return self._file_desc_protos_by_symbol[top_level]
|
||||
except KeyError:
|
||||
# Raise the original symbol as a KeyError for better diagnostics.
|
||||
raise KeyError(symbol)
|
||||
|
||||
def FindFileContainingExtension(self, extendee_name, extension_number):
|
||||
# TODO(jieluo): implement this API.
|
||||
return None
|
||||
|
||||
def FindAllExtensionNumbers(self, extendee_name):
|
||||
# TODO(jieluo): implement this API.
|
||||
return []
|
||||
|
||||
def _AddSymbol(self, name, file_desc_proto):
|
||||
if name in self._file_desc_protos_by_symbol:
|
||||
warn_msg = ('Conflict register for file "' + file_desc_proto.name +
|
||||
'": ' + name +
|
||||
' is already defined in file "' +
|
||||
self._file_desc_protos_by_symbol[name].name + '"')
|
||||
warnings.warn(warn_msg, RuntimeWarning)
|
||||
self._file_desc_protos_by_symbol[name] = file_desc_proto
|
||||
|
||||
|
||||
def _ExtractSymbols(desc_proto, package):
|
||||
"""Pulls out all the symbols from a descriptor proto.
|
||||
|
||||
Args:
|
||||
desc_proto: The proto to extract symbols from.
|
||||
package: The package containing the descriptor type.
|
||||
|
||||
Yields:
|
||||
The fully qualified name found in the descriptor.
|
||||
"""
|
||||
message_name = package + '.' + desc_proto.name if package else desc_proto.name
|
||||
yield message_name
|
||||
for nested_type in desc_proto.nested_type:
|
||||
for symbol in _ExtractSymbols(nested_type, message_name):
|
||||
yield symbol
|
||||
for enum_type in desc_proto.enum_type:
|
||||
yield '.'.join((message_name, enum_type.name))
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,35 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Generated by the protocol buffer compiler. DO NOT EDIT!
|
||||
# source: google/protobuf/duration.proto
|
||||
"""Generated protocol buffer code."""
|
||||
from google.protobuf import descriptor as _descriptor
|
||||
from google.protobuf import descriptor_pool as _descriptor_pool
|
||||
from google.protobuf import message as _message
|
||||
from google.protobuf import reflection as _reflection
|
||||
from google.protobuf import symbol_database as _symbol_database
|
||||
# @@protoc_insertion_point(imports)
|
||||
|
||||
_sym_db = _symbol_database.Default()
|
||||
|
||||
|
||||
|
||||
|
||||
DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x1egoogle/protobuf/duration.proto\x12\x0fgoogle.protobuf\"*\n\x08\x44uration\x12\x0f\n\x07seconds\x18\x01 \x01(\x03\x12\r\n\x05nanos\x18\x02 \x01(\x05\x42\x83\x01\n\x13\x63om.google.protobufB\rDurationProtoP\x01Z1google.golang.org/protobuf/types/known/durationpb\xf8\x01\x01\xa2\x02\x03GPB\xaa\x02\x1eGoogle.Protobuf.WellKnownTypesb\x06proto3')
|
||||
|
||||
|
||||
|
||||
_DURATION = DESCRIPTOR.message_types_by_name['Duration']
|
||||
Duration = _reflection.GeneratedProtocolMessageType('Duration', (_message.Message,), {
|
||||
'DESCRIPTOR' : _DURATION,
|
||||
'__module__' : 'google.protobuf.duration_pb2'
|
||||
# @@protoc_insertion_point(class_scope:google.protobuf.Duration)
|
||||
})
|
||||
_sym_db.RegisterMessage(Duration)
|
||||
|
||||
if _descriptor._USE_C_DESCRIPTORS == False:
|
||||
|
||||
DESCRIPTOR._options = None
|
||||
DESCRIPTOR._serialized_options = b'\n\023com.google.protobufB\rDurationProtoP\001Z1google.golang.org/protobuf/types/known/durationpb\370\001\001\242\002\003GPB\252\002\036Google.Protobuf.WellKnownTypes'
|
||||
_DURATION._serialized_start=51
|
||||
_DURATION._serialized_end=93
|
||||
# @@protoc_insertion_point(module_scope)
|
||||
@@ -0,0 +1,35 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Generated by the protocol buffer compiler. DO NOT EDIT!
|
||||
# source: google/protobuf/empty.proto
|
||||
"""Generated protocol buffer code."""
|
||||
from google.protobuf import descriptor as _descriptor
|
||||
from google.protobuf import descriptor_pool as _descriptor_pool
|
||||
from google.protobuf import message as _message
|
||||
from google.protobuf import reflection as _reflection
|
||||
from google.protobuf import symbol_database as _symbol_database
|
||||
# @@protoc_insertion_point(imports)
|
||||
|
||||
_sym_db = _symbol_database.Default()
|
||||
|
||||
|
||||
|
||||
|
||||
DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x1bgoogle/protobuf/empty.proto\x12\x0fgoogle.protobuf\"\x07\n\x05\x45mptyB}\n\x13\x63om.google.protobufB\nEmptyProtoP\x01Z.google.golang.org/protobuf/types/known/emptypb\xf8\x01\x01\xa2\x02\x03GPB\xaa\x02\x1eGoogle.Protobuf.WellKnownTypesb\x06proto3')
|
||||
|
||||
|
||||
|
||||
_EMPTY = DESCRIPTOR.message_types_by_name['Empty']
|
||||
Empty = _reflection.GeneratedProtocolMessageType('Empty', (_message.Message,), {
|
||||
'DESCRIPTOR' : _EMPTY,
|
||||
'__module__' : 'google.protobuf.empty_pb2'
|
||||
# @@protoc_insertion_point(class_scope:google.protobuf.Empty)
|
||||
})
|
||||
_sym_db.RegisterMessage(Empty)
|
||||
|
||||
if _descriptor._USE_C_DESCRIPTORS == False:
|
||||
|
||||
DESCRIPTOR._options = None
|
||||
DESCRIPTOR._serialized_options = b'\n\023com.google.protobufB\nEmptyProtoP\001Z.google.golang.org/protobuf/types/known/emptypb\370\001\001\242\002\003GPB\252\002\036Google.Protobuf.WellKnownTypes'
|
||||
_EMPTY._serialized_start=48
|
||||
_EMPTY._serialized_end=55
|
||||
# @@protoc_insertion_point(module_scope)
|
||||
@@ -0,0 +1,35 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Generated by the protocol buffer compiler. DO NOT EDIT!
|
||||
# source: google/protobuf/field_mask.proto
|
||||
"""Generated protocol buffer code."""
|
||||
from google.protobuf import descriptor as _descriptor
|
||||
from google.protobuf import descriptor_pool as _descriptor_pool
|
||||
from google.protobuf import message as _message
|
||||
from google.protobuf import reflection as _reflection
|
||||
from google.protobuf import symbol_database as _symbol_database
|
||||
# @@protoc_insertion_point(imports)
|
||||
|
||||
_sym_db = _symbol_database.Default()
|
||||
|
||||
|
||||
|
||||
|
||||
DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n google/protobuf/field_mask.proto\x12\x0fgoogle.protobuf\"\x1a\n\tFieldMask\x12\r\n\x05paths\x18\x01 \x03(\tB\x85\x01\n\x13\x63om.google.protobufB\x0e\x46ieldMaskProtoP\x01Z2google.golang.org/protobuf/types/known/fieldmaskpb\xf8\x01\x01\xa2\x02\x03GPB\xaa\x02\x1eGoogle.Protobuf.WellKnownTypesb\x06proto3')
|
||||
|
||||
|
||||
|
||||
_FIELDMASK = DESCRIPTOR.message_types_by_name['FieldMask']
|
||||
FieldMask = _reflection.GeneratedProtocolMessageType('FieldMask', (_message.Message,), {
|
||||
'DESCRIPTOR' : _FIELDMASK,
|
||||
'__module__' : 'google.protobuf.field_mask_pb2'
|
||||
# @@protoc_insertion_point(class_scope:google.protobuf.FieldMask)
|
||||
})
|
||||
_sym_db.RegisterMessage(FieldMask)
|
||||
|
||||
if _descriptor._USE_C_DESCRIPTORS == False:
|
||||
|
||||
DESCRIPTOR._options = None
|
||||
DESCRIPTOR._serialized_options = b'\n\023com.google.protobufB\016FieldMaskProtoP\001Z2google.golang.org/protobuf/types/known/fieldmaskpb\370\001\001\242\002\003GPB\252\002\036Google.Protobuf.WellKnownTypes'
|
||||
_FIELDMASK._serialized_start=53
|
||||
_FIELDMASK._serialized_end=79
|
||||
# @@protoc_insertion_point(module_scope)
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,112 @@
|
||||
# Protocol Buffers - Google's data interchange format
|
||||
# Copyright 2008 Google Inc. All rights reserved.
|
||||
# https://developers.google.com/protocol-buffers/
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions are
|
||||
# met:
|
||||
#
|
||||
# * Redistributions of source code must retain the above copyright
|
||||
# notice, this list of conditions and the following disclaimer.
|
||||
# * Redistributions in binary form must reproduce the above
|
||||
# copyright notice, this list of conditions and the following disclaimer
|
||||
# in the documentation and/or other materials provided with the
|
||||
# distribution.
|
||||
# * Neither the name of Google Inc. nor the names of its
|
||||
# contributors may be used to endorse or promote products derived from
|
||||
# this software without specific prior written permission.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
"""Determine which implementation of the protobuf API is used in this process.
|
||||
"""
|
||||
|
||||
import os
|
||||
import sys
|
||||
import warnings
|
||||
|
||||
try:
|
||||
# pylint: disable=g-import-not-at-top
|
||||
from google.protobuf.internal import _api_implementation
|
||||
# The compile-time constants in the _api_implementation module can be used to
|
||||
# switch to a certain implementation of the Python API at build time.
|
||||
_api_version = _api_implementation.api_version
|
||||
except ImportError:
|
||||
_api_version = -1 # Unspecified by compiler flags.
|
||||
|
||||
if _api_version == 1:
|
||||
raise ValueError('api_version=1 is no longer supported.')
|
||||
|
||||
|
||||
_default_implementation_type = ('cpp' if _api_version > 0 else 'python')
|
||||
|
||||
|
||||
# This environment variable can be used to switch to a certain implementation
|
||||
# of the Python API, overriding the compile-time constants in the
|
||||
# _api_implementation module. Right now only 'python' and 'cpp' are valid
|
||||
# values. Any other value will be ignored.
|
||||
_implementation_type = os.getenv('PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION',
|
||||
_default_implementation_type)
|
||||
|
||||
if _implementation_type != 'python':
|
||||
_implementation_type = 'cpp'
|
||||
|
||||
if 'PyPy' in sys.version and _implementation_type == 'cpp':
|
||||
warnings.warn('PyPy does not work yet with cpp protocol buffers. '
|
||||
'Falling back to the python implementation.')
|
||||
_implementation_type = 'python'
|
||||
|
||||
|
||||
# Detect if serialization should be deterministic by default
|
||||
try:
|
||||
# The presence of this module in a build allows the proto implementation to
|
||||
# be upgraded merely via build deps.
|
||||
#
|
||||
# NOTE: Merely importing this automatically enables deterministic proto
|
||||
# serialization for C++ code, but we still need to export it as a boolean so
|
||||
# that we can do the same for `_implementation_type == 'python'`.
|
||||
#
|
||||
# NOTE2: It is possible for C++ code to enable deterministic serialization by
|
||||
# default _without_ affecting Python code, if the C++ implementation is not in
|
||||
# use by this module. That is intended behavior, so we don't actually expose
|
||||
# this boolean outside of this module.
|
||||
#
|
||||
# pylint: disable=g-import-not-at-top,unused-import
|
||||
from google.protobuf import enable_deterministic_proto_serialization
|
||||
_python_deterministic_proto_serialization = True
|
||||
except ImportError:
|
||||
_python_deterministic_proto_serialization = False
|
||||
|
||||
|
||||
# Usage of this function is discouraged. Clients shouldn't care which
|
||||
# implementation of the API is in use. Note that there is no guarantee
|
||||
# that differences between APIs will be maintained.
|
||||
# Please don't use this function if possible.
|
||||
def Type():
|
||||
return _implementation_type
|
||||
|
||||
|
||||
def _SetType(implementation_type):
|
||||
"""Never use! Only for protobuf benchmark."""
|
||||
global _implementation_type
|
||||
_implementation_type = implementation_type
|
||||
|
||||
|
||||
# See comment on 'Type' above.
|
||||
def Version():
|
||||
return 2
|
||||
|
||||
|
||||
# For internal use only
|
||||
def IsPythonDefaultSerializationDeterministic():
|
||||
return _python_deterministic_proto_serialization
|
||||
@@ -0,0 +1,643 @@
|
||||
# Protocol Buffers - Google's data interchange format
|
||||
# Copyright 2008 Google Inc. All rights reserved.
|
||||
# https://developers.google.com/protocol-buffers/
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions are
|
||||
# met:
|
||||
#
|
||||
# * Redistributions of source code must retain the above copyright
|
||||
# notice, this list of conditions and the following disclaimer.
|
||||
# * Redistributions in binary form must reproduce the above
|
||||
# copyright notice, this list of conditions and the following disclaimer
|
||||
# in the documentation and/or other materials provided with the
|
||||
# distribution.
|
||||
# * Neither the name of Google Inc. nor the names of its
|
||||
# contributors may be used to endorse or promote products derived from
|
||||
# this software without specific prior written permission.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
"""Contains container classes to represent different protocol buffer types.
|
||||
|
||||
This file defines container classes which represent categories of protocol
|
||||
buffer field types which need extra maintenance. Currently these categories
|
||||
are:
|
||||
|
||||
- Repeated scalar fields - These are all repeated fields which aren't
|
||||
composite (e.g. they are of simple types like int32, string, etc).
|
||||
- Repeated composite fields - Repeated fields which are composite. This
|
||||
includes groups and nested messages.
|
||||
"""
|
||||
|
||||
__author__ = 'petar@google.com (Petar Petrov)'
|
||||
|
||||
import collections.abc
|
||||
|
||||
|
||||
class BaseContainer(object):
|
||||
|
||||
"""Base container class."""
|
||||
|
||||
# Minimizes memory usage and disallows assignment to other attributes.
|
||||
__slots__ = ['_message_listener', '_values']
|
||||
|
||||
def __init__(self, message_listener):
|
||||
"""
|
||||
Args:
|
||||
message_listener: A MessageListener implementation.
|
||||
The RepeatedScalarFieldContainer will call this object's
|
||||
Modified() method when it is modified.
|
||||
"""
|
||||
self._message_listener = message_listener
|
||||
self._values = []
|
||||
|
||||
def __getitem__(self, key):
|
||||
"""Retrieves item by the specified key."""
|
||||
return self._values[key]
|
||||
|
||||
def __len__(self):
|
||||
"""Returns the number of elements in the container."""
|
||||
return len(self._values)
|
||||
|
||||
def __ne__(self, other):
|
||||
"""Checks if another instance isn't equal to this one."""
|
||||
# The concrete classes should define __eq__.
|
||||
return not self == other
|
||||
|
||||
def __hash__(self):
|
||||
raise TypeError('unhashable object')
|
||||
|
||||
def __repr__(self):
|
||||
return repr(self._values)
|
||||
|
||||
def sort(self, *args, **kwargs):
|
||||
# Continue to support the old sort_function keyword argument.
|
||||
# This is expected to be a rare occurrence, so use LBYL to avoid
|
||||
# the overhead of actually catching KeyError.
|
||||
if 'sort_function' in kwargs:
|
||||
kwargs['cmp'] = kwargs.pop('sort_function')
|
||||
self._values.sort(*args, **kwargs)
|
||||
|
||||
def reverse(self):
|
||||
self._values.reverse()
|
||||
|
||||
|
||||
collections.abc.MutableSequence.register(BaseContainer)
|
||||
|
||||
|
||||
class RepeatedScalarFieldContainer(BaseContainer):
|
||||
"""Simple, type-checked, list-like container for holding repeated scalars."""
|
||||
|
||||
# Disallows assignment to other attributes.
|
||||
__slots__ = ['_type_checker']
|
||||
|
||||
def __init__(self, message_listener, type_checker):
|
||||
"""Args:
|
||||
|
||||
message_listener: A MessageListener implementation. The
|
||||
RepeatedScalarFieldContainer will call this object's Modified() method
|
||||
when it is modified.
|
||||
type_checker: A type_checkers.ValueChecker instance to run on elements
|
||||
inserted into this container.
|
||||
"""
|
||||
super(RepeatedScalarFieldContainer, self).__init__(message_listener)
|
||||
self._type_checker = type_checker
|
||||
|
||||
def append(self, value):
|
||||
"""Appends an item to the list. Similar to list.append()."""
|
||||
self._values.append(self._type_checker.CheckValue(value))
|
||||
if not self._message_listener.dirty:
|
||||
self._message_listener.Modified()
|
||||
|
||||
def insert(self, key, value):
|
||||
"""Inserts the item at the specified position. Similar to list.insert()."""
|
||||
self._values.insert(key, self._type_checker.CheckValue(value))
|
||||
if not self._message_listener.dirty:
|
||||
self._message_listener.Modified()
|
||||
|
||||
def extend(self, elem_seq):
|
||||
"""Extends by appending the given iterable. Similar to list.extend()."""
|
||||
|
||||
if elem_seq is None:
|
||||
return
|
||||
try:
|
||||
elem_seq_iter = iter(elem_seq)
|
||||
except TypeError:
|
||||
if not elem_seq:
|
||||
# silently ignore falsy inputs :-/.
|
||||
# TODO(ptucker): Deprecate this behavior. b/18413862
|
||||
return
|
||||
raise
|
||||
|
||||
new_values = [self._type_checker.CheckValue(elem) for elem in elem_seq_iter]
|
||||
if new_values:
|
||||
self._values.extend(new_values)
|
||||
self._message_listener.Modified()
|
||||
|
||||
def MergeFrom(self, other):
|
||||
"""Appends the contents of another repeated field of the same type to this
|
||||
one. We do not check the types of the individual fields.
|
||||
"""
|
||||
self._values.extend(other._values)
|
||||
self._message_listener.Modified()
|
||||
|
||||
def remove(self, elem):
|
||||
"""Removes an item from the list. Similar to list.remove()."""
|
||||
self._values.remove(elem)
|
||||
self._message_listener.Modified()
|
||||
|
||||
def pop(self, key=-1):
|
||||
"""Removes and returns an item at a given index. Similar to list.pop()."""
|
||||
value = self._values[key]
|
||||
self.__delitem__(key)
|
||||
return value
|
||||
|
||||
def __setitem__(self, key, value):
|
||||
"""Sets the item on the specified position."""
|
||||
if isinstance(key, slice): # PY3
|
||||
if key.step is not None:
|
||||
raise ValueError('Extended slices not supported')
|
||||
self.__setslice__(key.start, key.stop, value)
|
||||
else:
|
||||
self._values[key] = self._type_checker.CheckValue(value)
|
||||
self._message_listener.Modified()
|
||||
|
||||
def __getslice__(self, start, stop):
|
||||
"""Retrieves the subset of items from between the specified indices."""
|
||||
return self._values[start:stop]
|
||||
|
||||
def __setslice__(self, start, stop, values):
|
||||
"""Sets the subset of items from between the specified indices."""
|
||||
new_values = []
|
||||
for value in values:
|
||||
new_values.append(self._type_checker.CheckValue(value))
|
||||
self._values[start:stop] = new_values
|
||||
self._message_listener.Modified()
|
||||
|
||||
def __delitem__(self, key):
|
||||
"""Deletes the item at the specified position."""
|
||||
del self._values[key]
|
||||
self._message_listener.Modified()
|
||||
|
||||
def __delslice__(self, start, stop):
|
||||
"""Deletes the subset of items from between the specified indices."""
|
||||
del self._values[start:stop]
|
||||
self._message_listener.Modified()
|
||||
|
||||
def __eq__(self, other):
|
||||
"""Compares the current instance with another one."""
|
||||
if self is other:
|
||||
return True
|
||||
# Special case for the same type which should be common and fast.
|
||||
if isinstance(other, self.__class__):
|
||||
return other._values == self._values
|
||||
# We are presumably comparing against some other sequence type.
|
||||
return other == self._values
|
||||
|
||||
|
||||
class RepeatedCompositeFieldContainer(BaseContainer):
|
||||
|
||||
"""Simple, list-like container for holding repeated composite fields."""
|
||||
|
||||
# Disallows assignment to other attributes.
|
||||
__slots__ = ['_message_descriptor']
|
||||
|
||||
def __init__(self, message_listener, message_descriptor):
|
||||
"""
|
||||
Note that we pass in a descriptor instead of the generated directly,
|
||||
since at the time we construct a _RepeatedCompositeFieldContainer we
|
||||
haven't yet necessarily initialized the type that will be contained in the
|
||||
container.
|
||||
|
||||
Args:
|
||||
message_listener: A MessageListener implementation.
|
||||
The RepeatedCompositeFieldContainer will call this object's
|
||||
Modified() method when it is modified.
|
||||
message_descriptor: A Descriptor instance describing the protocol type
|
||||
that should be present in this container. We'll use the
|
||||
_concrete_class field of this descriptor when the client calls add().
|
||||
"""
|
||||
super(RepeatedCompositeFieldContainer, self).__init__(message_listener)
|
||||
self._message_descriptor = message_descriptor
|
||||
|
||||
def add(self, **kwargs):
|
||||
"""Adds a new element at the end of the list and returns it. Keyword
|
||||
arguments may be used to initialize the element.
|
||||
"""
|
||||
new_element = self._message_descriptor._concrete_class(**kwargs)
|
||||
new_element._SetListener(self._message_listener)
|
||||
self._values.append(new_element)
|
||||
if not self._message_listener.dirty:
|
||||
self._message_listener.Modified()
|
||||
return new_element
|
||||
|
||||
def append(self, value):
|
||||
"""Appends one element by copying the message."""
|
||||
new_element = self._message_descriptor._concrete_class()
|
||||
new_element._SetListener(self._message_listener)
|
||||
new_element.CopyFrom(value)
|
||||
self._values.append(new_element)
|
||||
if not self._message_listener.dirty:
|
||||
self._message_listener.Modified()
|
||||
|
||||
def insert(self, key, value):
|
||||
"""Inserts the item at the specified position by copying."""
|
||||
new_element = self._message_descriptor._concrete_class()
|
||||
new_element._SetListener(self._message_listener)
|
||||
new_element.CopyFrom(value)
|
||||
self._values.insert(key, new_element)
|
||||
if not self._message_listener.dirty:
|
||||
self._message_listener.Modified()
|
||||
|
||||
def extend(self, elem_seq):
|
||||
"""Extends by appending the given sequence of elements of the same type
|
||||
|
||||
as this one, copying each individual message.
|
||||
"""
|
||||
message_class = self._message_descriptor._concrete_class
|
||||
listener = self._message_listener
|
||||
values = self._values
|
||||
for message in elem_seq:
|
||||
new_element = message_class()
|
||||
new_element._SetListener(listener)
|
||||
new_element.MergeFrom(message)
|
||||
values.append(new_element)
|
||||
listener.Modified()
|
||||
|
||||
def MergeFrom(self, other):
|
||||
"""Appends the contents of another repeated field of the same type to this
|
||||
one, copying each individual message.
|
||||
"""
|
||||
self.extend(other._values)
|
||||
|
||||
def remove(self, elem):
|
||||
"""Removes an item from the list. Similar to list.remove()."""
|
||||
self._values.remove(elem)
|
||||
self._message_listener.Modified()
|
||||
|
||||
def pop(self, key=-1):
|
||||
"""Removes and returns an item at a given index. Similar to list.pop()."""
|
||||
value = self._values[key]
|
||||
self.__delitem__(key)
|
||||
return value
|
||||
|
||||
def __getslice__(self, start, stop):
|
||||
"""Retrieves the subset of items from between the specified indices."""
|
||||
return self._values[start:stop]
|
||||
|
||||
def __delitem__(self, key):
|
||||
"""Deletes the item at the specified position."""
|
||||
del self._values[key]
|
||||
self._message_listener.Modified()
|
||||
|
||||
def __delslice__(self, start, stop):
|
||||
"""Deletes the subset of items from between the specified indices."""
|
||||
del self._values[start:stop]
|
||||
self._message_listener.Modified()
|
||||
|
||||
def __eq__(self, other):
|
||||
"""Compares the current instance with another one."""
|
||||
if self is other:
|
||||
return True
|
||||
if not isinstance(other, self.__class__):
|
||||
raise TypeError('Can only compare repeated composite fields against '
|
||||
'other repeated composite fields.')
|
||||
return self._values == other._values
|
||||
|
||||
|
||||
class ScalarMap(collections.abc.MutableMapping):
|
||||
|
||||
"""Simple, type-checked, dict-like container for holding repeated scalars."""
|
||||
|
||||
# Disallows assignment to other attributes.
|
||||
__slots__ = ['_key_checker', '_value_checker', '_values', '_message_listener',
|
||||
'_entry_descriptor']
|
||||
|
||||
def __init__(self, message_listener, key_checker, value_checker,
|
||||
entry_descriptor):
|
||||
"""
|
||||
Args:
|
||||
message_listener: A MessageListener implementation.
|
||||
The ScalarMap will call this object's Modified() method when it
|
||||
is modified.
|
||||
key_checker: A type_checkers.ValueChecker instance to run on keys
|
||||
inserted into this container.
|
||||
value_checker: A type_checkers.ValueChecker instance to run on values
|
||||
inserted into this container.
|
||||
entry_descriptor: The MessageDescriptor of a map entry: key and value.
|
||||
"""
|
||||
self._message_listener = message_listener
|
||||
self._key_checker = key_checker
|
||||
self._value_checker = value_checker
|
||||
self._entry_descriptor = entry_descriptor
|
||||
self._values = {}
|
||||
|
||||
def __getitem__(self, key):
|
||||
try:
|
||||
return self._values[key]
|
||||
except KeyError:
|
||||
key = self._key_checker.CheckValue(key)
|
||||
val = self._value_checker.DefaultValue()
|
||||
self._values[key] = val
|
||||
return val
|
||||
|
||||
def __contains__(self, item):
|
||||
# We check the key's type to match the strong-typing flavor of the API.
|
||||
# Also this makes it easier to match the behavior of the C++ implementation.
|
||||
self._key_checker.CheckValue(item)
|
||||
return item in self._values
|
||||
|
||||
# We need to override this explicitly, because our defaultdict-like behavior
|
||||
# will make the default implementation (from our base class) always insert
|
||||
# the key.
|
||||
def get(self, key, default=None):
|
||||
if key in self:
|
||||
return self[key]
|
||||
else:
|
||||
return default
|
||||
|
||||
def __setitem__(self, key, value):
|
||||
checked_key = self._key_checker.CheckValue(key)
|
||||
checked_value = self._value_checker.CheckValue(value)
|
||||
self._values[checked_key] = checked_value
|
||||
self._message_listener.Modified()
|
||||
|
||||
def __delitem__(self, key):
|
||||
del self._values[key]
|
||||
self._message_listener.Modified()
|
||||
|
||||
def __len__(self):
|
||||
return len(self._values)
|
||||
|
||||
def __iter__(self):
|
||||
return iter(self._values)
|
||||
|
||||
def __repr__(self):
|
||||
return repr(self._values)
|
||||
|
||||
def MergeFrom(self, other):
|
||||
self._values.update(other._values)
|
||||
self._message_listener.Modified()
|
||||
|
||||
def InvalidateIterators(self):
|
||||
# It appears that the only way to reliably invalidate iterators to
|
||||
# self._values is to ensure that its size changes.
|
||||
original = self._values
|
||||
self._values = original.copy()
|
||||
original[None] = None
|
||||
|
||||
# This is defined in the abstract base, but we can do it much more cheaply.
|
||||
def clear(self):
|
||||
self._values.clear()
|
||||
self._message_listener.Modified()
|
||||
|
||||
def GetEntryClass(self):
|
||||
return self._entry_descriptor._concrete_class
|
||||
|
||||
|
||||
class MessageMap(collections.abc.MutableMapping):
|
||||
|
||||
"""Simple, type-checked, dict-like container for with submessage values."""
|
||||
|
||||
# Disallows assignment to other attributes.
|
||||
__slots__ = ['_key_checker', '_values', '_message_listener',
|
||||
'_message_descriptor', '_entry_descriptor']
|
||||
|
||||
def __init__(self, message_listener, message_descriptor, key_checker,
|
||||
entry_descriptor):
|
||||
"""
|
||||
Args:
|
||||
message_listener: A MessageListener implementation.
|
||||
The ScalarMap will call this object's Modified() method when it
|
||||
is modified.
|
||||
key_checker: A type_checkers.ValueChecker instance to run on keys
|
||||
inserted into this container.
|
||||
value_checker: A type_checkers.ValueChecker instance to run on values
|
||||
inserted into this container.
|
||||
entry_descriptor: The MessageDescriptor of a map entry: key and value.
|
||||
"""
|
||||
self._message_listener = message_listener
|
||||
self._message_descriptor = message_descriptor
|
||||
self._key_checker = key_checker
|
||||
self._entry_descriptor = entry_descriptor
|
||||
self._values = {}
|
||||
|
||||
def __getitem__(self, key):
|
||||
key = self._key_checker.CheckValue(key)
|
||||
try:
|
||||
return self._values[key]
|
||||
except KeyError:
|
||||
new_element = self._message_descriptor._concrete_class()
|
||||
new_element._SetListener(self._message_listener)
|
||||
self._values[key] = new_element
|
||||
self._message_listener.Modified()
|
||||
|
||||
return new_element
|
||||
|
||||
def get_or_create(self, key):
|
||||
"""get_or_create() is an alias for getitem (ie. map[key]).
|
||||
|
||||
Args:
|
||||
key: The key to get or create in the map.
|
||||
|
||||
This is useful in cases where you want to be explicit that the call is
|
||||
mutating the map. This can avoid lint errors for statements like this
|
||||
that otherwise would appear to be pointless statements:
|
||||
|
||||
msg.my_map[key]
|
||||
"""
|
||||
return self[key]
|
||||
|
||||
# We need to override this explicitly, because our defaultdict-like behavior
|
||||
# will make the default implementation (from our base class) always insert
|
||||
# the key.
|
||||
def get(self, key, default=None):
|
||||
if key in self:
|
||||
return self[key]
|
||||
else:
|
||||
return default
|
||||
|
||||
def __contains__(self, item):
|
||||
item = self._key_checker.CheckValue(item)
|
||||
return item in self._values
|
||||
|
||||
def __setitem__(self, key, value):
|
||||
raise ValueError('May not set values directly, call my_map[key].foo = 5')
|
||||
|
||||
def __delitem__(self, key):
|
||||
key = self._key_checker.CheckValue(key)
|
||||
del self._values[key]
|
||||
self._message_listener.Modified()
|
||||
|
||||
def __len__(self):
|
||||
return len(self._values)
|
||||
|
||||
def __iter__(self):
|
||||
return iter(self._values)
|
||||
|
||||
def __repr__(self):
|
||||
return repr(self._values)
|
||||
|
||||
def MergeFrom(self, other):
|
||||
# pylint: disable=protected-access
|
||||
for key in other._values:
|
||||
# According to documentation: "When parsing from the wire or when merging,
|
||||
# if there are duplicate map keys the last key seen is used".
|
||||
if key in self:
|
||||
del self[key]
|
||||
self[key].CopyFrom(other[key])
|
||||
# self._message_listener.Modified() not required here, because
|
||||
# mutations to submessages already propagate.
|
||||
|
||||
def InvalidateIterators(self):
|
||||
# It appears that the only way to reliably invalidate iterators to
|
||||
# self._values is to ensure that its size changes.
|
||||
original = self._values
|
||||
self._values = original.copy()
|
||||
original[None] = None
|
||||
|
||||
# This is defined in the abstract base, but we can do it much more cheaply.
|
||||
def clear(self):
|
||||
self._values.clear()
|
||||
self._message_listener.Modified()
|
||||
|
||||
def GetEntryClass(self):
|
||||
return self._entry_descriptor._concrete_class
|
||||
|
||||
|
||||
class _UnknownField(object):
|
||||
|
||||
"""A parsed unknown field."""
|
||||
|
||||
# Disallows assignment to other attributes.
|
||||
__slots__ = ['_field_number', '_wire_type', '_data']
|
||||
|
||||
def __init__(self, field_number, wire_type, data):
|
||||
self._field_number = field_number
|
||||
self._wire_type = wire_type
|
||||
self._data = data
|
||||
return
|
||||
|
||||
def __lt__(self, other):
|
||||
# pylint: disable=protected-access
|
||||
return self._field_number < other._field_number
|
||||
|
||||
def __eq__(self, other):
|
||||
if self is other:
|
||||
return True
|
||||
# pylint: disable=protected-access
|
||||
return (self._field_number == other._field_number and
|
||||
self._wire_type == other._wire_type and
|
||||
self._data == other._data)
|
||||
|
||||
|
||||
class UnknownFieldRef(object):
|
||||
|
||||
def __init__(self, parent, index):
|
||||
self._parent = parent
|
||||
self._index = index
|
||||
return
|
||||
|
||||
def _check_valid(self):
|
||||
if not self._parent:
|
||||
raise ValueError('UnknownField does not exist. '
|
||||
'The parent message might be cleared.')
|
||||
if self._index >= len(self._parent):
|
||||
raise ValueError('UnknownField does not exist. '
|
||||
'The parent message might be cleared.')
|
||||
|
||||
@property
|
||||
def field_number(self):
|
||||
self._check_valid()
|
||||
# pylint: disable=protected-access
|
||||
return self._parent._internal_get(self._index)._field_number
|
||||
|
||||
@property
|
||||
def wire_type(self):
|
||||
self._check_valid()
|
||||
# pylint: disable=protected-access
|
||||
return self._parent._internal_get(self._index)._wire_type
|
||||
|
||||
@property
|
||||
def data(self):
|
||||
self._check_valid()
|
||||
# pylint: disable=protected-access
|
||||
return self._parent._internal_get(self._index)._data
|
||||
|
||||
|
||||
class UnknownFieldSet(object):
|
||||
|
||||
"""UnknownField container"""
|
||||
|
||||
# Disallows assignment to other attributes.
|
||||
__slots__ = ['_values']
|
||||
|
||||
def __init__(self):
|
||||
self._values = []
|
||||
|
||||
def __getitem__(self, index):
|
||||
if self._values is None:
|
||||
raise ValueError('UnknownFields does not exist. '
|
||||
'The parent message might be cleared.')
|
||||
size = len(self._values)
|
||||
if index < 0:
|
||||
index += size
|
||||
if index < 0 or index >= size:
|
||||
raise IndexError('index %d out of range'.index)
|
||||
|
||||
return UnknownFieldRef(self, index)
|
||||
|
||||
def _internal_get(self, index):
|
||||
return self._values[index]
|
||||
|
||||
def __len__(self):
|
||||
if self._values is None:
|
||||
raise ValueError('UnknownFields does not exist. '
|
||||
'The parent message might be cleared.')
|
||||
return len(self._values)
|
||||
|
||||
def _add(self, field_number, wire_type, data):
|
||||
unknown_field = _UnknownField(field_number, wire_type, data)
|
||||
self._values.append(unknown_field)
|
||||
return unknown_field
|
||||
|
||||
def __iter__(self):
|
||||
for i in range(len(self)):
|
||||
yield UnknownFieldRef(self, i)
|
||||
|
||||
def _extend(self, other):
|
||||
if other is None:
|
||||
return
|
||||
# pylint: disable=protected-access
|
||||
self._values.extend(other._values)
|
||||
|
||||
def __eq__(self, other):
|
||||
if self is other:
|
||||
return True
|
||||
# Sort unknown fields because their order shouldn't
|
||||
# affect equality test.
|
||||
values = list(self._values)
|
||||
if other is None:
|
||||
return not values
|
||||
values.sort()
|
||||
# pylint: disable=protected-access
|
||||
other_values = sorted(other._values)
|
||||
return values == other_values
|
||||
|
||||
def _clear(self):
|
||||
for value in self._values:
|
||||
# pylint: disable=protected-access
|
||||
if isinstance(value._data, UnknownFieldSet):
|
||||
value._data._clear() # pylint: disable=protected-access
|
||||
self._values = None
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,829 @@
|
||||
# Protocol Buffers - Google's data interchange format
|
||||
# Copyright 2008 Google Inc. All rights reserved.
|
||||
# https://developers.google.com/protocol-buffers/
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions are
|
||||
# met:
|
||||
#
|
||||
# * Redistributions of source code must retain the above copyright
|
||||
# notice, this list of conditions and the following disclaimer.
|
||||
# * Redistributions in binary form must reproduce the above
|
||||
# copyright notice, this list of conditions and the following disclaimer
|
||||
# in the documentation and/or other materials provided with the
|
||||
# distribution.
|
||||
# * Neither the name of Google Inc. nor the names of its
|
||||
# contributors may be used to endorse or promote products derived from
|
||||
# this software without specific prior written permission.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
"""Code for encoding protocol message primitives.
|
||||
|
||||
Contains the logic for encoding every logical protocol field type
|
||||
into one of the 5 physical wire types.
|
||||
|
||||
This code is designed to push the Python interpreter's performance to the
|
||||
limits.
|
||||
|
||||
The basic idea is that at startup time, for every field (i.e. every
|
||||
FieldDescriptor) we construct two functions: a "sizer" and an "encoder". The
|
||||
sizer takes a value of this field's type and computes its byte size. The
|
||||
encoder takes a writer function and a value. It encodes the value into byte
|
||||
strings and invokes the writer function to write those strings. Typically the
|
||||
writer function is the write() method of a BytesIO.
|
||||
|
||||
We try to do as much work as possible when constructing the writer and the
|
||||
sizer rather than when calling them. In particular:
|
||||
* We copy any needed global functions to local variables, so that we do not need
|
||||
to do costly global table lookups at runtime.
|
||||
* Similarly, we try to do any attribute lookups at startup time if possible.
|
||||
* Every field's tag is encoded to bytes at startup, since it can't change at
|
||||
runtime.
|
||||
* Whatever component of the field size we can compute at startup, we do.
|
||||
* We *avoid* sharing code if doing so would make the code slower and not sharing
|
||||
does not burden us too much. For example, encoders for repeated fields do
|
||||
not just call the encoders for singular fields in a loop because this would
|
||||
add an extra function call overhead for every loop iteration; instead, we
|
||||
manually inline the single-value encoder into the loop.
|
||||
* If a Python function lacks a return statement, Python actually generates
|
||||
instructions to pop the result of the last statement off the stack, push
|
||||
None onto the stack, and then return that. If we really don't care what
|
||||
value is returned, then we can save two instructions by returning the
|
||||
result of the last statement. It looks funny but it helps.
|
||||
* We assume that type and bounds checking has happened at a higher level.
|
||||
"""
|
||||
|
||||
__author__ = 'kenton@google.com (Kenton Varda)'
|
||||
|
||||
import struct
|
||||
|
||||
from google.protobuf.internal import wire_format
|
||||
|
||||
|
||||
# This will overflow and thus become IEEE-754 "infinity". We would use
|
||||
# "float('inf')" but it doesn't work on Windows pre-Python-2.6.
|
||||
_POS_INF = 1e10000
|
||||
_NEG_INF = -_POS_INF
|
||||
|
||||
|
||||
def _VarintSize(value):
|
||||
"""Compute the size of a varint value."""
|
||||
if value <= 0x7f: return 1
|
||||
if value <= 0x3fff: return 2
|
||||
if value <= 0x1fffff: return 3
|
||||
if value <= 0xfffffff: return 4
|
||||
if value <= 0x7ffffffff: return 5
|
||||
if value <= 0x3ffffffffff: return 6
|
||||
if value <= 0x1ffffffffffff: return 7
|
||||
if value <= 0xffffffffffffff: return 8
|
||||
if value <= 0x7fffffffffffffff: return 9
|
||||
return 10
|
||||
|
||||
|
||||
def _SignedVarintSize(value):
|
||||
"""Compute the size of a signed varint value."""
|
||||
if value < 0: return 10
|
||||
if value <= 0x7f: return 1
|
||||
if value <= 0x3fff: return 2
|
||||
if value <= 0x1fffff: return 3
|
||||
if value <= 0xfffffff: return 4
|
||||
if value <= 0x7ffffffff: return 5
|
||||
if value <= 0x3ffffffffff: return 6
|
||||
if value <= 0x1ffffffffffff: return 7
|
||||
if value <= 0xffffffffffffff: return 8
|
||||
if value <= 0x7fffffffffffffff: return 9
|
||||
return 10
|
||||
|
||||
|
||||
def _TagSize(field_number):
|
||||
"""Returns the number of bytes required to serialize a tag with this field
|
||||
number."""
|
||||
# Just pass in type 0, since the type won't affect the tag+type size.
|
||||
return _VarintSize(wire_format.PackTag(field_number, 0))
|
||||
|
||||
|
||||
# --------------------------------------------------------------------
|
||||
# In this section we define some generic sizers. Each of these functions
|
||||
# takes parameters specific to a particular field type, e.g. int32 or fixed64.
|
||||
# It returns another function which in turn takes parameters specific to a
|
||||
# particular field, e.g. the field number and whether it is repeated or packed.
|
||||
# Look at the next section to see how these are used.
|
||||
|
||||
|
||||
def _SimpleSizer(compute_value_size):
|
||||
"""A sizer which uses the function compute_value_size to compute the size of
|
||||
each value. Typically compute_value_size is _VarintSize."""
|
||||
|
||||
def SpecificSizer(field_number, is_repeated, is_packed):
|
||||
tag_size = _TagSize(field_number)
|
||||
if is_packed:
|
||||
local_VarintSize = _VarintSize
|
||||
def PackedFieldSize(value):
|
||||
result = 0
|
||||
for element in value:
|
||||
result += compute_value_size(element)
|
||||
return result + local_VarintSize(result) + tag_size
|
||||
return PackedFieldSize
|
||||
elif is_repeated:
|
||||
def RepeatedFieldSize(value):
|
||||
result = tag_size * len(value)
|
||||
for element in value:
|
||||
result += compute_value_size(element)
|
||||
return result
|
||||
return RepeatedFieldSize
|
||||
else:
|
||||
def FieldSize(value):
|
||||
return tag_size + compute_value_size(value)
|
||||
return FieldSize
|
||||
|
||||
return SpecificSizer
|
||||
|
||||
|
||||
def _ModifiedSizer(compute_value_size, modify_value):
|
||||
"""Like SimpleSizer, but modify_value is invoked on each value before it is
|
||||
passed to compute_value_size. modify_value is typically ZigZagEncode."""
|
||||
|
||||
def SpecificSizer(field_number, is_repeated, is_packed):
|
||||
tag_size = _TagSize(field_number)
|
||||
if is_packed:
|
||||
local_VarintSize = _VarintSize
|
||||
def PackedFieldSize(value):
|
||||
result = 0
|
||||
for element in value:
|
||||
result += compute_value_size(modify_value(element))
|
||||
return result + local_VarintSize(result) + tag_size
|
||||
return PackedFieldSize
|
||||
elif is_repeated:
|
||||
def RepeatedFieldSize(value):
|
||||
result = tag_size * len(value)
|
||||
for element in value:
|
||||
result += compute_value_size(modify_value(element))
|
||||
return result
|
||||
return RepeatedFieldSize
|
||||
else:
|
||||
def FieldSize(value):
|
||||
return tag_size + compute_value_size(modify_value(value))
|
||||
return FieldSize
|
||||
|
||||
return SpecificSizer
|
||||
|
||||
|
||||
def _FixedSizer(value_size):
|
||||
"""Like _SimpleSizer except for a fixed-size field. The input is the size
|
||||
of one value."""
|
||||
|
||||
def SpecificSizer(field_number, is_repeated, is_packed):
|
||||
tag_size = _TagSize(field_number)
|
||||
if is_packed:
|
||||
local_VarintSize = _VarintSize
|
||||
def PackedFieldSize(value):
|
||||
result = len(value) * value_size
|
||||
return result + local_VarintSize(result) + tag_size
|
||||
return PackedFieldSize
|
||||
elif is_repeated:
|
||||
element_size = value_size + tag_size
|
||||
def RepeatedFieldSize(value):
|
||||
return len(value) * element_size
|
||||
return RepeatedFieldSize
|
||||
else:
|
||||
field_size = value_size + tag_size
|
||||
def FieldSize(value):
|
||||
return field_size
|
||||
return FieldSize
|
||||
|
||||
return SpecificSizer
|
||||
|
||||
|
||||
# ====================================================================
|
||||
# Here we declare a sizer constructor for each field type. Each "sizer
|
||||
# constructor" is a function that takes (field_number, is_repeated, is_packed)
|
||||
# as parameters and returns a sizer, which in turn takes a field value as
|
||||
# a parameter and returns its encoded size.
|
||||
|
||||
|
||||
Int32Sizer = Int64Sizer = EnumSizer = _SimpleSizer(_SignedVarintSize)
|
||||
|
||||
UInt32Sizer = UInt64Sizer = _SimpleSizer(_VarintSize)
|
||||
|
||||
SInt32Sizer = SInt64Sizer = _ModifiedSizer(
|
||||
_SignedVarintSize, wire_format.ZigZagEncode)
|
||||
|
||||
Fixed32Sizer = SFixed32Sizer = FloatSizer = _FixedSizer(4)
|
||||
Fixed64Sizer = SFixed64Sizer = DoubleSizer = _FixedSizer(8)
|
||||
|
||||
BoolSizer = _FixedSizer(1)
|
||||
|
||||
|
||||
def StringSizer(field_number, is_repeated, is_packed):
|
||||
"""Returns a sizer for a string field."""
|
||||
|
||||
tag_size = _TagSize(field_number)
|
||||
local_VarintSize = _VarintSize
|
||||
local_len = len
|
||||
assert not is_packed
|
||||
if is_repeated:
|
||||
def RepeatedFieldSize(value):
|
||||
result = tag_size * len(value)
|
||||
for element in value:
|
||||
l = local_len(element.encode('utf-8'))
|
||||
result += local_VarintSize(l) + l
|
||||
return result
|
||||
return RepeatedFieldSize
|
||||
else:
|
||||
def FieldSize(value):
|
||||
l = local_len(value.encode('utf-8'))
|
||||
return tag_size + local_VarintSize(l) + l
|
||||
return FieldSize
|
||||
|
||||
|
||||
def BytesSizer(field_number, is_repeated, is_packed):
|
||||
"""Returns a sizer for a bytes field."""
|
||||
|
||||
tag_size = _TagSize(field_number)
|
||||
local_VarintSize = _VarintSize
|
||||
local_len = len
|
||||
assert not is_packed
|
||||
if is_repeated:
|
||||
def RepeatedFieldSize(value):
|
||||
result = tag_size * len(value)
|
||||
for element in value:
|
||||
l = local_len(element)
|
||||
result += local_VarintSize(l) + l
|
||||
return result
|
||||
return RepeatedFieldSize
|
||||
else:
|
||||
def FieldSize(value):
|
||||
l = local_len(value)
|
||||
return tag_size + local_VarintSize(l) + l
|
||||
return FieldSize
|
||||
|
||||
|
||||
def GroupSizer(field_number, is_repeated, is_packed):
|
||||
"""Returns a sizer for a group field."""
|
||||
|
||||
tag_size = _TagSize(field_number) * 2
|
||||
assert not is_packed
|
||||
if is_repeated:
|
||||
def RepeatedFieldSize(value):
|
||||
result = tag_size * len(value)
|
||||
for element in value:
|
||||
result += element.ByteSize()
|
||||
return result
|
||||
return RepeatedFieldSize
|
||||
else:
|
||||
def FieldSize(value):
|
||||
return tag_size + value.ByteSize()
|
||||
return FieldSize
|
||||
|
||||
|
||||
def MessageSizer(field_number, is_repeated, is_packed):
|
||||
"""Returns a sizer for a message field."""
|
||||
|
||||
tag_size = _TagSize(field_number)
|
||||
local_VarintSize = _VarintSize
|
||||
assert not is_packed
|
||||
if is_repeated:
|
||||
def RepeatedFieldSize(value):
|
||||
result = tag_size * len(value)
|
||||
for element in value:
|
||||
l = element.ByteSize()
|
||||
result += local_VarintSize(l) + l
|
||||
return result
|
||||
return RepeatedFieldSize
|
||||
else:
|
||||
def FieldSize(value):
|
||||
l = value.ByteSize()
|
||||
return tag_size + local_VarintSize(l) + l
|
||||
return FieldSize
|
||||
|
||||
|
||||
# --------------------------------------------------------------------
|
||||
# MessageSet is special: it needs custom logic to compute its size properly.
|
||||
|
||||
|
||||
def MessageSetItemSizer(field_number):
|
||||
"""Returns a sizer for extensions of MessageSet.
|
||||
|
||||
The message set message looks like this:
|
||||
message MessageSet {
|
||||
repeated group Item = 1 {
|
||||
required int32 type_id = 2;
|
||||
required string message = 3;
|
||||
}
|
||||
}
|
||||
"""
|
||||
static_size = (_TagSize(1) * 2 + _TagSize(2) + _VarintSize(field_number) +
|
||||
_TagSize(3))
|
||||
local_VarintSize = _VarintSize
|
||||
|
||||
def FieldSize(value):
|
||||
l = value.ByteSize()
|
||||
return static_size + local_VarintSize(l) + l
|
||||
|
||||
return FieldSize
|
||||
|
||||
|
||||
# --------------------------------------------------------------------
|
||||
# Map is special: it needs custom logic to compute its size properly.
|
||||
|
||||
|
||||
def MapSizer(field_descriptor, is_message_map):
|
||||
"""Returns a sizer for a map field."""
|
||||
|
||||
# Can't look at field_descriptor.message_type._concrete_class because it may
|
||||
# not have been initialized yet.
|
||||
message_type = field_descriptor.message_type
|
||||
message_sizer = MessageSizer(field_descriptor.number, False, False)
|
||||
|
||||
def FieldSize(map_value):
|
||||
total = 0
|
||||
for key in map_value:
|
||||
value = map_value[key]
|
||||
# It's wasteful to create the messages and throw them away one second
|
||||
# later since we'll do the same for the actual encode. But there's not an
|
||||
# obvious way to avoid this within the current design without tons of code
|
||||
# duplication. For message map, value.ByteSize() should be called to
|
||||
# update the status.
|
||||
entry_msg = message_type._concrete_class(key=key, value=value)
|
||||
total += message_sizer(entry_msg)
|
||||
if is_message_map:
|
||||
value.ByteSize()
|
||||
return total
|
||||
|
||||
return FieldSize
|
||||
|
||||
# ====================================================================
|
||||
# Encoders!
|
||||
|
||||
|
||||
def _VarintEncoder():
|
||||
"""Return an encoder for a basic varint value (does not include tag)."""
|
||||
|
||||
local_int2byte = struct.Struct('>B').pack
|
||||
|
||||
def EncodeVarint(write, value, unused_deterministic=None):
|
||||
bits = value & 0x7f
|
||||
value >>= 7
|
||||
while value:
|
||||
write(local_int2byte(0x80|bits))
|
||||
bits = value & 0x7f
|
||||
value >>= 7
|
||||
return write(local_int2byte(bits))
|
||||
|
||||
return EncodeVarint
|
||||
|
||||
|
||||
def _SignedVarintEncoder():
|
||||
"""Return an encoder for a basic signed varint value (does not include
|
||||
tag)."""
|
||||
|
||||
local_int2byte = struct.Struct('>B').pack
|
||||
|
||||
def EncodeSignedVarint(write, value, unused_deterministic=None):
|
||||
if value < 0:
|
||||
value += (1 << 64)
|
||||
bits = value & 0x7f
|
||||
value >>= 7
|
||||
while value:
|
||||
write(local_int2byte(0x80|bits))
|
||||
bits = value & 0x7f
|
||||
value >>= 7
|
||||
return write(local_int2byte(bits))
|
||||
|
||||
return EncodeSignedVarint
|
||||
|
||||
|
||||
_EncodeVarint = _VarintEncoder()
|
||||
_EncodeSignedVarint = _SignedVarintEncoder()
|
||||
|
||||
|
||||
def _VarintBytes(value):
|
||||
"""Encode the given integer as a varint and return the bytes. This is only
|
||||
called at startup time so it doesn't need to be fast."""
|
||||
|
||||
pieces = []
|
||||
_EncodeVarint(pieces.append, value, True)
|
||||
return b"".join(pieces)
|
||||
|
||||
|
||||
def TagBytes(field_number, wire_type):
|
||||
"""Encode the given tag and return the bytes. Only called at startup."""
|
||||
|
||||
return bytes(_VarintBytes(wire_format.PackTag(field_number, wire_type)))
|
||||
|
||||
# --------------------------------------------------------------------
|
||||
# As with sizers (see above), we have a number of common encoder
|
||||
# implementations.
|
||||
|
||||
|
||||
def _SimpleEncoder(wire_type, encode_value, compute_value_size):
|
||||
"""Return a constructor for an encoder for fields of a particular type.
|
||||
|
||||
Args:
|
||||
wire_type: The field's wire type, for encoding tags.
|
||||
encode_value: A function which encodes an individual value, e.g.
|
||||
_EncodeVarint().
|
||||
compute_value_size: A function which computes the size of an individual
|
||||
value, e.g. _VarintSize().
|
||||
"""
|
||||
|
||||
def SpecificEncoder(field_number, is_repeated, is_packed):
|
||||
if is_packed:
|
||||
tag_bytes = TagBytes(field_number, wire_format.WIRETYPE_LENGTH_DELIMITED)
|
||||
local_EncodeVarint = _EncodeVarint
|
||||
def EncodePackedField(write, value, deterministic):
|
||||
write(tag_bytes)
|
||||
size = 0
|
||||
for element in value:
|
||||
size += compute_value_size(element)
|
||||
local_EncodeVarint(write, size, deterministic)
|
||||
for element in value:
|
||||
encode_value(write, element, deterministic)
|
||||
return EncodePackedField
|
||||
elif is_repeated:
|
||||
tag_bytes = TagBytes(field_number, wire_type)
|
||||
def EncodeRepeatedField(write, value, deterministic):
|
||||
for element in value:
|
||||
write(tag_bytes)
|
||||
encode_value(write, element, deterministic)
|
||||
return EncodeRepeatedField
|
||||
else:
|
||||
tag_bytes = TagBytes(field_number, wire_type)
|
||||
def EncodeField(write, value, deterministic):
|
||||
write(tag_bytes)
|
||||
return encode_value(write, value, deterministic)
|
||||
return EncodeField
|
||||
|
||||
return SpecificEncoder
|
||||
|
||||
|
||||
def _ModifiedEncoder(wire_type, encode_value, compute_value_size, modify_value):
|
||||
"""Like SimpleEncoder but additionally invokes modify_value on every value
|
||||
before passing it to encode_value. Usually modify_value is ZigZagEncode."""
|
||||
|
||||
def SpecificEncoder(field_number, is_repeated, is_packed):
|
||||
if is_packed:
|
||||
tag_bytes = TagBytes(field_number, wire_format.WIRETYPE_LENGTH_DELIMITED)
|
||||
local_EncodeVarint = _EncodeVarint
|
||||
def EncodePackedField(write, value, deterministic):
|
||||
write(tag_bytes)
|
||||
size = 0
|
||||
for element in value:
|
||||
size += compute_value_size(modify_value(element))
|
||||
local_EncodeVarint(write, size, deterministic)
|
||||
for element in value:
|
||||
encode_value(write, modify_value(element), deterministic)
|
||||
return EncodePackedField
|
||||
elif is_repeated:
|
||||
tag_bytes = TagBytes(field_number, wire_type)
|
||||
def EncodeRepeatedField(write, value, deterministic):
|
||||
for element in value:
|
||||
write(tag_bytes)
|
||||
encode_value(write, modify_value(element), deterministic)
|
||||
return EncodeRepeatedField
|
||||
else:
|
||||
tag_bytes = TagBytes(field_number, wire_type)
|
||||
def EncodeField(write, value, deterministic):
|
||||
write(tag_bytes)
|
||||
return encode_value(write, modify_value(value), deterministic)
|
||||
return EncodeField
|
||||
|
||||
return SpecificEncoder
|
||||
|
||||
|
||||
def _StructPackEncoder(wire_type, format):
|
||||
"""Return a constructor for an encoder for a fixed-width field.
|
||||
|
||||
Args:
|
||||
wire_type: The field's wire type, for encoding tags.
|
||||
format: The format string to pass to struct.pack().
|
||||
"""
|
||||
|
||||
value_size = struct.calcsize(format)
|
||||
|
||||
def SpecificEncoder(field_number, is_repeated, is_packed):
|
||||
local_struct_pack = struct.pack
|
||||
if is_packed:
|
||||
tag_bytes = TagBytes(field_number, wire_format.WIRETYPE_LENGTH_DELIMITED)
|
||||
local_EncodeVarint = _EncodeVarint
|
||||
def EncodePackedField(write, value, deterministic):
|
||||
write(tag_bytes)
|
||||
local_EncodeVarint(write, len(value) * value_size, deterministic)
|
||||
for element in value:
|
||||
write(local_struct_pack(format, element))
|
||||
return EncodePackedField
|
||||
elif is_repeated:
|
||||
tag_bytes = TagBytes(field_number, wire_type)
|
||||
def EncodeRepeatedField(write, value, unused_deterministic=None):
|
||||
for element in value:
|
||||
write(tag_bytes)
|
||||
write(local_struct_pack(format, element))
|
||||
return EncodeRepeatedField
|
||||
else:
|
||||
tag_bytes = TagBytes(field_number, wire_type)
|
||||
def EncodeField(write, value, unused_deterministic=None):
|
||||
write(tag_bytes)
|
||||
return write(local_struct_pack(format, value))
|
||||
return EncodeField
|
||||
|
||||
return SpecificEncoder
|
||||
|
||||
|
||||
def _FloatingPointEncoder(wire_type, format):
|
||||
"""Return a constructor for an encoder for float fields.
|
||||
|
||||
This is like StructPackEncoder, but catches errors that may be due to
|
||||
passing non-finite floating-point values to struct.pack, and makes a
|
||||
second attempt to encode those values.
|
||||
|
||||
Args:
|
||||
wire_type: The field's wire type, for encoding tags.
|
||||
format: The format string to pass to struct.pack().
|
||||
"""
|
||||
|
||||
value_size = struct.calcsize(format)
|
||||
if value_size == 4:
|
||||
def EncodeNonFiniteOrRaise(write, value):
|
||||
# Remember that the serialized form uses little-endian byte order.
|
||||
if value == _POS_INF:
|
||||
write(b'\x00\x00\x80\x7F')
|
||||
elif value == _NEG_INF:
|
||||
write(b'\x00\x00\x80\xFF')
|
||||
elif value != value: # NaN
|
||||
write(b'\x00\x00\xC0\x7F')
|
||||
else:
|
||||
raise
|
||||
elif value_size == 8:
|
||||
def EncodeNonFiniteOrRaise(write, value):
|
||||
if value == _POS_INF:
|
||||
write(b'\x00\x00\x00\x00\x00\x00\xF0\x7F')
|
||||
elif value == _NEG_INF:
|
||||
write(b'\x00\x00\x00\x00\x00\x00\xF0\xFF')
|
||||
elif value != value: # NaN
|
||||
write(b'\x00\x00\x00\x00\x00\x00\xF8\x7F')
|
||||
else:
|
||||
raise
|
||||
else:
|
||||
raise ValueError('Can\'t encode floating-point values that are '
|
||||
'%d bytes long (only 4 or 8)' % value_size)
|
||||
|
||||
def SpecificEncoder(field_number, is_repeated, is_packed):
|
||||
local_struct_pack = struct.pack
|
||||
if is_packed:
|
||||
tag_bytes = TagBytes(field_number, wire_format.WIRETYPE_LENGTH_DELIMITED)
|
||||
local_EncodeVarint = _EncodeVarint
|
||||
def EncodePackedField(write, value, deterministic):
|
||||
write(tag_bytes)
|
||||
local_EncodeVarint(write, len(value) * value_size, deterministic)
|
||||
for element in value:
|
||||
# This try/except block is going to be faster than any code that
|
||||
# we could write to check whether element is finite.
|
||||
try:
|
||||
write(local_struct_pack(format, element))
|
||||
except SystemError:
|
||||
EncodeNonFiniteOrRaise(write, element)
|
||||
return EncodePackedField
|
||||
elif is_repeated:
|
||||
tag_bytes = TagBytes(field_number, wire_type)
|
||||
def EncodeRepeatedField(write, value, unused_deterministic=None):
|
||||
for element in value:
|
||||
write(tag_bytes)
|
||||
try:
|
||||
write(local_struct_pack(format, element))
|
||||
except SystemError:
|
||||
EncodeNonFiniteOrRaise(write, element)
|
||||
return EncodeRepeatedField
|
||||
else:
|
||||
tag_bytes = TagBytes(field_number, wire_type)
|
||||
def EncodeField(write, value, unused_deterministic=None):
|
||||
write(tag_bytes)
|
||||
try:
|
||||
write(local_struct_pack(format, value))
|
||||
except SystemError:
|
||||
EncodeNonFiniteOrRaise(write, value)
|
||||
return EncodeField
|
||||
|
||||
return SpecificEncoder
|
||||
|
||||
|
||||
# ====================================================================
|
||||
# Here we declare an encoder constructor for each field type. These work
|
||||
# very similarly to sizer constructors, described earlier.
|
||||
|
||||
|
||||
Int32Encoder = Int64Encoder = EnumEncoder = _SimpleEncoder(
|
||||
wire_format.WIRETYPE_VARINT, _EncodeSignedVarint, _SignedVarintSize)
|
||||
|
||||
UInt32Encoder = UInt64Encoder = _SimpleEncoder(
|
||||
wire_format.WIRETYPE_VARINT, _EncodeVarint, _VarintSize)
|
||||
|
||||
SInt32Encoder = SInt64Encoder = _ModifiedEncoder(
|
||||
wire_format.WIRETYPE_VARINT, _EncodeVarint, _VarintSize,
|
||||
wire_format.ZigZagEncode)
|
||||
|
||||
# Note that Python conveniently guarantees that when using the '<' prefix on
|
||||
# formats, they will also have the same size across all platforms (as opposed
|
||||
# to without the prefix, where their sizes depend on the C compiler's basic
|
||||
# type sizes).
|
||||
Fixed32Encoder = _StructPackEncoder(wire_format.WIRETYPE_FIXED32, '<I')
|
||||
Fixed64Encoder = _StructPackEncoder(wire_format.WIRETYPE_FIXED64, '<Q')
|
||||
SFixed32Encoder = _StructPackEncoder(wire_format.WIRETYPE_FIXED32, '<i')
|
||||
SFixed64Encoder = _StructPackEncoder(wire_format.WIRETYPE_FIXED64, '<q')
|
||||
FloatEncoder = _FloatingPointEncoder(wire_format.WIRETYPE_FIXED32, '<f')
|
||||
DoubleEncoder = _FloatingPointEncoder(wire_format.WIRETYPE_FIXED64, '<d')
|
||||
|
||||
|
||||
def BoolEncoder(field_number, is_repeated, is_packed):
|
||||
"""Returns an encoder for a boolean field."""
|
||||
|
||||
false_byte = b'\x00'
|
||||
true_byte = b'\x01'
|
||||
if is_packed:
|
||||
tag_bytes = TagBytes(field_number, wire_format.WIRETYPE_LENGTH_DELIMITED)
|
||||
local_EncodeVarint = _EncodeVarint
|
||||
def EncodePackedField(write, value, deterministic):
|
||||
write(tag_bytes)
|
||||
local_EncodeVarint(write, len(value), deterministic)
|
||||
for element in value:
|
||||
if element:
|
||||
write(true_byte)
|
||||
else:
|
||||
write(false_byte)
|
||||
return EncodePackedField
|
||||
elif is_repeated:
|
||||
tag_bytes = TagBytes(field_number, wire_format.WIRETYPE_VARINT)
|
||||
def EncodeRepeatedField(write, value, unused_deterministic=None):
|
||||
for element in value:
|
||||
write(tag_bytes)
|
||||
if element:
|
||||
write(true_byte)
|
||||
else:
|
||||
write(false_byte)
|
||||
return EncodeRepeatedField
|
||||
else:
|
||||
tag_bytes = TagBytes(field_number, wire_format.WIRETYPE_VARINT)
|
||||
def EncodeField(write, value, unused_deterministic=None):
|
||||
write(tag_bytes)
|
||||
if value:
|
||||
return write(true_byte)
|
||||
return write(false_byte)
|
||||
return EncodeField
|
||||
|
||||
|
||||
def StringEncoder(field_number, is_repeated, is_packed):
|
||||
"""Returns an encoder for a string field."""
|
||||
|
||||
tag = TagBytes(field_number, wire_format.WIRETYPE_LENGTH_DELIMITED)
|
||||
local_EncodeVarint = _EncodeVarint
|
||||
local_len = len
|
||||
assert not is_packed
|
||||
if is_repeated:
|
||||
def EncodeRepeatedField(write, value, deterministic):
|
||||
for element in value:
|
||||
encoded = element.encode('utf-8')
|
||||
write(tag)
|
||||
local_EncodeVarint(write, local_len(encoded), deterministic)
|
||||
write(encoded)
|
||||
return EncodeRepeatedField
|
||||
else:
|
||||
def EncodeField(write, value, deterministic):
|
||||
encoded = value.encode('utf-8')
|
||||
write(tag)
|
||||
local_EncodeVarint(write, local_len(encoded), deterministic)
|
||||
return write(encoded)
|
||||
return EncodeField
|
||||
|
||||
|
||||
def BytesEncoder(field_number, is_repeated, is_packed):
|
||||
"""Returns an encoder for a bytes field."""
|
||||
|
||||
tag = TagBytes(field_number, wire_format.WIRETYPE_LENGTH_DELIMITED)
|
||||
local_EncodeVarint = _EncodeVarint
|
||||
local_len = len
|
||||
assert not is_packed
|
||||
if is_repeated:
|
||||
def EncodeRepeatedField(write, value, deterministic):
|
||||
for element in value:
|
||||
write(tag)
|
||||
local_EncodeVarint(write, local_len(element), deterministic)
|
||||
write(element)
|
||||
return EncodeRepeatedField
|
||||
else:
|
||||
def EncodeField(write, value, deterministic):
|
||||
write(tag)
|
||||
local_EncodeVarint(write, local_len(value), deterministic)
|
||||
return write(value)
|
||||
return EncodeField
|
||||
|
||||
|
||||
def GroupEncoder(field_number, is_repeated, is_packed):
|
||||
"""Returns an encoder for a group field."""
|
||||
|
||||
start_tag = TagBytes(field_number, wire_format.WIRETYPE_START_GROUP)
|
||||
end_tag = TagBytes(field_number, wire_format.WIRETYPE_END_GROUP)
|
||||
assert not is_packed
|
||||
if is_repeated:
|
||||
def EncodeRepeatedField(write, value, deterministic):
|
||||
for element in value:
|
||||
write(start_tag)
|
||||
element._InternalSerialize(write, deterministic)
|
||||
write(end_tag)
|
||||
return EncodeRepeatedField
|
||||
else:
|
||||
def EncodeField(write, value, deterministic):
|
||||
write(start_tag)
|
||||
value._InternalSerialize(write, deterministic)
|
||||
return write(end_tag)
|
||||
return EncodeField
|
||||
|
||||
|
||||
def MessageEncoder(field_number, is_repeated, is_packed):
|
||||
"""Returns an encoder for a message field."""
|
||||
|
||||
tag = TagBytes(field_number, wire_format.WIRETYPE_LENGTH_DELIMITED)
|
||||
local_EncodeVarint = _EncodeVarint
|
||||
assert not is_packed
|
||||
if is_repeated:
|
||||
def EncodeRepeatedField(write, value, deterministic):
|
||||
for element in value:
|
||||
write(tag)
|
||||
local_EncodeVarint(write, element.ByteSize(), deterministic)
|
||||
element._InternalSerialize(write, deterministic)
|
||||
return EncodeRepeatedField
|
||||
else:
|
||||
def EncodeField(write, value, deterministic):
|
||||
write(tag)
|
||||
local_EncodeVarint(write, value.ByteSize(), deterministic)
|
||||
return value._InternalSerialize(write, deterministic)
|
||||
return EncodeField
|
||||
|
||||
|
||||
# --------------------------------------------------------------------
|
||||
# As before, MessageSet is special.
|
||||
|
||||
|
||||
def MessageSetItemEncoder(field_number):
|
||||
"""Encoder for extensions of MessageSet.
|
||||
|
||||
The message set message looks like this:
|
||||
message MessageSet {
|
||||
repeated group Item = 1 {
|
||||
required int32 type_id = 2;
|
||||
required string message = 3;
|
||||
}
|
||||
}
|
||||
"""
|
||||
start_bytes = b"".join([
|
||||
TagBytes(1, wire_format.WIRETYPE_START_GROUP),
|
||||
TagBytes(2, wire_format.WIRETYPE_VARINT),
|
||||
_VarintBytes(field_number),
|
||||
TagBytes(3, wire_format.WIRETYPE_LENGTH_DELIMITED)])
|
||||
end_bytes = TagBytes(1, wire_format.WIRETYPE_END_GROUP)
|
||||
local_EncodeVarint = _EncodeVarint
|
||||
|
||||
def EncodeField(write, value, deterministic):
|
||||
write(start_bytes)
|
||||
local_EncodeVarint(write, value.ByteSize(), deterministic)
|
||||
value._InternalSerialize(write, deterministic)
|
||||
return write(end_bytes)
|
||||
|
||||
return EncodeField
|
||||
|
||||
|
||||
# --------------------------------------------------------------------
|
||||
# As before, Map is special.
|
||||
|
||||
|
||||
def MapEncoder(field_descriptor):
|
||||
"""Encoder for extensions of MessageSet.
|
||||
|
||||
Maps always have a wire format like this:
|
||||
message MapEntry {
|
||||
key_type key = 1;
|
||||
value_type value = 2;
|
||||
}
|
||||
repeated MapEntry map = N;
|
||||
"""
|
||||
# Can't look at field_descriptor.message_type._concrete_class because it may
|
||||
# not have been initialized yet.
|
||||
message_type = field_descriptor.message_type
|
||||
encode_message = MessageEncoder(field_descriptor.number, False, False)
|
||||
|
||||
def EncodeField(write, value, deterministic):
|
||||
value_keys = sorted(value.keys()) if deterministic else value
|
||||
for key in value_keys:
|
||||
entry_msg = message_type._concrete_class(key=key, value=value[key])
|
||||
encode_message(write, entry_msg, deterministic)
|
||||
|
||||
return EncodeField
|
||||
@@ -0,0 +1,115 @@
|
||||
# Protocol Buffers - Google's data interchange format
|
||||
# Copyright 2008 Google Inc. All rights reserved.
|
||||
# https://developers.google.com/protocol-buffers/
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions are
|
||||
# met:
|
||||
#
|
||||
# * Redistributions of source code must retain the above copyright
|
||||
# notice, this list of conditions and the following disclaimer.
|
||||
# * Redistributions in binary form must reproduce the above
|
||||
# copyright notice, this list of conditions and the following disclaimer
|
||||
# in the documentation and/or other materials provided with the
|
||||
# distribution.
|
||||
# * Neither the name of Google Inc. nor the names of its
|
||||
# contributors may be used to endorse or promote products derived from
|
||||
# this software without specific prior written permission.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
"""A simple wrapper around enum types to expose utility functions.
|
||||
|
||||
Instances are created as properties with the same name as the enum they wrap
|
||||
on proto classes. For usage, see:
|
||||
reflection_test.py
|
||||
"""
|
||||
|
||||
__author__ = 'rabsatt@google.com (Kevin Rabsatt)'
|
||||
|
||||
|
||||
class EnumTypeWrapper(object):
|
||||
"""A utility for finding the names of enum values."""
|
||||
|
||||
DESCRIPTOR = None
|
||||
|
||||
def __init__(self, enum_type):
|
||||
"""Inits EnumTypeWrapper with an EnumDescriptor."""
|
||||
self._enum_type = enum_type
|
||||
self.DESCRIPTOR = enum_type # pylint: disable=invalid-name
|
||||
|
||||
def Name(self, number): # pylint: disable=invalid-name
|
||||
"""Returns a string containing the name of an enum value."""
|
||||
try:
|
||||
return self._enum_type.values_by_number[number].name
|
||||
except KeyError:
|
||||
pass # fall out to break exception chaining
|
||||
|
||||
if not isinstance(number, int):
|
||||
raise TypeError(
|
||||
'Enum value for {} must be an int, but got {} {!r}.'.format(
|
||||
self._enum_type.name, type(number), number))
|
||||
else:
|
||||
# repr here to handle the odd case when you pass in a boolean.
|
||||
raise ValueError('Enum {} has no name defined for value {!r}'.format(
|
||||
self._enum_type.name, number))
|
||||
|
||||
def Value(self, name): # pylint: disable=invalid-name
|
||||
"""Returns the value corresponding to the given enum name."""
|
||||
try:
|
||||
return self._enum_type.values_by_name[name].number
|
||||
except KeyError:
|
||||
pass # fall out to break exception chaining
|
||||
raise ValueError('Enum {} has no value defined for name {!r}'.format(
|
||||
self._enum_type.name, name))
|
||||
|
||||
def keys(self):
|
||||
"""Return a list of the string names in the enum.
|
||||
|
||||
Returns:
|
||||
A list of strs, in the order they were defined in the .proto file.
|
||||
"""
|
||||
|
||||
return [value_descriptor.name
|
||||
for value_descriptor in self._enum_type.values]
|
||||
|
||||
def values(self):
|
||||
"""Return a list of the integer values in the enum.
|
||||
|
||||
Returns:
|
||||
A list of ints, in the order they were defined in the .proto file.
|
||||
"""
|
||||
|
||||
return [value_descriptor.number
|
||||
for value_descriptor in self._enum_type.values]
|
||||
|
||||
def items(self):
|
||||
"""Return a list of the (name, value) pairs of the enum.
|
||||
|
||||
Returns:
|
||||
A list of (str, int) pairs, in the order they were defined
|
||||
in the .proto file.
|
||||
"""
|
||||
return [(value_descriptor.name, value_descriptor.number)
|
||||
for value_descriptor in self._enum_type.values]
|
||||
|
||||
def __getattr__(self, name):
|
||||
"""Returns the value corresponding to the given enum name."""
|
||||
try:
|
||||
return super(
|
||||
EnumTypeWrapper,
|
||||
self).__getattribute__('_enum_type').values_by_name[name].number
|
||||
except KeyError:
|
||||
pass # fall out to break exception chaining
|
||||
raise AttributeError('Enum {} has no value defined for name {!r}'.format(
|
||||
self._enum_type.name, name))
|
||||
@@ -0,0 +1,213 @@
|
||||
# Protocol Buffers - Google's data interchange format
|
||||
# Copyright 2008 Google Inc. All rights reserved.
|
||||
# https://developers.google.com/protocol-buffers/
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions are
|
||||
# met:
|
||||
#
|
||||
# * Redistributions of source code must retain the above copyright
|
||||
# notice, this list of conditions and the following disclaimer.
|
||||
# * Redistributions in binary form must reproduce the above
|
||||
# copyright notice, this list of conditions and the following disclaimer
|
||||
# in the documentation and/or other materials provided with the
|
||||
# distribution.
|
||||
# * Neither the name of Google Inc. nor the names of its
|
||||
# contributors may be used to endorse or promote products derived from
|
||||
# this software without specific prior written permission.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
"""Contains _ExtensionDict class to represent extensions.
|
||||
"""
|
||||
|
||||
from google.protobuf.internal import type_checkers
|
||||
from google.protobuf.descriptor import FieldDescriptor
|
||||
|
||||
|
||||
def _VerifyExtensionHandle(message, extension_handle):
|
||||
"""Verify that the given extension handle is valid."""
|
||||
|
||||
if not isinstance(extension_handle, FieldDescriptor):
|
||||
raise KeyError('HasExtension() expects an extension handle, got: %s' %
|
||||
extension_handle)
|
||||
|
||||
if not extension_handle.is_extension:
|
||||
raise KeyError('"%s" is not an extension.' % extension_handle.full_name)
|
||||
|
||||
if not extension_handle.containing_type:
|
||||
raise KeyError('"%s" is missing a containing_type.'
|
||||
% extension_handle.full_name)
|
||||
|
||||
if extension_handle.containing_type is not message.DESCRIPTOR:
|
||||
raise KeyError('Extension "%s" extends message type "%s", but this '
|
||||
'message is of type "%s".' %
|
||||
(extension_handle.full_name,
|
||||
extension_handle.containing_type.full_name,
|
||||
message.DESCRIPTOR.full_name))
|
||||
|
||||
|
||||
# TODO(robinson): Unify error handling of "unknown extension" crap.
|
||||
# TODO(robinson): Support iteritems()-style iteration over all
|
||||
# extensions with the "has" bits turned on?
|
||||
class _ExtensionDict(object):
|
||||
|
||||
"""Dict-like container for Extension fields on proto instances.
|
||||
|
||||
Note that in all cases we expect extension handles to be
|
||||
FieldDescriptors.
|
||||
"""
|
||||
|
||||
def __init__(self, extended_message):
|
||||
"""
|
||||
Args:
|
||||
extended_message: Message instance for which we are the Extensions dict.
|
||||
"""
|
||||
self._extended_message = extended_message
|
||||
|
||||
def __getitem__(self, extension_handle):
|
||||
"""Returns the current value of the given extension handle."""
|
||||
|
||||
_VerifyExtensionHandle(self._extended_message, extension_handle)
|
||||
|
||||
result = self._extended_message._fields.get(extension_handle)
|
||||
if result is not None:
|
||||
return result
|
||||
|
||||
if extension_handle.label == FieldDescriptor.LABEL_REPEATED:
|
||||
result = extension_handle._default_constructor(self._extended_message)
|
||||
elif extension_handle.cpp_type == FieldDescriptor.CPPTYPE_MESSAGE:
|
||||
message_type = extension_handle.message_type
|
||||
if not hasattr(message_type, '_concrete_class'):
|
||||
# pylint: disable=protected-access
|
||||
self._extended_message._FACTORY.GetPrototype(message_type)
|
||||
assert getattr(extension_handle.message_type, '_concrete_class', None), (
|
||||
'Uninitialized concrete class found for field %r (message type %r)'
|
||||
% (extension_handle.full_name,
|
||||
extension_handle.message_type.full_name))
|
||||
result = extension_handle.message_type._concrete_class()
|
||||
try:
|
||||
result._SetListener(self._extended_message._listener_for_children)
|
||||
except ReferenceError:
|
||||
pass
|
||||
else:
|
||||
# Singular scalar -- just return the default without inserting into the
|
||||
# dict.
|
||||
return extension_handle.default_value
|
||||
|
||||
# Atomically check if another thread has preempted us and, if not, swap
|
||||
# in the new object we just created. If someone has preempted us, we
|
||||
# take that object and discard ours.
|
||||
# WARNING: We are relying on setdefault() being atomic. This is true
|
||||
# in CPython but we haven't investigated others. This warning appears
|
||||
# in several other locations in this file.
|
||||
result = self._extended_message._fields.setdefault(
|
||||
extension_handle, result)
|
||||
|
||||
return result
|
||||
|
||||
def __eq__(self, other):
|
||||
if not isinstance(other, self.__class__):
|
||||
return False
|
||||
|
||||
my_fields = self._extended_message.ListFields()
|
||||
other_fields = other._extended_message.ListFields()
|
||||
|
||||
# Get rid of non-extension fields.
|
||||
my_fields = [field for field in my_fields if field.is_extension]
|
||||
other_fields = [field for field in other_fields if field.is_extension]
|
||||
|
||||
return my_fields == other_fields
|
||||
|
||||
def __ne__(self, other):
|
||||
return not self == other
|
||||
|
||||
def __len__(self):
|
||||
fields = self._extended_message.ListFields()
|
||||
# Get rid of non-extension fields.
|
||||
extension_fields = [field for field in fields if field[0].is_extension]
|
||||
return len(extension_fields)
|
||||
|
||||
def __hash__(self):
|
||||
raise TypeError('unhashable object')
|
||||
|
||||
# Note that this is only meaningful for non-repeated, scalar extension
|
||||
# fields. Note also that we may have to call _Modified() when we do
|
||||
# successfully set a field this way, to set any necessary "has" bits in the
|
||||
# ancestors of the extended message.
|
||||
def __setitem__(self, extension_handle, value):
|
||||
"""If extension_handle specifies a non-repeated, scalar extension
|
||||
field, sets the value of that field.
|
||||
"""
|
||||
|
||||
_VerifyExtensionHandle(self._extended_message, extension_handle)
|
||||
|
||||
if (extension_handle.label == FieldDescriptor.LABEL_REPEATED or
|
||||
extension_handle.cpp_type == FieldDescriptor.CPPTYPE_MESSAGE):
|
||||
raise TypeError(
|
||||
'Cannot assign to extension "%s" because it is a repeated or '
|
||||
'composite type.' % extension_handle.full_name)
|
||||
|
||||
# It's slightly wasteful to lookup the type checker each time,
|
||||
# but we expect this to be a vanishingly uncommon case anyway.
|
||||
type_checker = type_checkers.GetTypeChecker(extension_handle)
|
||||
# pylint: disable=protected-access
|
||||
self._extended_message._fields[extension_handle] = (
|
||||
type_checker.CheckValue(value))
|
||||
self._extended_message._Modified()
|
||||
|
||||
def __delitem__(self, extension_handle):
|
||||
self._extended_message.ClearExtension(extension_handle)
|
||||
|
||||
def _FindExtensionByName(self, name):
|
||||
"""Tries to find a known extension with the specified name.
|
||||
|
||||
Args:
|
||||
name: Extension full name.
|
||||
|
||||
Returns:
|
||||
Extension field descriptor.
|
||||
"""
|
||||
return self._extended_message._extensions_by_name.get(name, None)
|
||||
|
||||
def _FindExtensionByNumber(self, number):
|
||||
"""Tries to find a known extension with the field number.
|
||||
|
||||
Args:
|
||||
number: Extension field number.
|
||||
|
||||
Returns:
|
||||
Extension field descriptor.
|
||||
"""
|
||||
return self._extended_message._extensions_by_number.get(number, None)
|
||||
|
||||
def __iter__(self):
|
||||
# Return a generator over the populated extension fields
|
||||
return (f[0] for f in self._extended_message.ListFields()
|
||||
if f[0].is_extension)
|
||||
|
||||
def __contains__(self, extension_handle):
|
||||
_VerifyExtensionHandle(self._extended_message, extension_handle)
|
||||
|
||||
if extension_handle not in self._extended_message._fields:
|
||||
return False
|
||||
|
||||
if extension_handle.label == FieldDescriptor.LABEL_REPEATED:
|
||||
return bool(self._extended_message._fields.get(extension_handle))
|
||||
|
||||
if extension_handle.cpp_type == FieldDescriptor.CPPTYPE_MESSAGE:
|
||||
value = self._extended_message._fields.get(extension_handle)
|
||||
# pylint: disable=protected-access
|
||||
return value is not None and value._is_present_in_parent
|
||||
|
||||
return True
|
||||
@@ -0,0 +1,78 @@
|
||||
# Protocol Buffers - Google's data interchange format
|
||||
# Copyright 2008 Google Inc. All rights reserved.
|
||||
# https://developers.google.com/protocol-buffers/
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions are
|
||||
# met:
|
||||
#
|
||||
# * Redistributions of source code must retain the above copyright
|
||||
# notice, this list of conditions and the following disclaimer.
|
||||
# * Redistributions in binary form must reproduce the above
|
||||
# copyright notice, this list of conditions and the following disclaimer
|
||||
# in the documentation and/or other materials provided with the
|
||||
# distribution.
|
||||
# * Neither the name of Google Inc. nor the names of its
|
||||
# contributors may be used to endorse or promote products derived from
|
||||
# this software without specific prior written permission.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
"""Defines a listener interface for observing certain
|
||||
state transitions on Message objects.
|
||||
|
||||
Also defines a null implementation of this interface.
|
||||
"""
|
||||
|
||||
__author__ = 'robinson@google.com (Will Robinson)'
|
||||
|
||||
|
||||
class MessageListener(object):
|
||||
|
||||
"""Listens for modifications made to a message. Meant to be registered via
|
||||
Message._SetListener().
|
||||
|
||||
Attributes:
|
||||
dirty: If True, then calling Modified() would be a no-op. This can be
|
||||
used to avoid these calls entirely in the common case.
|
||||
"""
|
||||
|
||||
def Modified(self):
|
||||
"""Called every time the message is modified in such a way that the parent
|
||||
message may need to be updated. This currently means either:
|
||||
(a) The message was modified for the first time, so the parent message
|
||||
should henceforth mark the message as present.
|
||||
(b) The message's cached byte size became dirty -- i.e. the message was
|
||||
modified for the first time after a previous call to ByteSize().
|
||||
Therefore the parent should also mark its byte size as dirty.
|
||||
Note that (a) implies (b), since new objects start out with a client cached
|
||||
size (zero). However, we document (a) explicitly because it is important.
|
||||
|
||||
Modified() will *only* be called in response to one of these two events --
|
||||
not every time the sub-message is modified.
|
||||
|
||||
Note that if the listener's |dirty| attribute is true, then calling
|
||||
Modified at the moment would be a no-op, so it can be skipped. Performance-
|
||||
sensitive callers should check this attribute directly before calling since
|
||||
it will be true most of the time.
|
||||
"""
|
||||
|
||||
raise NotImplementedError
|
||||
|
||||
|
||||
class NullMessageListener(object):
|
||||
|
||||
"""No-op MessageListener implementation."""
|
||||
|
||||
def Modified(self):
|
||||
pass
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,410 @@
|
||||
# Protocol Buffers - Google's data interchange format
|
||||
# Copyright 2008 Google Inc. All rights reserved.
|
||||
# https://developers.google.com/protocol-buffers/
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions are
|
||||
# met:
|
||||
#
|
||||
# * Redistributions of source code must retain the above copyright
|
||||
# notice, this list of conditions and the following disclaimer.
|
||||
# * Redistributions in binary form must reproduce the above
|
||||
# copyright notice, this list of conditions and the following disclaimer
|
||||
# in the documentation and/or other materials provided with the
|
||||
# distribution.
|
||||
# * Neither the name of Google Inc. nor the names of its
|
||||
# contributors may be used to endorse or promote products derived from
|
||||
# this software without specific prior written permission.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
"""Provides type checking routines.
|
||||
|
||||
This module defines type checking utilities in the forms of dictionaries:
|
||||
|
||||
VALUE_CHECKERS: A dictionary of field types and a value validation object.
|
||||
TYPE_TO_BYTE_SIZE_FN: A dictionary with field types and a size computing
|
||||
function.
|
||||
TYPE_TO_SERIALIZE_METHOD: A dictionary with field types and serialization
|
||||
function.
|
||||
FIELD_TYPE_TO_WIRE_TYPE: A dictionary with field typed and their
|
||||
corresponding wire types.
|
||||
TYPE_TO_DESERIALIZE_METHOD: A dictionary with field types and deserialization
|
||||
function.
|
||||
"""
|
||||
|
||||
__author__ = 'robinson@google.com (Will Robinson)'
|
||||
|
||||
import ctypes
|
||||
import numbers
|
||||
|
||||
from google.protobuf.internal import api_implementation
|
||||
from google.protobuf.internal import decoder
|
||||
from google.protobuf.internal import encoder
|
||||
from google.protobuf.internal import wire_format
|
||||
from google.protobuf import descriptor
|
||||
|
||||
_FieldDescriptor = descriptor.FieldDescriptor
|
||||
|
||||
|
||||
def TruncateToFourByteFloat(original):
|
||||
return ctypes.c_float(original).value
|
||||
|
||||
|
||||
def ToShortestFloat(original):
|
||||
"""Returns the shortest float that has same value in wire."""
|
||||
# All 4 byte floats have between 6 and 9 significant digits, so we
|
||||
# start with 6 as the lower bound.
|
||||
# It has to be iterative because use '.9g' directly can not get rid
|
||||
# of the noises for most values. For example if set a float_field=0.9
|
||||
# use '.9g' will print 0.899999976.
|
||||
precision = 6
|
||||
rounded = float('{0:.{1}g}'.format(original, precision))
|
||||
while TruncateToFourByteFloat(rounded) != original:
|
||||
precision += 1
|
||||
rounded = float('{0:.{1}g}'.format(original, precision))
|
||||
return rounded
|
||||
|
||||
|
||||
def SupportsOpenEnums(field_descriptor):
|
||||
return field_descriptor.containing_type.syntax == "proto3"
|
||||
|
||||
def GetTypeChecker(field):
|
||||
"""Returns a type checker for a message field of the specified types.
|
||||
|
||||
Args:
|
||||
field: FieldDescriptor object for this field.
|
||||
|
||||
Returns:
|
||||
An instance of TypeChecker which can be used to verify the types
|
||||
of values assigned to a field of the specified type.
|
||||
"""
|
||||
if (field.cpp_type == _FieldDescriptor.CPPTYPE_STRING and
|
||||
field.type == _FieldDescriptor.TYPE_STRING):
|
||||
return UnicodeValueChecker()
|
||||
if field.cpp_type == _FieldDescriptor.CPPTYPE_ENUM:
|
||||
if SupportsOpenEnums(field):
|
||||
# When open enums are supported, any int32 can be assigned.
|
||||
return _VALUE_CHECKERS[_FieldDescriptor.CPPTYPE_INT32]
|
||||
else:
|
||||
return EnumValueChecker(field.enum_type)
|
||||
return _VALUE_CHECKERS[field.cpp_type]
|
||||
|
||||
|
||||
# None of the typecheckers below make any attempt to guard against people
|
||||
# subclassing builtin types and doing weird things. We're not trying to
|
||||
# protect against malicious clients here, just people accidentally shooting
|
||||
# themselves in the foot in obvious ways.
|
||||
|
||||
class TypeChecker(object):
|
||||
|
||||
"""Type checker used to catch type errors as early as possible
|
||||
when the client is setting scalar fields in protocol messages.
|
||||
"""
|
||||
|
||||
def __init__(self, *acceptable_types):
|
||||
self._acceptable_types = acceptable_types
|
||||
|
||||
def CheckValue(self, proposed_value):
|
||||
"""Type check the provided value and return it.
|
||||
|
||||
The returned value might have been normalized to another type.
|
||||
"""
|
||||
if not isinstance(proposed_value, self._acceptable_types):
|
||||
message = ('%.1024r has type %s, but expected one of: %s' %
|
||||
(proposed_value, type(proposed_value), self._acceptable_types))
|
||||
raise TypeError(message)
|
||||
# Some field types(float, double and bool) accept other types, must
|
||||
# convert to the correct type in such cases.
|
||||
if self._acceptable_types:
|
||||
if self._acceptable_types[0] in (bool, float):
|
||||
return self._acceptable_types[0](proposed_value)
|
||||
return proposed_value
|
||||
|
||||
|
||||
class TypeCheckerWithDefault(TypeChecker):
|
||||
|
||||
def __init__(self, default_value, *acceptable_types):
|
||||
TypeChecker.__init__(self, *acceptable_types)
|
||||
self._default_value = default_value
|
||||
|
||||
def DefaultValue(self):
|
||||
return self._default_value
|
||||
|
||||
|
||||
# IntValueChecker and its subclasses perform integer type-checks
|
||||
# and bounds-checks.
|
||||
class IntValueChecker(object):
|
||||
|
||||
"""Checker used for integer fields. Performs type-check and range check."""
|
||||
|
||||
def CheckValue(self, proposed_value):
|
||||
if not isinstance(proposed_value, numbers.Integral):
|
||||
message = ('%.1024r has type %s, but expected one of: %s' %
|
||||
(proposed_value, type(proposed_value), (int,)))
|
||||
raise TypeError(message)
|
||||
if not self._MIN <= int(proposed_value) <= self._MAX:
|
||||
raise ValueError('Value out of range: %d' % proposed_value)
|
||||
# We force all values to int to make alternate implementations where the
|
||||
# distinction is more significant (e.g. the C++ implementation) simpler.
|
||||
proposed_value = int(proposed_value)
|
||||
return proposed_value
|
||||
|
||||
def DefaultValue(self):
|
||||
return 0
|
||||
|
||||
|
||||
class EnumValueChecker(object):
|
||||
|
||||
"""Checker used for enum fields. Performs type-check and range check."""
|
||||
|
||||
def __init__(self, enum_type):
|
||||
self._enum_type = enum_type
|
||||
|
||||
def CheckValue(self, proposed_value):
|
||||
if not isinstance(proposed_value, numbers.Integral):
|
||||
message = ('%.1024r has type %s, but expected one of: %s' %
|
||||
(proposed_value, type(proposed_value), (int,)))
|
||||
raise TypeError(message)
|
||||
if int(proposed_value) not in self._enum_type.values_by_number:
|
||||
raise ValueError('Unknown enum value: %d' % proposed_value)
|
||||
return proposed_value
|
||||
|
||||
def DefaultValue(self):
|
||||
return self._enum_type.values[0].number
|
||||
|
||||
|
||||
class UnicodeValueChecker(object):
|
||||
|
||||
"""Checker used for string fields.
|
||||
|
||||
Always returns a unicode value, even if the input is of type str.
|
||||
"""
|
||||
|
||||
def CheckValue(self, proposed_value):
|
||||
if not isinstance(proposed_value, (bytes, str)):
|
||||
message = ('%.1024r has type %s, but expected one of: %s' %
|
||||
(proposed_value, type(proposed_value), (bytes, str)))
|
||||
raise TypeError(message)
|
||||
|
||||
# If the value is of type 'bytes' make sure that it is valid UTF-8 data.
|
||||
if isinstance(proposed_value, bytes):
|
||||
try:
|
||||
proposed_value = proposed_value.decode('utf-8')
|
||||
except UnicodeDecodeError:
|
||||
raise ValueError('%.1024r has type bytes, but isn\'t valid UTF-8 '
|
||||
'encoding. Non-UTF-8 strings must be converted to '
|
||||
'unicode objects before being added.' %
|
||||
(proposed_value))
|
||||
else:
|
||||
try:
|
||||
proposed_value.encode('utf8')
|
||||
except UnicodeEncodeError:
|
||||
raise ValueError('%.1024r isn\'t a valid unicode string and '
|
||||
'can\'t be encoded in UTF-8.'%
|
||||
(proposed_value))
|
||||
|
||||
return proposed_value
|
||||
|
||||
def DefaultValue(self):
|
||||
return u""
|
||||
|
||||
|
||||
class Int32ValueChecker(IntValueChecker):
|
||||
# We're sure to use ints instead of longs here since comparison may be more
|
||||
# efficient.
|
||||
_MIN = -2147483648
|
||||
_MAX = 2147483647
|
||||
|
||||
|
||||
class Uint32ValueChecker(IntValueChecker):
|
||||
_MIN = 0
|
||||
_MAX = (1 << 32) - 1
|
||||
|
||||
|
||||
class Int64ValueChecker(IntValueChecker):
|
||||
_MIN = -(1 << 63)
|
||||
_MAX = (1 << 63) - 1
|
||||
|
||||
|
||||
class Uint64ValueChecker(IntValueChecker):
|
||||
_MIN = 0
|
||||
_MAX = (1 << 64) - 1
|
||||
|
||||
|
||||
# The max 4 bytes float is about 3.4028234663852886e+38
|
||||
_FLOAT_MAX = float.fromhex('0x1.fffffep+127')
|
||||
_FLOAT_MIN = -_FLOAT_MAX
|
||||
_INF = float('inf')
|
||||
_NEG_INF = float('-inf')
|
||||
|
||||
|
||||
class FloatValueChecker(object):
|
||||
|
||||
"""Checker used for float fields. Performs type-check and range check.
|
||||
|
||||
Values exceeding a 32-bit float will be converted to inf/-inf.
|
||||
"""
|
||||
|
||||
def CheckValue(self, proposed_value):
|
||||
"""Check and convert proposed_value to float."""
|
||||
if not isinstance(proposed_value, numbers.Real):
|
||||
message = ('%.1024r has type %s, but expected one of: numbers.Real' %
|
||||
(proposed_value, type(proposed_value)))
|
||||
raise TypeError(message)
|
||||
converted_value = float(proposed_value)
|
||||
# This inf rounding matches the C++ proto SafeDoubleToFloat logic.
|
||||
if converted_value > _FLOAT_MAX:
|
||||
return _INF
|
||||
if converted_value < _FLOAT_MIN:
|
||||
return _NEG_INF
|
||||
|
||||
return TruncateToFourByteFloat(converted_value)
|
||||
|
||||
def DefaultValue(self):
|
||||
return 0.0
|
||||
|
||||
|
||||
# Type-checkers for all scalar CPPTYPEs.
|
||||
_VALUE_CHECKERS = {
|
||||
_FieldDescriptor.CPPTYPE_INT32: Int32ValueChecker(),
|
||||
_FieldDescriptor.CPPTYPE_INT64: Int64ValueChecker(),
|
||||
_FieldDescriptor.CPPTYPE_UINT32: Uint32ValueChecker(),
|
||||
_FieldDescriptor.CPPTYPE_UINT64: Uint64ValueChecker(),
|
||||
_FieldDescriptor.CPPTYPE_DOUBLE: TypeCheckerWithDefault(
|
||||
0.0, float, numbers.Real),
|
||||
_FieldDescriptor.CPPTYPE_FLOAT: FloatValueChecker(),
|
||||
_FieldDescriptor.CPPTYPE_BOOL: TypeCheckerWithDefault(
|
||||
False, bool, numbers.Integral),
|
||||
_FieldDescriptor.CPPTYPE_STRING: TypeCheckerWithDefault(b'', bytes),
|
||||
}
|
||||
|
||||
|
||||
# Map from field type to a function F, such that F(field_num, value)
|
||||
# gives the total byte size for a value of the given type. This
|
||||
# byte size includes tag information and any other additional space
|
||||
# associated with serializing "value".
|
||||
TYPE_TO_BYTE_SIZE_FN = {
|
||||
_FieldDescriptor.TYPE_DOUBLE: wire_format.DoubleByteSize,
|
||||
_FieldDescriptor.TYPE_FLOAT: wire_format.FloatByteSize,
|
||||
_FieldDescriptor.TYPE_INT64: wire_format.Int64ByteSize,
|
||||
_FieldDescriptor.TYPE_UINT64: wire_format.UInt64ByteSize,
|
||||
_FieldDescriptor.TYPE_INT32: wire_format.Int32ByteSize,
|
||||
_FieldDescriptor.TYPE_FIXED64: wire_format.Fixed64ByteSize,
|
||||
_FieldDescriptor.TYPE_FIXED32: wire_format.Fixed32ByteSize,
|
||||
_FieldDescriptor.TYPE_BOOL: wire_format.BoolByteSize,
|
||||
_FieldDescriptor.TYPE_STRING: wire_format.StringByteSize,
|
||||
_FieldDescriptor.TYPE_GROUP: wire_format.GroupByteSize,
|
||||
_FieldDescriptor.TYPE_MESSAGE: wire_format.MessageByteSize,
|
||||
_FieldDescriptor.TYPE_BYTES: wire_format.BytesByteSize,
|
||||
_FieldDescriptor.TYPE_UINT32: wire_format.UInt32ByteSize,
|
||||
_FieldDescriptor.TYPE_ENUM: wire_format.EnumByteSize,
|
||||
_FieldDescriptor.TYPE_SFIXED32: wire_format.SFixed32ByteSize,
|
||||
_FieldDescriptor.TYPE_SFIXED64: wire_format.SFixed64ByteSize,
|
||||
_FieldDescriptor.TYPE_SINT32: wire_format.SInt32ByteSize,
|
||||
_FieldDescriptor.TYPE_SINT64: wire_format.SInt64ByteSize
|
||||
}
|
||||
|
||||
|
||||
# Maps from field types to encoder constructors.
|
||||
TYPE_TO_ENCODER = {
|
||||
_FieldDescriptor.TYPE_DOUBLE: encoder.DoubleEncoder,
|
||||
_FieldDescriptor.TYPE_FLOAT: encoder.FloatEncoder,
|
||||
_FieldDescriptor.TYPE_INT64: encoder.Int64Encoder,
|
||||
_FieldDescriptor.TYPE_UINT64: encoder.UInt64Encoder,
|
||||
_FieldDescriptor.TYPE_INT32: encoder.Int32Encoder,
|
||||
_FieldDescriptor.TYPE_FIXED64: encoder.Fixed64Encoder,
|
||||
_FieldDescriptor.TYPE_FIXED32: encoder.Fixed32Encoder,
|
||||
_FieldDescriptor.TYPE_BOOL: encoder.BoolEncoder,
|
||||
_FieldDescriptor.TYPE_STRING: encoder.StringEncoder,
|
||||
_FieldDescriptor.TYPE_GROUP: encoder.GroupEncoder,
|
||||
_FieldDescriptor.TYPE_MESSAGE: encoder.MessageEncoder,
|
||||
_FieldDescriptor.TYPE_BYTES: encoder.BytesEncoder,
|
||||
_FieldDescriptor.TYPE_UINT32: encoder.UInt32Encoder,
|
||||
_FieldDescriptor.TYPE_ENUM: encoder.EnumEncoder,
|
||||
_FieldDescriptor.TYPE_SFIXED32: encoder.SFixed32Encoder,
|
||||
_FieldDescriptor.TYPE_SFIXED64: encoder.SFixed64Encoder,
|
||||
_FieldDescriptor.TYPE_SINT32: encoder.SInt32Encoder,
|
||||
_FieldDescriptor.TYPE_SINT64: encoder.SInt64Encoder,
|
||||
}
|
||||
|
||||
|
||||
# Maps from field types to sizer constructors.
|
||||
TYPE_TO_SIZER = {
|
||||
_FieldDescriptor.TYPE_DOUBLE: encoder.DoubleSizer,
|
||||
_FieldDescriptor.TYPE_FLOAT: encoder.FloatSizer,
|
||||
_FieldDescriptor.TYPE_INT64: encoder.Int64Sizer,
|
||||
_FieldDescriptor.TYPE_UINT64: encoder.UInt64Sizer,
|
||||
_FieldDescriptor.TYPE_INT32: encoder.Int32Sizer,
|
||||
_FieldDescriptor.TYPE_FIXED64: encoder.Fixed64Sizer,
|
||||
_FieldDescriptor.TYPE_FIXED32: encoder.Fixed32Sizer,
|
||||
_FieldDescriptor.TYPE_BOOL: encoder.BoolSizer,
|
||||
_FieldDescriptor.TYPE_STRING: encoder.StringSizer,
|
||||
_FieldDescriptor.TYPE_GROUP: encoder.GroupSizer,
|
||||
_FieldDescriptor.TYPE_MESSAGE: encoder.MessageSizer,
|
||||
_FieldDescriptor.TYPE_BYTES: encoder.BytesSizer,
|
||||
_FieldDescriptor.TYPE_UINT32: encoder.UInt32Sizer,
|
||||
_FieldDescriptor.TYPE_ENUM: encoder.EnumSizer,
|
||||
_FieldDescriptor.TYPE_SFIXED32: encoder.SFixed32Sizer,
|
||||
_FieldDescriptor.TYPE_SFIXED64: encoder.SFixed64Sizer,
|
||||
_FieldDescriptor.TYPE_SINT32: encoder.SInt32Sizer,
|
||||
_FieldDescriptor.TYPE_SINT64: encoder.SInt64Sizer,
|
||||
}
|
||||
|
||||
|
||||
# Maps from field type to a decoder constructor.
|
||||
TYPE_TO_DECODER = {
|
||||
_FieldDescriptor.TYPE_DOUBLE: decoder.DoubleDecoder,
|
||||
_FieldDescriptor.TYPE_FLOAT: decoder.FloatDecoder,
|
||||
_FieldDescriptor.TYPE_INT64: decoder.Int64Decoder,
|
||||
_FieldDescriptor.TYPE_UINT64: decoder.UInt64Decoder,
|
||||
_FieldDescriptor.TYPE_INT32: decoder.Int32Decoder,
|
||||
_FieldDescriptor.TYPE_FIXED64: decoder.Fixed64Decoder,
|
||||
_FieldDescriptor.TYPE_FIXED32: decoder.Fixed32Decoder,
|
||||
_FieldDescriptor.TYPE_BOOL: decoder.BoolDecoder,
|
||||
_FieldDescriptor.TYPE_STRING: decoder.StringDecoder,
|
||||
_FieldDescriptor.TYPE_GROUP: decoder.GroupDecoder,
|
||||
_FieldDescriptor.TYPE_MESSAGE: decoder.MessageDecoder,
|
||||
_FieldDescriptor.TYPE_BYTES: decoder.BytesDecoder,
|
||||
_FieldDescriptor.TYPE_UINT32: decoder.UInt32Decoder,
|
||||
_FieldDescriptor.TYPE_ENUM: decoder.EnumDecoder,
|
||||
_FieldDescriptor.TYPE_SFIXED32: decoder.SFixed32Decoder,
|
||||
_FieldDescriptor.TYPE_SFIXED64: decoder.SFixed64Decoder,
|
||||
_FieldDescriptor.TYPE_SINT32: decoder.SInt32Decoder,
|
||||
_FieldDescriptor.TYPE_SINT64: decoder.SInt64Decoder,
|
||||
}
|
||||
|
||||
# Maps from field type to expected wiretype.
|
||||
FIELD_TYPE_TO_WIRE_TYPE = {
|
||||
_FieldDescriptor.TYPE_DOUBLE: wire_format.WIRETYPE_FIXED64,
|
||||
_FieldDescriptor.TYPE_FLOAT: wire_format.WIRETYPE_FIXED32,
|
||||
_FieldDescriptor.TYPE_INT64: wire_format.WIRETYPE_VARINT,
|
||||
_FieldDescriptor.TYPE_UINT64: wire_format.WIRETYPE_VARINT,
|
||||
_FieldDescriptor.TYPE_INT32: wire_format.WIRETYPE_VARINT,
|
||||
_FieldDescriptor.TYPE_FIXED64: wire_format.WIRETYPE_FIXED64,
|
||||
_FieldDescriptor.TYPE_FIXED32: wire_format.WIRETYPE_FIXED32,
|
||||
_FieldDescriptor.TYPE_BOOL: wire_format.WIRETYPE_VARINT,
|
||||
_FieldDescriptor.TYPE_STRING:
|
||||
wire_format.WIRETYPE_LENGTH_DELIMITED,
|
||||
_FieldDescriptor.TYPE_GROUP: wire_format.WIRETYPE_START_GROUP,
|
||||
_FieldDescriptor.TYPE_MESSAGE:
|
||||
wire_format.WIRETYPE_LENGTH_DELIMITED,
|
||||
_FieldDescriptor.TYPE_BYTES:
|
||||
wire_format.WIRETYPE_LENGTH_DELIMITED,
|
||||
_FieldDescriptor.TYPE_UINT32: wire_format.WIRETYPE_VARINT,
|
||||
_FieldDescriptor.TYPE_ENUM: wire_format.WIRETYPE_VARINT,
|
||||
_FieldDescriptor.TYPE_SFIXED32: wire_format.WIRETYPE_FIXED32,
|
||||
_FieldDescriptor.TYPE_SFIXED64: wire_format.WIRETYPE_FIXED64,
|
||||
_FieldDescriptor.TYPE_SINT32: wire_format.WIRETYPE_VARINT,
|
||||
_FieldDescriptor.TYPE_SINT64: wire_format.WIRETYPE_VARINT,
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user