.pydev*
*.iml
.idea
+*.bak
\ No newline at end of file
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-all</artifactId>
- <version>1.10.19</version>
<scope>test</scope>
</dependency>
</dependencies>
@SuppressWarnings("serial")
public class ConfigException extends Exception
{
- ConfigException(String what)
+ public ConfigException(String what)
{
super(what);
}
else
{
if (!x.hasMode("o"))
- return;
-
- // Non priv commands can be used by any oper
- if (confCommand.privilege == null)
{
- log.info("Denied access to " + confCommand.name + " to " + x + " [command has no privilege]");
- // Commands with no priv can not be executed in PM
- return;
+ if (!"anyone".equals(confCommand.privilege))
+ {
+ // Only accept commands that are explicitly accessible
+ // by anyone.
+ return;
+ }
}
-
- // Explicitly requires no privilege
- if (confCommand.privilege.equals("none"))
- ;
- else if (x.hasFlags(confCommand.privilege) == false)
+ else
{
- log.info("Denied access to " + confCommand.name + " to " + x + " [user has no priv]");
- return;
+ // Non priv commands can be used by any oper
+ if (confCommand.privilege == null)
+ {
+ log.info("Denied access to " + confCommand.name + " to " + x + " [command has no privilege]");
+ // Commands with no priv can not be executed in PM
+ return;
+ }
+
+ // Explicitly requires no privilege
+ if (confCommand.privilege.equals("none") || "anyone".equals(confCommand.privilege))
+ ;
+ else if (x.hasFlags(confCommand.privilege) == false)
+ {
+ log.info("Denied access to " + confCommand.name + " to " + x + " [user has no priv]");
+ return;
+ }
}
}
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
+import java.sql.Statement;
import java.util.LinkedList;
import net.rizon.acid.conf.Database;
import net.rizon.acid.core.Acidictive;
}
public PreparedStatement prepare(final String statement) throws SQLException
+ {
+ return this.prepare(statement, Statement.NO_GENERATED_KEYS);
+ }
+
+ public PreparedStatement prepare(final String statement, int autoGeneratedKeys) throws SQLException
{
this.close(this.statement, this.result);
}
}
- this.statement = this.con.prepareStatement(statement);
+ this.statement = this.con.prepareStatement(statement, autoGeneratedKeys);
return this.statement;
}
<module>pyva</module>
<module>trapbot</module>
<module>xmas</module>
+ <module>vizon</module>
</modules>
<dependencyManagement>
<version>4.12</version>
<scope>test</scope>
</dependency>
+ <dependency>
+ <groupId>org.mockito</groupId>
+ <artifactId>mockito-all</artifactId>
+ <version>1.10.19</version>
+ <scope>test</scope>
+ </dependency>
</dependencies>
</dependencyManagement>
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+
+ <parent>
+ <groupId>net.rizon</groupId>
+ <artifactId>acid</artifactId>
+ <version>4.1-SNAPSHOT</version>
+ </parent>
+
+ <name>VIzon</name>
+ <artifactId>acid-vizon</artifactId>
+
+ <dependencies>
+ <dependency>
+ <groupId>net.rizon</groupId>
+ <artifactId>acid-acid</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+
+ <dependency>
+ <groupId>junit</groupId>
+ <artifactId>junit</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.mockito</groupId>
+ <artifactId>mockito-all</artifactId>
+ <scope>test</scope>
+ </dependency>
+ </dependencies>
+
+ <build>
+ <plugins>
+ <plugin>
+ <artifactId>maven-jar-plugin</artifactId>
+ <configuration>
+ <archive>
+ <manifest>
+ <mainClass>net.rizon.acid.plugins.vizon.Vizon</mainClass>
+ </manifest>
+ <manifestEntries>
+ <Export-Base>net.rizon.acid.plugins.vizon.</Export-Base>
+ </manifestEntries>
+ </archive>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+</project>
--- /dev/null
+/*
+ * Copyright (c) 2016, orillion <orillion@rizon.net>
+ * All rights reserved.
+ *
+ * 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.
+ *
+ * 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 HOLDER 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.
+ */
+package net.rizon.acid.plugins.vizon;
+
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+/**
+ * Holds a user's bet.
+ *
+ * @author orillion <orillion@rizon.net>
+ */
+public class Bet
+{
+ private final int first;
+ private final int second;
+ private final int third;
+ private final int fourth;
+ private final int fifth;
+ private final int sixth;
+
+ /**
+ * Constructs an object that holds a user's bet.
+ *
+ * @param first First number the user bet
+ * @param second Second number the user bet
+ * @param third Third number the user bet
+ * @param fourth Fourth number the user bet
+ * @param fifth Fifth number the user bet
+ * @param sixth Sixth number the user bet
+ */
+ public Bet(int first, int second, int third, int fourth, int fifth, int sixth)
+ {
+ this.first = first;
+ this.second = second;
+ this.third = third;
+ this.fourth = fourth;
+ this.fifth = fifth;
+ this.sixth = sixth;
+ }
+
+ /**
+ * Gets the first number the user bet.
+ *
+ * @return First number
+ */
+ public int getFirst()
+ {
+ return first;
+ }
+
+ /**
+ * Gets the second number the user bet.
+ *
+ * @return Second number
+ */
+ public int getSecond()
+ {
+ return second;
+ }
+
+ /**
+ * Gets the third number the user bet.
+ *
+ * @return Third number
+ */
+ public int getThird()
+ {
+ return third;
+ }
+
+ /**
+ * Gets the fourth number the user bet.
+ *
+ * @return Fourth number
+ */
+ public int getFourth()
+ {
+ return fourth;
+ }
+
+ /**
+ * Gets the fifth number the user bet.
+ *
+ * @return Fifth number
+ */
+ public int getFifth()
+ {
+ return fifth;
+ }
+
+ /**
+ * Gets the sixth number the user bet.
+ *
+ * @return Sixth number
+ */
+ public int getSixth()
+ {
+ return sixth;
+ }
+
+ public List<Integer> asList()
+ {
+ return Arrays.asList(
+ first,
+ second,
+ third,
+ fourth,
+ fifth,
+ sixth);
+ }
+
+ public boolean hasSameNumbers(Bet other)
+ {
+ Set<Integer> ours = new HashSet<>(asList()),
+ theirs = new HashSet<>(other.asList());
+ return ours.equals(theirs);
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2016, orillion <orillion@rizon.net>
+ * All rights reserved.
+ *
+ * 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.
+ *
+ * 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 HOLDER 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.
+ */
+package net.rizon.acid.plugins.vizon;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Optional;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * Static class which validates a bet placed by a user.
+ *
+ * @author orillion <orillion@rizon.net>
+ */
+public class BetValidator
+{
+ private static final Pattern BET_PATTERN
+ = Pattern.compile("^\\s*(\\d+)\\s+(\\d+)\\s+(\\d+)\\s+(\\d+)\\s+(\\d+)\\s+(\\d+)\\s*$");
+
+ public static final int BET_MIN = 1;
+ public static final int BET_MAX = 29; // inclusive
+
+ /**
+ * Attempts to validate if a bet placed by a user is within [1,29]. Bets
+ * are done via <code>!bet first second third fourth fifth sixth</code>.
+ * This function expects to get the string without !bet part and then
+ * parses it into an {@link Optional}.
+ *
+ * @param bet Bet the user placed.
+ *
+ * @return {@link Optional} which contains the bet, or is empty if not
+ * parsable.
+ */
+ public static Optional<Bet> validate(String bet)
+ {
+ if (bet == null)
+ {
+ return Optional.empty();
+ }
+
+ Matcher matcher = BET_PATTERN.matcher(bet);
+
+ if (!matcher.find())
+ {
+ return Optional.empty();
+ }
+
+ List<Integer> numbers = new ArrayList<>();
+
+ for (int i = 1; i <= matcher.groupCount(); i++)
+ {
+ // Guaranteed to be integers due to regex.
+ int number = Integer.parseInt(matcher.group(i));
+
+ if (!validNumber(number))
+ {
+ // Number is not between 1 and 29 inclusive
+ return Optional.empty();
+ }
+
+ if (numbers.contains(number))
+ {
+ // Number already occured before
+ return Optional.empty();
+ }
+
+ numbers.add(number);
+ }
+
+ Bet betValue = new Bet(
+ numbers.get(0),
+ numbers.get(1),
+ numbers.get(2),
+ numbers.get(3),
+ numbers.get(4),
+ numbers.get(5));
+
+ return Optional.of(betValue);
+ }
+
+ private static boolean validNumber(int number)
+ {
+ return number >= BET_MIN && number <= BET_MAX;
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2017, orillion <orillion@rizon.net>
+ * All rights reserved.
+ *
+ * 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.
+ *
+ * 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 HOLDER 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.
+ */
+package net.rizon.acid.plugins.vizon;
+
+import java.security.SecureRandom;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.stream.IntStream;
+import static net.rizon.acid.plugins.vizon.BetValidator.BET_MAX;
+import static net.rizon.acid.plugins.vizon.BetValidator.BET_MIN;
+
+/**
+ *
+ * @author orillion <orillion@rizon.net>
+ */
+public class DrawGenerator
+{
+ private final List<Integer> numbers = new ArrayList<>(BET_MAX - BET_MIN + 1);
+ private final SecureRandom random = new SecureRandom();
+
+ public DrawGenerator()
+ {
+ IntStream
+ .rangeClosed(BET_MIN, BET_MAX)
+ .forEach(i -> numbers.add(i));
+ }
+
+ /**
+ * Generates a new drawing with random numbers.
+ *
+ * @return
+ */
+ public Bet generate()
+ {
+ Collections.shuffle(numbers, random);
+
+ Bet bet = new Bet(
+ numbers.get(0),
+ numbers.get(1),
+ numbers.get(2),
+ numbers.get(3),
+ numbers.get(4),
+ numbers.get(5));
+
+ return bet;
+ }
+
+ /**
+ * Takes a random bet and declares it the winner. If there are no bets,
+ * it will generate a random one.
+ *
+ * @param bets Bets that were placed
+ *
+ * @return A random bet.
+ */
+ public Bet generateSpecial(List<Bet> bets)
+ {
+ if (bets == null || bets.isEmpty())
+ {
+ return generate();
+ }
+
+ Collections.shuffle(bets, random);
+
+ return bets.get(0);
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2017, orillion <orillion@rizon.net>
+ * All rights reserved.
+ *
+ * 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.
+ *
+ * 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 HOLDER 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.
+ */
+package net.rizon.acid.plugins.vizon;
+
+/**
+ *
+ * @author orillion <orillion@rizon.net>
+ */
+public enum DrawingState
+{
+ OPEN,
+ CLOSED,
+ PREPARING
+}
--- /dev/null
+/*
+ * Copyright (c) 2017, orillion <orillion@rizon.net>
+ * All rights reserved.
+ *
+ * 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.
+ *
+ * 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 HOLDER 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.
+ */
+package net.rizon.acid.plugins.vizon;
+
+import net.rizon.acid.plugins.vizon.db.VizonDatabase;
+import net.rizon.acid.plugins.vizon.db.VizonUser;
+import net.rizon.acid.plugins.vizon.db.VizonDrawing;
+import java.time.LocalDateTime;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import static java.util.stream.Collectors.toList;
+import net.rizon.acid.core.AcidUser;
+import net.rizon.acid.core.Acidictive;
+import net.rizon.acid.core.Channel;
+import net.rizon.acid.core.User;
+import net.rizon.acid.util.Format;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ *
+ * @author orillion <orillion@rizon.net>
+ */
+public class LotteryThread extends Thread
+{
+ private static final Logger logger = LoggerFactory.getLogger(LotteryThread.class);
+
+ private AcidUser vizonUser;
+ private Channel channel;
+ private VizonDatabase database;
+ private VizonDrawing drawing;
+
+ private final List<VizonUser> jackpockWinners = new ArrayList<>();
+ private final List<VizonUser> grandPrizeWinners = new ArrayList<>();
+ private final List<VizonUser> firstPrizeWinners = new ArrayList<>();
+ private final List<VizonUser> secondPrizeWinners = new ArrayList<>();
+ private final List<VizonUser> thirdPrizeWinners = new ArrayList<>();
+ private final List<VizonUser> consolationPrizeWinners = new ArrayList<>();
+
+ public LotteryThread(VizonDrawing drawing)
+ {
+ super("LotteryThread");
+ this.drawing = drawing;
+ }
+
+ @Override
+ public void run()
+ {
+ database = Vizon.getVizonThreadDatabase();
+ channel = Vizon.getVizonChannel();
+ vizonUser = Vizon.getVizonBot();
+
+ boolean channelWasModerated = channel.hasMode('m');
+
+ List<VizonBet> bets = database.findBetsForDrawing(drawing);
+
+ DrawGenerator generator = Vizon.getGenerator();
+ Bet winning;
+
+ if (drawing.getId() % 100 == 0)
+ {
+ // Do special drawing
+ List<Bet> userBets = bets.stream()
+ .map((b) -> b.getBet())
+ .collect(toList());
+
+ winning = generator.generateSpecial(userBets);
+ }
+ else
+ {
+ // Do normal drawing
+ winning = generator.generate();
+ }
+
+ // Set the results of the drawing.
+ drawing.setDrawingResult(winning);
+
+ // Announce we're starting the drawing
+ privmsgChannel(String.format(
+ "Starting drawing No.%d of VIzon...",
+ drawing.getId()));
+
+ if (!channelWasModerated)
+ {
+ // No need to set +m, channel was already moderated
+ Acidictive.setMode(
+ vizonUser.getUID(),
+ channel.getName(),
+ "+m");
+ }
+
+ // Announce a new number every 5 seconds.
+ for (int i = 1; i <= 6; i++)
+ {
+ try
+ {
+ Thread.sleep(5000);
+
+ privmsgChannel(String.format(
+ "%s number is %2d",
+ ordinal(i),
+ winning.asList().get(i - 1)));
+ }
+ catch (InterruptedException ex)
+ {
+ logger.error("LotteryRunner thread was interrupted");
+ return;
+ }
+ }
+
+ try
+ {
+ Thread.sleep(5000);
+ }
+ catch (InterruptedException ex)
+ {
+ logger.error("LotteryRunner thread was interrupted");
+ return;
+ }
+
+ // Sort the winning numbers from low to high.
+ List<Integer> winningNumbers = winning.asList();
+ Collections.sort(winningNumbers);
+
+ // Announce results of the drawing, ordered.
+ privmsgChannel(String.format(
+ "The result of No.%d drawing of VIzon is %d %d %d %d %d %d",
+ drawing.getId(),
+ winningNumbers.get(0),
+ winningNumbers.get(1),
+ winningNumbers.get(2),
+ winningNumbers.get(3),
+ winningNumbers.get(4),
+ winningNumbers.get(5)));
+
+ // Determine winners
+ for (VizonBet bet : bets)
+ {
+ int correct = drawing.checkCorrect(bet.getBet());
+
+ switch (correct)
+ {
+ case 6:
+ // First prize
+ handleFirstPrize(bet);
+ break;
+ case 5:
+ // Second prinze
+ handleSecondPrize(bet);
+ break;
+ case 4:
+ // Third prize
+ handleThirdPrize(bet);
+ break;
+ case 3:
+ // consolation prize
+ handleConsolationPrize(bet);
+ break;
+ default:
+ // No prize
+ break;
+ }
+ }
+
+ // Announce we have grand prize winners, if there are any, else
+ // ignore it.
+ if (grandPrizeWinners.size() > 0)
+ {
+ privmsgChannel(String.format(
+ "%cGrand prize: %s%c",
+ Format.BOLD,
+ winnersString(grandPrizeWinners.size()),
+ Format.BOLD));
+ }
+
+ // Announce number of first prize winners.
+ privmsgChannel(String.format(
+ "%s prize: %s",
+ ordinal(1),
+ winnersString(firstPrizeWinners.size())));
+
+ // Announce number of second prize winners.
+ privmsgChannel(String.format(
+ "%s prize: %s",
+ ordinal(2),
+ winnersString(secondPrizeWinners.size())));
+
+ // Announce number of third prize winners.
+ privmsgChannel(String.format(
+ "%s prize: %s",
+ ordinal(3),
+ winnersString(thirdPrizeWinners.size())));
+
+ // Announce number of consolation prize winners.
+ privmsgChannel(String.format(
+ "Consolation prize: %s",
+ winnersString(consolationPrizeWinners.size())));
+
+ // Announce number of people that participated
+ privmsgChannel(String.format(
+ "No. of bets placed: %d",
+ bets.size()));
+
+ if (!channelWasModerated)
+ {
+ // Channel was not +m before the drawing began, so we need to reset
+ // it to -m
+ Acidictive.setMode(
+ vizonUser.getUID(),
+ channel.getName(),
+ "-m");
+ }
+
+ // Process and notify all winners
+ processWinners();
+
+ database.updateDrawing(drawing);
+
+ Vizon.updateChannel(database);
+ }
+
+ private void processWinners()
+ {
+ for (VizonUser user : jackpockWinners)
+ {
+ notifyJackpotWinner(user);
+ }
+
+ for (VizonUser user : grandPrizeWinners)
+ {
+ notifyGrandPrizeWinner(user);
+ }
+
+ for (VizonUser user : firstPrizeWinners)
+ {
+ notifyFirstPrizeWinner(user);
+ }
+
+ for (VizonUser user : secondPrizeWinners)
+ {
+ notifySecondPrizeWinner(user);
+ }
+
+ for (VizonUser user : thirdPrizeWinners)
+ {
+ notifyThirdPrizeWinner(user);
+ }
+
+ for (VizonUser user : consolationPrizeWinners)
+ {
+ notifyConsolationPrizeWinner(user);
+ }
+ }
+
+ private void notifyJackpotWinner(VizonUser user)
+ {
+ User u = User.findUser(user.getNick());
+
+ notifyUser(
+ u,
+ String.format("Congratulations, you won the jackpot in VIzon "
+ + "No.%d! You are eligible to select a new vhost and "
+ + "won a 1 letter nickname!", drawing.getId()),
+ user.getNick());
+ }
+
+ private void notifyGrandPrizeWinner(VizonUser user)
+ {
+ User u = User.findUser(user.getNick());
+
+ notifyUser(
+ u,
+ String.format("Congratulations, you won the grand prize in VIzon "
+ + "No.%d! You are eligible to select a new vhost! Your "
+ + "vhost will now be permanent!", drawing.getId()),
+ user.getNick());
+ }
+
+ private void notifyFirstPrizeWinner(VizonUser user)
+ {
+ User u = User.findUser(user.getNick());
+
+ notifyUser(
+ u,
+ String.format("Congratulations, you won the first prize in VIzon "
+ + "No.%d! You are eligible to select a new vhost! And your "
+ + "vhost will be made bold!", drawing.getId()),
+ user.getNick());
+ }
+
+ private void notifySecondPrizeWinner(VizonUser user)
+ {
+ User u = User.findUser(user.getNick());
+
+ notifyUser(
+ u,
+ String.format("Congratulations, you won the second prize in VIzon "
+ + "No.%d! You are eligible to select a new vhost!", drawing.getId()),
+ user.getNick());
+ }
+
+ private void notifyThirdPrizeWinner(VizonUser user)
+ {
+ User u = User.findUser(user.getNick());
+
+ notifyUser(
+ u,
+ String.format("Congratulations, you won the third prize in VIzon "
+ + "No.%d! You are eligible to select a new colored vhost!", drawing.getId()),
+ user.getNick());
+ }
+
+ private void notifyConsolationPrizeWinner(VizonUser user)
+ {
+ User u = User.findUser(user.getNick());
+
+ notifyUser(
+ u,
+ String.format("Congratulations, you won the consolation prize in VIzon "
+ + "No.%d! You are eligible to select a new colored vhost!", drawing.getId()),
+ user.getNick());
+ }
+
+ private void notifyUser(User user, String message, String nick)
+ {
+ Acidictive.privmsg(
+ Vizon.getVizonBot().getNick(),
+ "MemoServ",
+ String.format("SEND %s %s", nick, message));
+
+ if (user != null && user.isIdentified())
+ {
+ Acidictive.privmsg(
+ Vizon.getVizonBot().getNick(),
+ nick,
+ message);
+ }
+ }
+
+ private static String winnersString(int winners)
+ {
+ switch (winners)
+ {
+ case 0:
+ return "No winners";
+ case 1:
+ return "1 winner";
+ default:
+ return String.format("%d winners", winners);
+ }
+ }
+
+ private void handleFirstPrize(VizonBet bet)
+ {
+ VizonUser user = database.findUserById(bet.getUserId());
+
+ if (user == null)
+ {
+ return;
+ }
+
+ if (user.getObtained() == null)
+ {
+ user.setObtainedId(bet.getDrawingId());
+ user.setObtained(LocalDateTime.now());
+ }
+
+ // Allow user to request a new vhost
+ user.setEligible(true);
+ // Set the user's vhost to bold
+ user.setBold(true);
+
+ // @TODO: Determine if we are actually going to use this in the future.
+// if (user.isPermanent() && !user.isJackpot() && false)
+// {
+// // User has won grand prize before, and is eligible for the jackpot
+// jackpockWinners.add(user);
+// }
+// else
+ {
+ // Run normal checks
+ int multiplier = user.getMultiplier();
+
+ user.addDays(Vizon.getConf().firstPrize * multiplier);
+
+ if (user.getDays() >= 180 && !user.isPermanent())
+ {
+ // User won grand prize!
+ // Set +h on user
+ user.setPermanent(true);
+ grandPrizeWinners.add(user);
+ }
+ else
+ {
+ // Set +v on user.
+ firstPrizeWinners.add(user);
+ }
+ }
+
+ user.incrementMultiplier();
+ database.updateUser(user);
+ }
+
+ private void handleSecondPrize(VizonBet bet)
+ {
+ VizonUser user = database.findUserById(bet.getUserId());
+
+ if (user == null)
+ {
+ return;
+ }
+
+ if (user.getObtained() == null)
+ {
+ user.setObtainedId(bet.getDrawingId());
+ user.setObtained(LocalDateTime.now());
+ }
+
+ // Allow user to request a new vhost
+ user.setEligible(true);
+
+ int multiplier = user.getMultiplier();
+
+ user.addDays(Vizon.getConf().secondPrize * multiplier);
+
+ if (user.getDays() >= 180 && !user.isPermanent())
+ {
+ // User won grand prize!
+ // Set +h on user
+ user.setPermanent(true);
+ grandPrizeWinners.add(user);
+ }
+ else
+ {
+ // Set +v on user.
+ secondPrizeWinners.add(user);
+ }
+
+ user.incrementMultiplier();
+ database.updateUser(user);
+ }
+
+ private void handleThirdPrize(VizonBet bet)
+ {
+ VizonUser user = database.findUserById(bet.getUserId());
+
+ if (user == null)
+ {
+ return;
+ }
+
+ if (user.getObtained() == null)
+ {
+ user.setObtainedId(bet.getDrawingId());
+ user.setObtained(LocalDateTime.now());
+ }
+
+ // Allow user to request a new vhost
+ user.setEligible(true);
+
+ int multiplier = user.getMultiplier();
+
+ user.addDays(Vizon.getConf().thirdPrize * multiplier);
+
+ if (user.getDays() >= 180 && !user.isPermanent())
+ {
+ // User won grand prize!
+ // Set +h on user
+ user.setPermanent(true);
+ grandPrizeWinners.add(user);
+ }
+ else
+ {
+ // Set +v on user.
+ thirdPrizeWinners.add(user);
+ }
+
+ user.incrementMultiplier();
+ database.updateUser(user);
+ }
+
+ private void handleConsolationPrize(VizonBet bet)
+ {
+ VizonUser user = database.findUserById(bet.getUserId());
+
+ if (user == null)
+ {
+ return;
+ }
+
+ if (user.getObtained() == null)
+ {
+ user.setObtainedId(bet.getDrawingId());
+ user.setObtained(LocalDateTime.now());
+ }
+
+ // Allow user to request a new vhost
+ user.setEligible(true);
+
+ user.addDays(Vizon.getConf().consolationPrize);
+
+ if (user.getDays() >= 180 && !user.isPermanent())
+ {
+ // User won grand prize!
+ // Set +h on user
+ user.setPermanent(true);
+ grandPrizeWinners.add(user);
+ }
+ else
+ {
+ // Set +v on user.
+ consolationPrizeWinners.add(user);
+ }
+
+ database.updateUser(user);
+ }
+
+ private void privmsgChannel(String message)
+ {
+ Acidictive.privmsg(
+ vizonUser.getUID(),
+ channel.getName(),
+ message);
+ }
+
+ private static String ordinal(int i)
+ {
+ String[] sufixes = new String[]
+ {
+ "th", "st", "nd", "rd", "th", "th", "th", "th", "th", "th"
+ };
+ switch (i % 100)
+ {
+ case 11:
+ case 12:
+ case 13:
+ return i + "th";
+ default:
+ return i + sufixes[i % 10];
+
+ }
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2017, orillion <orillion@rizon.net>
+ * All rights reserved.
+ *
+ * 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.
+ *
+ * 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 HOLDER 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.
+ */
+package net.rizon.acid.plugins.vizon;
+
+/**
+ *
+ * @author orillion <orillion@rizon.net>
+ */
+public class RequestStatus
+{
+ public static final int PENDING = 0;
+ public static final int APPROVED = 1;
+ public static final int REJECTED = 2;
+}
--- /dev/null
+/*
+ * Copyright (c) 2017, orillion <orillion@rizon.net>
+ * All rights reserved.
+ *
+ * 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.
+ *
+ * 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 HOLDER 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.
+ */
+package net.rizon.acid.plugins.vizon;
+
+import net.rizon.acid.plugins.vizon.db.VizonRequest;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import java.util.Optional;
+import net.rizon.acid.conf.Config;
+import net.rizon.acid.core.Acidictive;
+import net.rizon.acid.core.Channel;
+
+/**
+ *
+ * @author orillion <orillion@rizon.net>
+ */
+public class RequestTracker
+{
+ public static final String MESSAGE_FORMAT = "[new] %d. %s :: %s\u000F :: Vizon vhost";
+ private static final String REJECT_FORMAT = "SEND %s Your colored vhost %s\u000F has been rejected";
+ private static final String APPROVE_FORMAT = "SEND %s Your colored vhost %s\u000F has been approved";
+ private final List<VizonRequest> requests = new ArrayList<>();
+ private final Config config;
+
+ public RequestTracker(Config conf)
+ {
+ this.config = conf;
+ }
+
+ public void addRequest(VizonRequest request)
+ {
+ Optional<VizonRequest> req = this.requests
+ .stream()
+ .filter(r -> r != null)
+ .filter(r -> r.getId() == request.getId())
+ .findFirst();
+
+ int index = 0;
+
+ if (req.isPresent())
+ {
+ index = this.requests.indexOf(req.get());
+ // Replace old request with new one
+ this.requests.set(index, request);
+ }
+ else
+ {
+ // Add new request to list.
+ this.requests.add(request);
+
+ index = this.requests.size() - 1;
+ }
+
+ String channel = this.config.getChannelNamed("vhost");
+ Channel c = Channel.findChannel(channel);
+
+ if (c == null)
+ return;
+
+ Acidictive.reply(
+ null,
+ Vizon.getVizonBot(),
+ c,
+ String.format(
+ MESSAGE_FORMAT,
+ index + 1,
+ request.getNick(),
+ request.getVhost()));
+ }
+
+ public boolean approveRequest(int request, String oper)
+ {
+ if (request < 0 || request >= this.requests.size())
+ {
+ return false;
+ }
+
+ VizonRequest req = this.requests.get(request);
+
+ if (req == null)
+ {
+ return false;
+ }
+
+ req.setOper(oper);
+ req.setStatus(RequestStatus.APPROVED);
+
+ if (!Vizon.getVhostManager().assignVhost(req))
+ {
+ return false;
+ }
+
+ if (!Vizon.getVizonDatabase().updateRequest(req))
+ {
+ return false;
+ }
+
+ Acidictive.privmsg(
+ Vizon.getVizonBot().getNick(),
+ "MemoServ",
+ String.format(
+ APPROVE_FORMAT,
+ req.getNick(),
+ req.getVhost()));
+
+ this.requests.set(request, null);
+ this.trimList();
+
+ return true;
+ }
+
+ public boolean rejectRequest(int request, String oper, String reason)
+ {
+ VizonRequest req = this.requests.get(request);
+
+ if (req == null)
+ {
+ return false;
+ }
+
+ req.setOper(oper);
+ req.setReason(reason);
+ req.setStatus(RequestStatus.REJECTED);
+
+ if (!Vizon.getVizonDatabase().updateRequest(req))
+ {
+ return false;
+ }
+
+ Acidictive.privmsg(
+ Vizon.getVizonBot().getNick(),
+ "MemoServ",
+ String.format(
+ REJECT_FORMAT,
+ req.getNick(),
+ req.getVhost()));
+
+ this.requests.set(request, null);
+ this.trimList();
+
+ return true;
+ }
+
+ private void trimList()
+ {
+ for (int index = this.requests.size() - 1; index >= 0; index--)
+ {
+ if (this.requests.get(index) != null)
+ {
+ // Clean up list until we find a non-null entry.
+ break;
+ }
+
+ this.requests.remove(index);
+ }
+ }
+
+ public void approveAllRequests(String oper)
+ {
+ for (int i = 0; i < this.requests.size(); i++)
+ {
+ this.approveRequest(i, oper);
+ }
+ }
+
+ public void rejectAllRequests(String oper)
+ {
+ for (int i = 0; i < this.requests.size(); i++)
+ {
+ this.rejectRequest(i, oper, null);
+ }
+ }
+
+ public void approveAllRequestsExcept(List<Integer> reqs, String oper)
+ {
+ for (int i = 0; i < this.requests.size(); i++)
+ {
+ if (reqs.contains(i))
+ {
+ this.approveRequest(i, oper);
+ }
+ else
+ {
+ this.rejectRequest(i, oper, null);
+ }
+ }
+ }
+
+ public List<VizonRequest> getPending()
+ {
+ Collection<VizonRequest> reqs = Vizon
+ .getVizonDatabase()
+ .findPendingVhostRequests();
+
+ if (reqs != null)
+ {
+ for (VizonRequest req : reqs)
+ {
+ Optional<VizonRequest> request = this.requests
+ .stream()
+ .filter(r -> r != null)
+ .filter(r -> r.getId() == req.getId())
+ .findFirst();
+
+ if (request.isPresent())
+ {
+ int index = this.requests.indexOf(request.get());
+ // Replace old request with new one
+ this.requests.set(index, req);
+ }
+ else
+ {
+ // Add new request to list.
+ this.requests.add(req);
+
+ }
+ }
+ }
+
+ return Collections.unmodifiableList(this.requests);
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2017, orillion <orillion@rizon.net>
+ * All rights reserved.
+ *
+ * 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.
+ *
+ * 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 HOLDER 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.
+ */
+package net.rizon.acid.plugins.vizon;
+
+import net.rizon.acid.plugins.vizon.db.VizonRequest;
+import net.rizon.acid.plugins.vizon.db.VizonUser;
+import java.util.regex.Pattern;
+import net.rizon.acid.core.Acidictive;
+import net.rizon.acid.core.Protocol;
+import net.rizon.acid.core.User;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ *
+ * @author orillion <orillion@rizon.net>
+ */
+public class VhostManager
+{
+ private static final Logger logger = LoggerFactory.getLogger(VhostManager.class);
+ private static final String DELETE_FORMAT = "DEL %s";
+
+ public static final Pattern NORMAL_PATTERN = Pattern.compile("^[\u0003\u000Fa-zA-Z0-9-.]*[a-zA-Z]+[\u0003\u000Fa-zA-Z0-9-.]*$");
+ public static final Pattern BOLD_PATTERN = Pattern.compile("^[\u0003\u0002\u000Fa-zA-Z0-9-.]*[a-zA-Z]+[\u0003\u0002\u000Fa-zA-Z0-9-.]*$");
+
+ public VhostManager()
+ {
+
+ }
+
+ public boolean assignVhost(VizonRequest request)
+ {
+ VizonUser user = Vizon.getVizonDatabase().findUserById(request.getUserId());
+
+ if (user == null)
+ {
+ return false;
+ }
+
+ Acidictive.privmsg("HostServ", String.format(DELETE_FORMAT, user.getNick()));
+
+ user.setVhost(request.getVhost());
+ user.setEligible(false);
+
+ if (!Vizon.getVizonDatabase().updateUser(user))
+ {
+ return false;
+ }
+
+ User u = User.findUser(request.getNick());
+
+ if (u != null)
+ {
+ this.applyVhostIfApplicable(u);
+ }
+
+ return true;
+ }
+
+ public void applyVhostIfApplicable(User user)
+ {
+ if (user == null || !user.isIdentified())
+ {
+ return;
+ }
+
+ VizonUser u = Vizon.getVizonDatabase().findUser(user.getNick());
+
+ if (u == null)
+ {
+ return;
+ }
+
+ Protocol.chghost(user, u.getVhost());
+ u.setVhost(u.getVhost());
+ }
+
+ public void expireVhosts()
+ {
+ int expired = Vizon.getVizonDatabase().expireVhosts();
+
+ // Users can keep their colored vhosts until they log out, when they expire.
+ logger.info("Expired {} vhosts", expired);
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2016, orillion <orillion@rizon.net>
+ * All rights reserved.
+ *
+ * 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.
+ *
+ * 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 HOLDER 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.
+ */
+package net.rizon.acid.plugins.vizon;
+
+import net.rizon.acid.plugins.vizon.db.VizonDatabase;
+import net.rizon.acid.plugins.vizon.db.VizonUser;
+import net.rizon.acid.plugins.vizon.db.VizonDrawing;
+import com.google.common.eventbus.Subscribe;
+import io.netty.util.concurrent.ScheduledFuture;
+import java.time.LocalDateTime;
+import java.util.concurrent.TimeUnit;
+import net.rizon.acid.conf.Config;
+import net.rizon.acid.conf.ConfigException;
+import net.rizon.acid.core.AcidUser;
+import net.rizon.acid.core.Acidictive;
+import net.rizon.acid.core.Channel;
+import net.rizon.acid.core.User;
+import net.rizon.acid.events.EventJoin;
+import net.rizon.acid.events.EventNickChange;
+import net.rizon.acid.events.EventSync;
+import net.rizon.acid.events.EventUserMode;
+import net.rizon.acid.plugins.Plugin;
+import net.rizon.acid.plugins.vizon.commands.PendingRequestCommand;
+import net.rizon.acid.plugins.vizon.conf.VizonConfig;
+import net.rizon.acid.plugins.vizon.util.VizonTemporal;
+import net.rizon.acid.sql.SQL;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ *
+ * @author orillion <orillion@rizon.net>
+ */
+public class Vizon extends Plugin
+{
+ private static final Logger logger = LoggerFactory.getLogger(Vizon.class);
+
+ private static VizonConfig conf;
+ private static AcidUser vizonBot;
+ private static Channel vizonChannel;
+
+ private static SQL vizonSql;
+ private static VizonDatabase vizonDatabase;
+
+ private static SQL vizonThreadSql;
+ private static VizonDatabase vizonThreadDatabase;
+
+ private static RequestTracker requestTracker;
+ private static VhostManager vhostManager;
+ private static DrawGenerator generator;
+
+ private ScheduledFuture checkDrawingFuture;
+ private ScheduledFuture vhostExpiryFuture;
+
+ private LotteryThread lotteryThread;
+
+ public static VizonConfig getConf()
+ {
+ return conf;
+ }
+
+ public static AcidUser getVizonBot()
+ {
+ return vizonBot;
+ }
+
+ public static Channel getVizonChannel()
+ {
+ return vizonChannel;
+ }
+
+ public static SQL getVizonSql()
+ {
+ return vizonSql;
+ }
+
+ public static VizonDatabase getVizonDatabase()
+ {
+ return vizonDatabase;
+ }
+
+ public static VizonDatabase getVizonThreadDatabase()
+ {
+ return vizonThreadDatabase;
+ }
+
+ public static RequestTracker getRequestTracker()
+ {
+ return requestTracker;
+ }
+
+ public static VhostManager getVhostManager()
+ {
+ return vhostManager;
+ }
+
+ public static DrawGenerator getGenerator()
+ {
+ return generator;
+ }
+
+ public static void updateChannel(VizonDatabase database)
+ {
+ for (String nick : vizonChannel.getUsers())
+ {
+ VizonUser user = database.findUser(nick);
+
+ if (user == null)
+ {
+ continue;
+ }
+
+ if (user.isPermanent())
+ {
+ // Grand prize winner
+ Acidictive.setMode(
+ vizonBot.getNick(),
+ vizonChannel.getName(),
+ String.format("+h %s", user.getNick()));
+ }
+ else if (user.getObtained() != null)
+ {
+ // User won a vhost
+ Acidictive.setMode(
+ vizonBot.getNick(),
+ vizonChannel.getName(),
+ String.format("+v %s", user.getNick()));
+ }
+ }
+ }
+
+ private void checkDrawing()
+ {
+ LocalDateTime now = LocalDateTime.now();
+ LocalDateTime drawingDate = VizonTemporal.determineNextDrawing(now, conf);
+
+ VizonDrawing drawing = vizonDatabase.findEarliestUnrunDrawing();
+
+ if (drawing == null)
+ {
+ drawing = vizonDatabase.createDrawing(drawingDate);
+
+ if (drawing == null)
+ {
+ logger.error("Error creating new drawing");
+ return;
+ }
+ }
+
+ logger.debug("Next drawing will be at {}, now is {}", drawing.getDate(), now);
+
+ if (drawing.getDate().isAfter(now))
+ {
+ return;
+ }
+
+ if (lotteryThread != null && lotteryThread.isAlive())
+ {
+ logger.warn("Unable to start new drawing thread, old one is still alive");
+ return;
+ }
+
+ lotteryThread = new LotteryThread(drawing);
+ lotteryThread.start();
+ }
+
+ @Override
+ public void start() throws Exception
+ {
+ reload();
+
+ vizonSql = SQL.getConnection("vizon");
+ vizonThreadSql = SQL.getConnection("vizon");
+ vizonDatabase = new VizonDatabase(vizonSql);
+ vizonThreadDatabase = new VizonDatabase(vizonThreadSql);
+ requestTracker = new RequestTracker(Acidictive.conf);
+ vhostManager = new VhostManager();
+ generator = new DrawGenerator();
+
+ checkDrawingFuture = Acidictive.scheduleAtFixedRate(this::checkDrawing, 1, TimeUnit.MINUTES);
+ vhostExpiryFuture = Acidictive.scheduleAtFixedRate(vhostManager::expireVhosts, 1, TimeUnit.DAYS);
+
+ Acidictive.eventBus.register(this);
+
+ // Load all pending requests from the DB.
+ requestTracker.getPending();
+ }
+
+ @Subscribe
+ public void onNickChange(EventNickChange event)
+ {
+ User user = event.getU();
+
+ if (!user.isIdentified())
+ {
+ return;
+ }
+
+ vhostManager.applyVhostIfApplicable(user);
+ setChannelModeIfApplicable(user);
+ }
+
+ @Subscribe
+ public void onModeChange(EventUserMode event)
+ {
+ User user = event.getUser();
+
+ if (!event.getNewmodes().contains("r"))
+ {
+ return;
+ }
+
+ vhostManager.applyVhostIfApplicable(user);
+ setChannelModeIfApplicable(user);
+ }
+
+ @Subscribe
+ public void onChannelJoin(EventJoin event)
+ {
+ Channel channel = event.getChannel();
+
+ if (!vizonChannel.equals(channel))
+ {
+ return;
+ }
+
+ for (User user : event.getUsers())
+ {
+ setChannelModeIfApplicable(user);
+ }
+ }
+
+ private void setChannelModeIfApplicable(User user)
+ {
+ if (!user.isIdentified())
+ {
+ return;
+ }
+
+ VizonUser vu = Vizon.getVizonDatabase().findUser(user.getNick());
+
+ if (vu == null || vu.getObtained() == null)
+ {
+ return;
+ }
+
+ String mode = vu.isPermanent() ? "+h" : "+v";
+
+ Acidictive.setMode(
+ vizonBot.getNick(),
+ vizonChannel.getName(),
+ String.format(
+ "%s %s",
+ mode,
+ user.getNick()));
+ }
+
+ @Subscribe
+ public void onSync(EventSync event)
+ {
+ // Run pending command on start.
+ PendingRequestCommand c = new PendingRequestCommand();
+ String channel = Acidictive.conf.getChannelNamed("vhost");
+ Channel chan = Channel.findChannel(channel);
+
+ if (chan == null)
+ return;
+
+ c.Run(vizonBot, vizonBot, chan, new String[0]);
+
+ Vizon.updateChannel(vizonDatabase);
+ }
+
+ @Override
+ public void stop()
+ {
+ if (checkDrawingFuture != null)
+ {
+ checkDrawingFuture.cancel(true);
+ checkDrawingFuture = null;
+ }
+
+ if (vhostExpiryFuture != null)
+ {
+ vhostExpiryFuture.cancel(true);
+ vhostExpiryFuture = null;
+ }
+
+ vizonSql.shutdown();
+ vizonThreadSql.shutdown();
+
+ Acidictive.eventBus.unregister(this);
+ }
+
+ @Override
+ public void reload() throws Exception
+ {
+ conf = (VizonConfig) Config.load("vizon.yml", VizonConfig.class);
+ Acidictive.loadClients(this, conf.clients);
+
+ User u = User.findUser(conf.vizonBot);
+
+ if (u == null || !(u instanceof AcidUser))
+ {
+ throw new ConfigException("VizonBot not loaded, or its nickname is in use by someone else");
+ }
+
+ Channel channel = Channel.findChannel(conf.vizonChannel);
+
+ if (channel == null)
+ {
+ throw new ConfigException("VizonChannel does not exist");
+ }
+
+ vizonBot = (AcidUser) u;
+
+ if (!vizonBot.isOnChan(channel))
+ {
+ throw new ConfigException("VizonBot not in Vizon channel");
+ }
+
+ vizonChannel = channel;
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2017, orillion <orillion@rizon.net>
+ * All rights reserved.
+ *
+ * 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.
+ *
+ * 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 HOLDER 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.
+ */
+package net.rizon.acid.plugins.vizon;
+
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.sql.Timestamp;
+import java.time.LocalDateTime;
+
+/**
+ *
+ * @author orillion <orillion@rizon.net>
+ */
+public class VizonBet
+{
+ private final int id;
+ private final int userId;
+ private final int drawingId;
+ private final Bet bet;
+ private final LocalDateTime placed;
+
+ public static VizonBet fromResultSet(ResultSet rs)
+ {
+ try
+ {
+ int id = rs.getInt("id");
+ int userId = rs.getInt("vizon_users_id");
+ int drawingId = rs.getInt("vizon_drawings_id");
+
+ int first = rs.getInt("first");
+ int second = rs.getInt("second");
+ int third = rs.getInt("third");
+ int fourth = rs.getInt("fourth");
+ int fifth = rs.getInt("fifth");
+ int sixth = rs.getInt("sixth");
+
+ Bet bet = new Bet(first, second, third, fourth, fifth, sixth);
+
+ Timestamp ts = rs.getTimestamp("placed");
+
+ return new VizonBet(id, userId, drawingId, bet, ts.toLocalDateTime());
+ }
+ catch (SQLException ex)
+ {
+ return null;
+ }
+ }
+
+ private VizonBet(int id, int userId, int drawingId, Bet bet, LocalDateTime placed)
+ {
+ this.id = id;
+ this.userId = userId;
+ this.drawingId = drawingId;
+ this.bet = bet;
+ this.placed = placed;
+ }
+
+ public int getId()
+ {
+ return id;
+ }
+
+ public int getUserId()
+ {
+ return userId;
+ }
+
+ public int getDrawingId()
+ {
+ return drawingId;
+ }
+
+ public Bet getBet()
+ {
+ return bet;
+ }
+
+ public LocalDateTime getPlaced()
+ {
+ return placed;
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2017, orillion <orillion@rizon.net>
+ * All rights reserved.
+ *
+ * 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.
+ *
+ * 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 HOLDER 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.
+ */
+package net.rizon.acid.plugins.vizon.commands;
+
+import net.rizon.acid.core.AcidUser;
+import net.rizon.acid.core.Acidictive;
+import net.rizon.acid.core.Channel;
+import net.rizon.acid.core.Command;
+import net.rizon.acid.core.User;
+import net.rizon.acid.plugins.vizon.Vizon;
+
+/**
+ *
+ * @author orillion <orillion@rizon.net>
+ */
+public class ApproveRequestCommand extends Command
+{
+ public ApproveRequestCommand()
+ {
+ super(1, 1);
+ }
+
+ @Override
+ public void Run(User source, AcidUser to, Channel c, String[] args)
+ {
+ try
+ {
+ int index = Integer.parseInt(args[0]);
+
+ if (Vizon.getRequestTracker().approveRequest(index - 1, source.getNick()))
+ {
+ Acidictive.reply(source, to, c, "Vhost approved");
+ }
+ else
+ {
+ Acidictive.reply(source, to, c, "Unable to approve vhost for id: " + index);
+ }
+ }
+ catch (NumberFormatException ex)
+ {
+ Acidictive.reply(source, to, c, "Argument is not a number");
+ }
+ }
+
+}
--- /dev/null
+/*
+ * Copyright (c) 2016, orillion <orillion@rizon.net>
+ * All rights reserved.
+ *
+ * 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.
+ *
+ * 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 HOLDER 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.
+ */
+package net.rizon.acid.plugins.vizon.commands;
+
+import java.util.Optional;
+import net.rizon.acid.core.AcidUser;
+import net.rizon.acid.core.Acidictive;
+import net.rizon.acid.core.Channel;
+import net.rizon.acid.core.Command;
+import net.rizon.acid.core.User;
+import net.rizon.acid.plugins.vizon.Bet;
+import net.rizon.acid.plugins.vizon.BetValidator;
+import net.rizon.acid.plugins.vizon.Vizon;
+import net.rizon.acid.plugins.vizon.VizonBet;
+import net.rizon.acid.plugins.vizon.db.VizonDrawing;
+import net.rizon.acid.plugins.vizon.db.VizonUser;
+
+/**
+ * This class handles the user's Bet command.
+ *
+ * @author orillion <orillion@rizon.net>
+ */
+public class BetCommand extends Command
+{
+ public BetCommand()
+ {
+ super(1, 1);
+ }
+
+ @Override
+ public void Run(User source, AcidUser to, Channel c, String[] args)
+ {
+ // @TODO: Perhaps we should move all replies to a config setting?
+ if (!source.isIdentified())
+ {
+ // User has not identified to NickServ.
+ Acidictive.reply(source, to, c, "You need to identify before you can participate");
+ return;
+ }
+
+ if (!source.isOnChan(Vizon.getVizonChannel()))
+ {
+ // User is not on the VIzon channel.
+ Acidictive.reply(source, to, c, String.format("You need to be on %s before placing a bet", Vizon.getConf().vizonChannel));
+ return;
+ }
+
+ VizonDrawing drawing = Vizon.getVizonDatabase().getNextDrawing();
+
+ if (drawing == null)
+ {
+ // @TODO: Tell user when bet will open.
+ Acidictive.reply(source, to, c,
+ "Betting is not open yet");
+ return;
+ }
+
+ switch (drawing.getState())
+ {
+ case PREPARING:
+ Acidictive.reply(source, to, c,
+ "Betting is not open yet");
+ return;
+ case CLOSED:
+ Acidictive.reply(source, to, c,
+ "Betting is closed, drawing will begin shortly");
+ return;
+ case OPEN:
+ default:
+ break;
+ }
+
+ // Find or create the user.
+ VizonUser user = Vizon.getVizonDatabase().findOrCreateUser(source.getNick());
+
+ if (user == null)
+ {
+ Acidictive.reply(source, to, c,
+ "Unable to find or create a user object");
+ return;
+ }
+
+ VizonBet vizonBet = Vizon.getVizonDatabase().findBetForUserAndDrawing(user, drawing);
+
+ if (vizonBet != null)
+ {
+ Acidictive.reply(source, to, c,
+ String.format("You have already placed a bet, your bet is %d %d %d %d %d %d",
+ vizonBet.getBet().getFirst(),
+ vizonBet.getBet().getSecond(),
+ vizonBet.getBet().getThird(),
+ vizonBet.getBet().getFourth(),
+ vizonBet.getBet().getFifth(),
+ vizonBet.getBet().getSixth()));
+ return;
+ }
+
+ Optional<Bet> betOpt = BetValidator.validate(args[0]);
+
+ if (!betOpt.isPresent())
+ {
+ // User made an invalid bet.
+ // @TODO: Move reply to config setting.
+ Acidictive.reply(source, to, c,
+ "Invalid bet. Please make sure you pick 6 non-repeating numbers between 1 and 29. Read http://s.rizon.net/VIzon for details.");
+ return;
+ }
+
+ Bet bet = betOpt.get();
+
+ boolean success = Vizon.getVizonDatabase().createBetForUser(user, drawing, bet);
+
+ if (success)
+ {
+ // Notify user bet was stored.
+ Acidictive.reply(
+ source,
+ to,
+ c,
+ String.format("Bet placed: %d %d %d %d %d %d",
+ bet.getFirst(),
+ bet.getSecond(),
+ bet.getThird(),
+ bet.getFourth(),
+ bet.getFifth(),
+ bet.getSixth()));
+ }
+ else
+ {
+ // Notify user that we failed to save the bet in the database.
+ Acidictive.reply(source, to, c,
+ "Failed to store bet, if this problem persists, please contact a staff member");
+ }
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2017, orillion <orillion@rizon.net>
+ * All rights reserved.
+ *
+ * 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.
+ *
+ * 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 HOLDER 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.
+ */
+package net.rizon.acid.plugins.vizon.commands;
+
+import java.time.LocalDateTime;
+import java.util.Collections;
+import java.util.List;
+import net.rizon.acid.core.AcidUser;
+import net.rizon.acid.core.Acidictive;
+import net.rizon.acid.core.Channel;
+import net.rizon.acid.core.Command;
+import net.rizon.acid.core.User;
+import net.rizon.acid.plugins.vizon.Vizon;
+import net.rizon.acid.plugins.vizon.VizonBet;
+import net.rizon.acid.plugins.vizon.db.VizonDrawing;
+import net.rizon.acid.plugins.vizon.db.VizonUser;
+
+/**
+ *
+ * @author orillion <orillion@rizon.net>
+ */
+public class CheckCommand extends Command
+{
+ public CheckCommand()
+ {
+ super(1, 1);
+ }
+
+ @Override
+ public void Run(User source, AcidUser to, Channel c, String[] args)
+ {
+ if (!source.hasMode("r"))
+ {
+ // User has not identified to NickServ.
+ Acidictive.reply(source, to, c, "You need to register your nickname before you can use this command");
+ return;
+ }
+
+ int drawingId;
+
+ try
+ {
+ drawingId = Integer.parseInt(args[0]);
+ }
+ catch (NumberFormatException e)
+ {
+ Acidictive.reply(source, to, c, "Please specify the number of the drawing you wish to check");
+ return;
+ }
+
+ VizonDrawing drawing = Vizon.getVizonDatabase().getDrawingById(drawingId);
+
+ if (drawing == null)
+ {
+ Acidictive.reply(source, to, c, String.format("Drawing with id %d does not exist", drawingId));
+ return;
+ }
+
+ VizonUser user = Vizon.getVizonDatabase().findOrCreateUser(source.getNick());
+
+ if (user == null)
+ {
+ // Should not happen, but just in case.
+ Acidictive.reply(source, to, c, "Unable to find your name in the database");
+ return;
+ }
+
+ VizonBet bet = Vizon.getVizonDatabase().findBetForUserAndDrawing(user, drawing);
+
+ if (drawing.getDate().isAfter(LocalDateTime.now()))
+ {
+ if (bet == null)
+ {
+ Acidictive.reply(source, to, c, String.format(
+ "Drawing No.%d did not happen yet!",
+ drawingId));
+ }
+ else
+ {
+ Acidictive.reply(source, to, c, String.format(
+ "Drawing No.%d did not happen yet! Your bet is: %d %d %d %d %d %d",
+ drawingId,
+ bet.getBet().getFirst(),
+ bet.getBet().getSecond(),
+ bet.getBet().getThird(),
+ bet.getBet().getFourth(),
+ bet.getBet().getFifth(),
+ bet.getBet().getSixth()));
+ }
+
+ return;
+ }
+
+ List<Integer> bets = drawing.getDraws();
+ Collections.sort(bets);
+
+ if (bet == null)
+ {
+ Acidictive.reply(source, to, c, String.format(
+ "The result of VIzon No.%d was: %d %d %d %d %d %d, you did not place a bet for this drawing",
+ drawing.getId(),
+ bets.get(0),
+ bets.get(1),
+ bets.get(2),
+ bets.get(3),
+ bets.get(4),
+ bets.get(5)));
+ }
+ else
+ {
+ // @TODO: Figure out how to recover Grand Prize info, perhaps
+ // store in the database or something.
+ int correct = drawing.checkCorrect(bet.getBet());
+
+ switch (correct)
+ {
+ case 6:
+ Acidictive.reply(source, to, c, String.format(
+ "The result of VIzon No.%d was: %d %d %d %d %d %d, you won first prize for this drawing! Your bet was: %d %d %d %d %d %d",
+ drawing.getId(),
+ bets.get(0),
+ bets.get(1),
+ bets.get(2),
+ bets.get(3),
+ bets.get(4),
+ bets.get(5),
+ bet.getBet().getFirst(),
+ bet.getBet().getSecond(),
+ bet.getBet().getThird(),
+ bet.getBet().getFourth(),
+ bet.getBet().getFifth(),
+ bet.getBet().getSixth()));
+ break;
+ case 5:
+ Acidictive.reply(source, to, c, String.format(
+ "The result of VIzon No.%d was: %d %d %d %d %d %d, you won second prize for this drawing! Your bet was: %d %d %d %d %d %d",
+ drawing.getId(),
+ bets.get(0),
+ bets.get(1),
+ bets.get(2),
+ bets.get(3),
+ bets.get(4),
+ bets.get(5),
+ bet.getBet().getFirst(),
+ bet.getBet().getSecond(),
+ bet.getBet().getThird(),
+ bet.getBet().getFourth(),
+ bet.getBet().getFifth(),
+ bet.getBet().getSixth()));
+ break;
+ case 4:
+ Acidictive.reply(source, to, c, String.format(
+ "The result of VIzon No.%d was: %d %d %d %d %d %d, you won third prize for this drawing! Your bet was: %d %d %d %d %d %d",
+ drawing.getId(),
+ bets.get(0),
+ bets.get(1),
+ bets.get(2),
+ bets.get(3),
+ bets.get(4),
+ bets.get(5),
+ bet.getBet().getFirst(),
+ bet.getBet().getSecond(),
+ bet.getBet().getThird(),
+ bet.getBet().getFourth(),
+ bet.getBet().getFifth(),
+ bet.getBet().getSixth()));
+ break;
+ case 3:
+ Acidictive.reply(source, to, c, String.format(
+ "The result of VIzon No.%d was: %d %d %d %d %d %d, you won the consolation prize for this drawing! Your bet was: %d %d %d %d %d %d",
+ drawing.getId(),
+ bets.get(0),
+ bets.get(1),
+ bets.get(2),
+ bets.get(3),
+ bets.get(4),
+ bets.get(5),
+ bet.getBet().getFirst(),
+ bet.getBet().getSecond(),
+ bet.getBet().getThird(),
+ bet.getBet().getFourth(),
+ bet.getBet().getFifth(),
+ bet.getBet().getSixth()));
+ break;
+ default:
+ Acidictive.reply(source, to, c, String.format(
+ "The result of VIzon No.%d was: %d %d %d %d %d %d, you did not win any prize for this drawing. Your bet was: %d %d %d %d %d %d",
+ drawing.getId(),
+ bets.get(0),
+ bets.get(1),
+ bets.get(2),
+ bets.get(3),
+ bets.get(4),
+ bets.get(5),
+ bet.getBet().getFirst(),
+ bet.getBet().getSecond(),
+ bet.getBet().getThird(),
+ bet.getBet().getFourth(),
+ bet.getBet().getFifth(),
+ bet.getBet().getSixth()));
+ break;
+ }
+ }
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2017, orillion <orillion@rizon.net>
+ * All rights reserved.
+ *
+ * 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.
+ *
+ * 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 HOLDER 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.
+ */
+package net.rizon.acid.plugins.vizon.commands;
+
+import net.rizon.acid.core.AcidUser;
+import net.rizon.acid.core.Acidictive;
+import net.rizon.acid.core.Channel;
+import net.rizon.acid.core.Command;
+import net.rizon.acid.core.Protocol;
+import net.rizon.acid.core.User;
+import net.rizon.acid.plugins.vizon.Vizon;
+import net.rizon.acid.plugins.vizon.db.VizonUser;
+
+/**
+ *
+ * @author orillion <orillion@rizon.net>
+ */
+public class DeleteCommand extends Command
+{
+ public DeleteCommand()
+ {
+ super(1, 1);
+ }
+
+ @Override
+ public void Run(User source, AcidUser to, Channel c, String[] args)
+ {
+ String nick = args[0];
+
+ VizonUser user = Vizon.getVizonDatabase().findUser(nick);
+
+ if (user == null)
+ {
+ Acidictive.reply(source, to, c, "Nickname not found in database");
+ return;
+ }
+
+ user.setEligible(false);
+ user.setVhost(null);
+ user.setBold(false);
+ user.setPermanent(false);
+ user.setJackpot(false);
+
+ if (Vizon.getVizonDatabase().updateUser(user))
+ {
+ Acidictive.reply(source, to, c, String.format("Removed colored vhost for user %s", nick));
+ }
+ else
+ {
+ Acidictive.reply(source, to, c, "Unable to update user, contact dev team");
+ }
+
+ User ircuser = User.findUser(nick);
+
+ if (ircuser == null)
+ {
+ return;
+ }
+
+ Protocol.chghost(ircuser, ircuser.getCloakedHost());
+ ircuser.setVhost(ircuser.getCloakedHost());
+ }
+
+}
--- /dev/null
+/*
+ * Copyright (c) 2017, orillion <orillion@rizon.net>
+ * All rights reserved.
+ *
+ * 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.
+ *
+ * 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 HOLDER 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.
+ */
+package net.rizon.acid.plugins.vizon.commands;
+
+import java.util.List;
+import net.rizon.acid.core.AcidUser;
+import net.rizon.acid.core.Acidictive;
+import net.rizon.acid.core.Channel;
+import net.rizon.acid.core.Command;
+import net.rizon.acid.core.User;
+import net.rizon.acid.plugins.vizon.RequestTracker;
+import net.rizon.acid.plugins.vizon.Vizon;
+import net.rizon.acid.plugins.vizon.db.VizonRequest;
+
+/**
+ *
+ * @author orillion <orillion@rizon.net>
+ */
+public class PendingRequestCommand extends Command
+{
+ public PendingRequestCommand()
+ {
+ super(0, 0);
+ }
+
+ @Override
+ public void Run(User source, AcidUser to, Channel c, String[] args)
+ {
+ List<VizonRequest> requests = Vizon.getRequestTracker().getPending();
+
+ if (requests.isEmpty())
+ {
+ Acidictive.reply(source, to, c, "No pending colored vhosts");
+ return;
+ }
+
+ for (int index = 0; index < requests.size(); index++)
+ {
+ VizonRequest request = requests.get(index);
+
+ if (request == null)
+ {
+ continue;
+ }
+
+ Acidictive.reply(source, to, c, String.format(
+ RequestTracker.MESSAGE_FORMAT,
+ index + 1,
+ request.getNick(),
+ request.getVhost()));
+ }
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2017, orillion <orillion@rizon.net>
+ * All rights reserved.
+ *
+ * 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.
+ *
+ * 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 HOLDER 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.
+ */
+package net.rizon.acid.plugins.vizon.commands;
+
+import net.rizon.acid.core.AcidUser;
+import net.rizon.acid.core.Acidictive;
+import net.rizon.acid.core.Channel;
+import net.rizon.acid.core.Command;
+import net.rizon.acid.core.User;
+import net.rizon.acid.plugins.vizon.Vizon;
+
+/**
+ *
+ * @author orillion <orillion@rizon.net>
+ */
+public class RejectRequestCommand extends Command
+{
+ public RejectRequestCommand()
+ {
+ super(1, 2);
+ }
+
+ @Override
+ public void Run(User source, AcidUser to, Channel c, String[] args)
+ {
+ String reason = null;
+
+ if (args.length > 1)
+ {
+ reason = args[1];
+ }
+
+ try
+ {
+ int index = Integer.parseInt(args[0]);
+
+ if (Vizon.getRequestTracker().rejectRequest(index - 1, source.getNick(), reason))
+ {
+ Acidictive.reply(source, to, c, "Vhost rejected");
+ }
+ else
+ {
+ Acidictive.reply(source, to, c, "Unable to reject vhost for id: " + index);
+ }
+ }
+ catch (NumberFormatException ex)
+ {
+ Acidictive.reply(source, to, c, "Argument is not a number");
+ }
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2017, orillion <orillion@rizon.net>
+ * All rights reserved.
+ *
+ * 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.
+ *
+ * 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 HOLDER 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.
+ */
+package net.rizon.acid.plugins.vizon.commands;
+
+import java.time.LocalDateTime;
+import java.util.regex.Matcher;
+import net.rizon.acid.core.AcidUser;
+import net.rizon.acid.core.Acidictive;
+import net.rizon.acid.core.Channel;
+import net.rizon.acid.core.Command;
+import net.rizon.acid.core.User;
+import net.rizon.acid.plugins.vizon.RequestStatus;
+import net.rizon.acid.plugins.vizon.VhostManager;
+import net.rizon.acid.plugins.vizon.Vizon;
+import net.rizon.acid.plugins.vizon.db.VizonRequest;
+import net.rizon.acid.plugins.vizon.db.VizonUser;
+
+/**
+ *
+ * @author orillion <orillion@rizon.net>
+ */
+public class RequestCommand extends Command
+{
+ private static final int MAX_HOST_BYTES = 63;
+
+ public RequestCommand()
+ {
+ super(1, 1);
+ }
+
+ @Override
+ public void Run(User source, AcidUser to, Channel c, String[] args)
+ {
+ String vhost = args[0] + '\u000F';
+
+ if (!source.isIdentified())
+ {
+ // User has not identified to NickServ.
+ Acidictive.reply(source, to, c, "You need to register or identify to your nickname before you can use this command");
+ return;
+ }
+
+ if (c != null)
+ {
+ // Cannot be a channel command
+ Acidictive.reply(source, to, null, "This command cannot be used in a channel");
+ return;
+ }
+
+ VizonUser user = Vizon.getVizonDatabase().findOrCreateUser(source.getNick());
+
+ if (!user.isEligible())
+ {
+ // User not eligible to select a new vhost
+ Acidictive.reply(source, to, null, "You are not allowed to select a new vhost");
+ return;
+ }
+
+ Matcher matcher;
+
+ if (user.isBold())
+ {
+ matcher = VhostManager.BOLD_PATTERN.matcher(vhost);
+ }
+ else
+ {
+ matcher = VhostManager.NORMAL_PATTERN.matcher(vhost);
+ }
+
+ if (!matcher.matches())
+ {
+ // Vhost contains illegal characters
+ Acidictive.reply(source, to, null, "Requested vhost contains illegal characters, or is empty");
+ return;
+ }
+
+ if (vhost.getBytes().length > MAX_HOST_BYTES)
+ {
+ // We count bytes instead of chars, since counting chars is wrong.
+ Acidictive.reply(source, to, null, "Requested vhost is too long");
+ return;
+ }
+
+ VizonRequest request = Vizon.getVizonDatabase().findVhostRequestByUserId(user.getId());
+
+ if (request == null)
+ {
+ // id doesn't really matter, it will get assigned in the database automatically.
+ request = new VizonRequest(
+ -1,
+ user.getId(),
+ user.getNick(),
+ vhost,
+ RequestStatus.PENDING,
+ null,
+ null,
+ LocalDateTime.now());
+
+ if (!Vizon.getVizonDatabase().insertRequest(request))
+ {
+ // User not eligible to select a new vhost
+ Acidictive.reply(source, to, null, "Something went wrong while registering your vhost request, please try again or contact an operator");
+ return;
+ }
+
+ request = Vizon.getVizonDatabase().findVhostRequestByUserId(request.getUserId());
+
+ Acidictive.reply(source, to, null, "Vhost requested");
+
+ if (request != null)
+ {
+ // Should never be null, but you know.
+ Vizon.getRequestTracker().addRequest(request);
+ }
+ }
+ else if (request.getVhost().equals(vhost))
+ {
+ Acidictive.reply(source, to, null, "You already requested this vhost");
+ }
+ else
+ {
+ request.setVhost(vhost);
+
+ if (!Vizon.getVizonDatabase().updateRequest(request))
+ {
+ Acidictive.reply(source, to, null, "Something went wrong while updating your vhost request, please try again or contact an operator");
+ return;
+ }
+
+ Acidictive.reply(source, to, null, "Request updated");
+
+ Vizon.getRequestTracker().addRequest(request);
+ }
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2017, orillion <orillion@rizon.net>
+ * All rights reserved.
+ *
+ * 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.
+ *
+ * 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 HOLDER 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.
+ */
+package net.rizon.acid.plugins.vizon.commands;
+
+import java.time.Duration;
+import java.time.LocalDateTime;
+import net.rizon.acid.core.AcidUser;
+import net.rizon.acid.core.Acidictive;
+import net.rizon.acid.core.Channel;
+import net.rizon.acid.core.Command;
+import net.rizon.acid.core.User;
+import net.rizon.acid.plugins.vizon.Vizon;
+import net.rizon.acid.plugins.vizon.db.VizonUser;
+import net.rizon.acid.util.Util;
+
+/**
+ *
+ * @author orillion <orillion@rizon.net>
+ */
+public class VipCommand extends Command
+{
+ private static final String VIP_FORMAT = "Multiplication factor: %d; Total accumulated days of current VIP: %d; Last drawing claimed of current VIP: %s (No.%d); Remaining time of current VIP: %s";
+
+ public VipCommand()
+ {
+ super(0, 0);
+ }
+
+ @Override
+ public void Run(User source, AcidUser to, Channel c, String[] args)
+ {
+ if (!source.isIdentified())
+ {
+ // User not identified
+ Acidictive.reply(source, to, c, "You need to identify before you can use this command");
+ return;
+ }
+
+ VizonUser user = Vizon.getVizonDatabase().findUser(source.getNick());
+
+ if (user == null)
+ {
+ // User never played
+ Acidictive.reply(source, to, c, "You have never played in Vizon before!");
+ return;
+ }
+
+ if (user.getObtained() == null)
+ {
+ // Not in a VIP session
+ Acidictive.reply(source, to, c, "You have no VIP");
+ return;
+ }
+
+ Duration remaining = Duration.between(LocalDateTime.now(), user.getObtained().plusDays(user.getDays()));
+ String remainingTime = Util.fTime((int) remaining.getSeconds());
+
+ Acidictive.reply(source, to, c, String.format(
+ VIP_FORMAT,
+ user.getMultiplier(),
+ user.getDays(),
+ user.getObtained(),
+ user.getObtainedId(),
+ remainingTime));
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2017, orillion <orillion@rizon.net>
+ * All rights reserved.
+ *
+ * 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.
+ *
+ * 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 HOLDER 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.
+ */
+package net.rizon.acid.plugins.vizon.conf;
+
+import java.time.Duration;
+import java.util.List;
+import net.rizon.acid.arguments.ExpiryArgument;
+import net.rizon.acid.conf.Client;
+import net.rizon.acid.conf.ConfigException;
+import net.rizon.acid.conf.Configuration;
+import net.rizon.acid.conf.Validator;
+
+/**
+ *
+ * @author orillion <orillion@rizon.net>
+ */
+public class VizonConfig extends Configuration
+{
+ public List<Client> clients;
+ public String vizonChannel;
+ public String vizonBot;
+ public List<Integer> days;
+ public String drawingOpen;
+ public String drawingClose;
+ public String drawingTime;
+
+ public int firstPrize;
+ public int secondPrize;
+ public int thirdPrize;
+ public int consolationPrize;
+
+ private ExpiryArgument drawingOpenArgument;
+ private ExpiryArgument drawingCloseArgument;
+
+ @Override
+ public void validate() throws ConfigException
+ {
+ drawingOpenArgument = ExpiryArgument.parse(drawingOpen);
+ drawingCloseArgument = ExpiryArgument.parse(drawingClose);
+
+ Validator.validateNotNull("drawingOpenArgument", drawingOpenArgument);
+ Validator.validateNotNull("drawingCloseArgument", drawingCloseArgument);
+ Validator.validateNotNull("days", days);
+ }
+
+ public Duration getOpenTimeInterval()
+ {
+ return drawingOpenArgument.getDuration();
+ }
+
+ public Duration getCloseTimeInterval()
+ {
+ return drawingCloseArgument.getDuration();
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2017, orillion <orillion@rizon.net>
+ * All rights reserved.
+ *
+ * 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.
+ *
+ * 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 HOLDER 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.
+ */
+package net.rizon.acid.plugins.vizon.db;
+
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.sql.Statement;
+import java.sql.Timestamp;
+import java.time.LocalDateTime;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import net.rizon.acid.plugins.vizon.Bet;
+import net.rizon.acid.plugins.vizon.RequestStatus;
+import net.rizon.acid.plugins.vizon.VizonBet;
+import net.rizon.acid.sql.SQL;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ *
+ * @author orillion <orillion@rizon.net>
+ */
+public class VizonDatabase
+{
+ private static final Logger logger = LoggerFactory.getLogger(VizonDatabase.class);
+ private final SQL vizonSql;
+
+ public VizonDatabase(SQL vizonSql)
+ {
+ this.vizonSql = vizonSql;
+ }
+
+ /**
+ * Finds a drawing by its id.
+ *
+ * @param id Id of the drawing.
+ *
+ * @return {@link VizonDrawing} or null if not found.
+ */
+ public VizonDrawing getDrawingById(int id)
+ {
+ try
+ {
+ PreparedStatement statement = vizonSql.prepare("SELECT * FROM vizon_drawings "
+ + "WHERE id = ?");
+
+ statement.setInt(1, id);
+
+ ResultSet rs = vizonSql.executeQuery(statement);
+
+ if (rs.next())
+ {
+ return VizonDrawing.fromResultSet(rs);
+ }
+
+ return null;
+ }
+ catch (SQLException ex)
+ {
+ logger.warn("Unable to get next drawing in Vizon Database", ex);
+ return null;
+ }
+ }
+
+ /**
+ * Finds the drawing closest to the specified date.
+ *
+ * @param date Date to look up.
+ *
+ * @return {@link VizonDrawing} or null if none can be found.
+ */
+ public VizonDrawing getDrawingByDate(LocalDateTime date)
+ {
+ if (date == null)
+ {
+ return null;
+ }
+
+ try
+ {
+ PreparedStatement statement = vizonSql.prepare("SELECT * FROM vizon_drawings "
+ + "ORDER BY ABS(TIMESTAMPDIFF(second, drawing_date, ?) "
+ + "LIMIT 1");
+
+ statement.setTimestamp(1, Timestamp.valueOf(date));
+
+ ResultSet rs = vizonSql.executeQuery(statement);
+
+ if (rs.next())
+ {
+ return VizonDrawing.fromResultSet(rs);
+ }
+
+ return null;
+ }
+ catch (SQLException ex)
+ {
+ logger.warn("Unable to get next drawing in Vizon Database", ex);
+ return null;
+ }
+ }
+
+ public VizonDrawing getLatestDrawing()
+ {
+ try
+ {
+ PreparedStatement statement = vizonSql.prepare("SELECT * FROM vizon_drawings "
+ + "ORDER BY id DESC "
+ + "LIMIT 1");
+
+ ResultSet rs = vizonSql.executeQuery(statement);
+
+ if (rs.next())
+ {
+ return VizonDrawing.fromResultSet(rs);
+ }
+
+ return null;
+ }
+ catch (SQLException ex)
+ {
+ logger.warn("Unable to get next drawing in Vizon Database", ex);
+ return null;
+ }
+ }
+
+ /**
+ * Gets the next drawing that's scheduled to take place.
+ *
+ * @return {@link VizonDrawing} or null if nothing is scheduled.
+ */
+ public VizonDrawing getNextDrawing()
+ {
+ try
+ {
+ PreparedStatement statement = vizonSql.prepare("SELECT * FROM vizon_drawings "
+ + "WHERE drawing_date >= NOW() "
+ + "ORDER BY drawing_date DESC "
+ + "LIMIT 1");
+
+ ResultSet rs = vizonSql.executeQuery(statement);
+
+ if (rs.next())
+ {
+ return VizonDrawing.fromResultSet(rs);
+ }
+
+ return null;
+ }
+ catch (SQLException ex)
+ {
+ logger.warn("Unable to get next drawing in Vizon Database", ex);
+ return null;
+ }
+ }
+
+ public VizonUser findUserById(int id)
+ {
+ try
+ {
+ PreparedStatement statement = vizonSql.prepare("SELECT * FROM vizon_users "
+ + "WHERE id = ?");
+
+ statement.setInt(1, id);
+
+ ResultSet rs = vizonSql.executeQuery(statement);
+
+ if (rs.next())
+ {
+ return VizonUser.fromResultSet(rs);
+ }
+
+ return null;
+ }
+ catch (SQLException ex)
+ {
+ logger.warn("Unable to find user by id in Vizon Database", ex);
+ return null;
+ }
+ }
+
+ public VizonUser findUser(String nick)
+ {
+ if (nick == null)
+ {
+ return null;
+ }
+
+ try
+ {
+ PreparedStatement statement = vizonSql.prepare("SELECT * FROM vizon_users WHERE nick = ?");
+ statement.setString(1, nick);
+
+ ResultSet rs = vizonSql.executeQuery(statement);
+
+ if (rs.next())
+ {
+ return VizonUser.fromResultSet(rs);
+ }
+
+ return null;
+ }
+ catch (SQLException ex)
+ {
+ logger.warn("Unable to select or create user in Vizon Database", ex);
+ return null;
+ }
+ }
+
+ /**
+ * Finds or creates a user. A user's id and nick are both unique in the
+ * database.
+ *
+ * @param nick Nick of the user. (Case insensitive)
+ *
+ * @return {@link VizonUser} or null if an error occurred.
+ */
+ public VizonUser findOrCreateUser(String nick)
+ {
+ if (nick == null)
+ {
+ return null;
+ }
+
+ try
+ {
+ PreparedStatement statement = vizonSql.prepare("SELECT * FROM vizon_users WHERE nick = ?");
+ statement.setString(1, nick);
+
+ ResultSet rs = vizonSql.executeQuery(statement);
+
+ if (rs.next())
+ {
+ return VizonUser.fromResultSet(rs);
+ }
+
+ statement = vizonSql.prepare("INSERT INTO vizon_users (nick) VALUES(?)");
+ statement.setString(1, nick);
+
+ int result = vizonSql.executeUpdateBlocking(statement);
+
+ if (result != 1)
+ {
+ // Unable to insert new user.
+ return null;
+ }
+
+ statement = vizonSql.prepare("SELECT * FROM vizon_users WHERE nick = ?");
+ statement.setString(1, nick);
+
+ rs = vizonSql.executeQuery(statement);
+
+ if (rs.next())
+ {
+ return VizonUser.fromResultSet(rs);
+ }
+
+ return null;
+ }
+ catch (SQLException ex)
+ {
+ logger.warn("Unable to select or create user in Vizon Database", ex);
+ return null;
+ }
+ }
+
+ public VizonRequest findVhostRequestByUserId(int userId)
+ {
+ try
+ {
+ PreparedStatement statement = vizonSql.prepare("SELECT vizon_requests.*, vizon_users.nick FROM vizon_requests "
+ + "INNER JOIN vizon_users "
+ + "ON vizon_users.id = vizon_requests.user_id "
+ + "WHERE user_id = ? "
+ + "AND status = ?");
+ statement.setInt(1, userId);
+ statement.setInt(2, RequestStatus.PENDING);
+
+ ResultSet rs = vizonSql.executeQuery(statement);
+
+ if (rs.next())
+ {
+ return VizonRequest.fromResultSet(rs);
+ }
+
+ return null;
+ }
+ catch (SQLException ex)
+ {
+ logger.warn("Unable to find vhost request for nick", ex);
+ return null;
+ }
+ }
+
+ public VizonRequest findVhostRequest(String nick)
+ {
+ if (nick == null)
+ {
+ return null;
+ }
+
+ try
+ {
+ PreparedStatement statement = vizonSql.prepare("SELECT vizon_requests.*, vizon_users.nick FROM vizon_requests"
+ + "INNER JOIN vizon_users "
+ + "ON vizon_users.id = vizon_requests.user_id"
+ + "WHERE vizon_users.nick = ?");
+ statement.setString(1, nick);
+
+ ResultSet rs = vizonSql.executeQuery(statement);
+
+ if (rs.next())
+ {
+ return VizonRequest.fromResultSet(rs);
+ }
+
+ return null;
+ }
+ catch (SQLException ex)
+ {
+ logger.warn("Unable to find vhost request for nick", ex);
+ return null;
+ }
+ }
+
+ public Collection<VizonRequest> findPendingVhostRequests()
+ {
+ try
+ {
+ PreparedStatement statement = vizonSql.prepare("SELECT vizon_requests.*, vizon_users.nick FROM vizon_requests "
+ + "INNER JOIN vizon_users "
+ + "ON vizon_users.id = vizon_requests.user_id "
+ + "WHERE vizon_requests.status = ?");
+ statement.setInt(1, RequestStatus.PENDING);
+
+ ResultSet rs = vizonSql.executeQuery(statement);
+
+ List<VizonRequest> requests = new ArrayList<>();
+
+ while (rs.next())
+ {
+ VizonRequest request = VizonRequest.fromResultSet(rs);
+
+ if (request != null)
+ {
+ requests.add(request);
+ }
+ }
+
+ return requests;
+ }
+ catch (SQLException ex)
+ {
+ logger.warn("Unable to find vhost request for nick", ex);
+ return null;
+ }
+ }
+
+ public boolean insertRequest(VizonRequest request)
+ {
+ if (request == null)
+ {
+ return false;
+ }
+
+ try
+ {
+ PreparedStatement statement = vizonSql.prepare("INSERT INTO vizon_requests "
+ + "(user_id, vhost, status, reason, oper) "
+ + "VALUES (?, ?, ?, ?, ?)");
+ statement.setInt(1, request.getUserId());
+ statement.setString(2, request.getVhost());
+ statement.setInt(3, request.getStatus());
+ statement.setString(4, request.getReason());
+ statement.setString(5, request.getOper());
+
+ int result = vizonSql.executeUpdateBlocking(statement);
+
+ return result > 0;
+ }
+ catch (SQLException ex)
+ {
+ logger.warn("Unable to insert vhost request", ex);
+ return false;
+ }
+ }
+
+ public boolean updateRequest(VizonRequest request)
+ {
+ if (request == null)
+ {
+ return false;
+ }
+
+ try
+ {
+ PreparedStatement statement = vizonSql.prepare("UPDATE vizon_requests "
+ + "SET vhost = ?, "
+ + "status = ?, "
+ + "reason = ?, "
+ + "oper = ? "
+ + "WHERE id = ?");
+ statement.setString(1, request.getVhost());
+ statement.setInt(2, request.getStatus());
+ statement.setString(3, request.getReason());
+ statement.setString(4, request.getOper());
+ statement.setInt(5, request.getId());
+
+ int result = vizonSql.executeUpdateBlocking(statement);
+
+ return true;
+ }
+ catch (SQLException ex)
+ {
+ logger.warn("Unable to insert vhost request", ex);
+ return false;
+ }
+ }
+
+ public boolean updateUser(VizonUser user)
+ {
+ if (user == null)
+ {
+ return false;
+ }
+
+ try
+ {
+ PreparedStatement statement = vizonSql.prepare("UPDATE vizon_users "
+ + "SET vhost = ?, "
+ + "eligible = ?, "
+ + "bold = ?, "
+ + "obtained = ?, "
+ + "obtained_id = ?, "
+ + "multiplier = ?, "
+ + "jackpot = ?, "
+ + "permanent = ?, "
+ + "days = ? "
+ + "WHERE id = ?");
+
+ statement.setString(1, user.getVhost());
+ statement.setBoolean(2, user.isEligible());
+ statement.setBoolean(3, user.isBold());
+ statement.setTimestamp(4, Timestamp.valueOf(user.getObtained()));
+ statement.setInt(5, user.getObtainedId());
+ statement.setInt(6, user.getMultiplier());
+ statement.setBoolean(7, user.isJackpot());
+ statement.setBoolean(8, user.isPermanent());
+ statement.setInt(9, user.getDays());
+ statement.setInt(10, user.getId());
+
+ int updated = vizonSql.executeUpdateBlocking(statement);
+
+ return updated > 0;
+ }
+ catch (SQLException ex)
+ {
+ logger.warn("Unable to select bet for user and drawing in Vizon Database", ex);
+ return false;
+ }
+ }
+
+ public boolean updateDrawing(VizonDrawing drawing)
+ {
+ if (drawing == null)
+ {
+ return false;
+ }
+
+ try
+ {
+ PreparedStatement statement = vizonSql.prepare("UPDATE vizon_drawings "
+ + "SET first = ?, "
+ + "second = ?, "
+ + "third = ?, "
+ + "fourth = ?, "
+ + "fifth = ?, "
+ + "sixth = ? "
+ + "WHERE id = ?");
+
+ statement.setInt(1, drawing.getDraws().get(0));
+ statement.setInt(2, drawing.getDraws().get(1));
+ statement.setInt(3, drawing.getDraws().get(2));
+ statement.setInt(4, drawing.getDraws().get(3));
+ statement.setInt(5, drawing.getDraws().get(4));
+ statement.setInt(6, drawing.getDraws().get(5));
+ statement.setInt(7, drawing.getId());
+
+ int updated = vizonSql.executeUpdateBlocking(statement);
+
+ return updated > 0;
+ }
+ catch (SQLException ex)
+ {
+ logger.warn("Unable to select bet for user and drawing in Vizon Database", ex);
+ return false;
+ }
+ }
+
+ /**
+ * Attempts to find a {@link VizonBet} of the user for the specified
+ * drawing.
+ *
+ * @param user User to find for.
+ * @param drawing Drawing to find for.
+ *
+ * @return {@link VizonBet} or null if none can be found.
+ */
+ public VizonBet findBetForUserAndDrawing(VizonUser user, VizonDrawing drawing)
+ {
+ if (user == null || drawing == null)
+ {
+ return null;
+ }
+
+ try
+ {
+ PreparedStatement statement = vizonSql.prepare("SELECT * FROM vizon_bets WHERE vizon_users_id = ? AND vizon_drawings_id = ?");
+ statement.setInt(1, user.getId());
+ statement.setInt(2, drawing.getId());
+
+ ResultSet rs = vizonSql.executeQuery(statement);
+
+ if (rs.next())
+ {
+ return VizonBet.fromResultSet(rs);
+ }
+
+ return null;
+ }
+ catch (SQLException ex)
+ {
+ logger.warn("Unable to select bet for user and drawing in Vizon Database", ex);
+ return null;
+ }
+ }
+
+ public List<VizonBet> findBetsForUser(VizonUser user)
+ {
+ return null;
+ }
+
+ public List<VizonBet> findBetsForDrawing(VizonDrawing drawing)
+ {
+ List<VizonBet> bets = new ArrayList<>();
+
+ if (drawing == null)
+ {
+ return bets;
+ }
+
+ try
+ {
+ PreparedStatement statement = vizonSql.prepare("SELECT * FROM vizon_bets WHERE vizon_drawings_id = ?");
+ statement.setInt(1, drawing.getId());
+
+ ResultSet rs = vizonSql.executeQuery(statement);
+
+ while (rs.next())
+ {
+ VizonBet bet = VizonBet.fromResultSet(rs);
+
+ if (bet == null)
+ {
+ continue;
+ }
+
+ bets.add(bet);
+ }
+ }
+ catch (SQLException ex)
+ {
+ logger.warn("Unable to select bets for drawing in Vizon Database", ex);
+ }
+
+ return bets;
+ }
+
+ /**
+ * Creates a new bet for the user for the specified drawing.
+ *
+ * @param user User to place the bet for.
+ * @param drawing Drawing to place the bet in.
+ * @param bet Bet to place.
+ *
+ * @return True if successful, false otherwise.
+ */
+ public boolean createBetForUser(VizonUser user, VizonDrawing drawing, Bet bet)
+ {
+ if (user == null || drawing == null || bet == null)
+ {
+ return false;
+ }
+
+ try
+ {
+ PreparedStatement statement = vizonSql.prepare("INSERT INTO vizon_bets "
+ + "(vizon_users_id, vizon_drawings_id, first, second, third, fourth, fifth, sixth) "
+ + "VALUES(?, ?, ?, ?, ?, ?, ?, ?)");
+
+ statement.setInt(1, user.getId());
+ statement.setInt(2, drawing.getId());
+ statement.setInt(3, bet.getFirst());
+ statement.setInt(4, bet.getSecond());
+ statement.setInt(5, bet.getThird());
+ statement.setInt(6, bet.getFourth());
+ statement.setInt(7, bet.getFifth());
+ statement.setInt(8, bet.getSixth());
+
+ int inserted = vizonSql.executeUpdateBlocking(statement);
+
+ return inserted > 0;
+ }
+ catch (SQLException ex)
+ {
+ logger.warn("Error while inserting bet for user in Vizon Database", ex);
+ return false;
+ }
+ }
+
+ /**
+ * Finds a scheduled drawing that has not been run yet (i.e. First == null)
+ *
+ * @return {@link VizonDrawing} or null if no unrun drawings exist
+ */
+ public VizonDrawing findEarliestUnrunDrawing()
+ {
+ try
+ {
+ PreparedStatement statement = vizonSql.prepare("SELECT * FROM vizon_drawings "
+ + "WHERE first IS NULL "
+ + "ORDER BY drawing_date "
+ + "LIMIT 1");
+
+ ResultSet rs = vizonSql.executeQuery(statement);
+
+ if (!rs.next())
+ {
+ return null;
+ }
+
+ return VizonDrawing.fromResultSet(rs);
+ }
+ catch (SQLException ex)
+ {
+ logger.warn("Error while trying to find earliest drawing in Vizon Database", ex);
+ return null;
+ }
+ }
+
+ public VizonDrawing createDrawing(LocalDateTime date)
+ {
+ try
+ {
+ PreparedStatement statement = vizonSql.prepare("INSERT INTO vizon_drawings "
+ + "(drawing_date) "
+ + "VALUES(?)",
+ Statement.RETURN_GENERATED_KEYS);
+
+ statement.setTimestamp(1, Timestamp.valueOf(date));
+
+ int inserted = vizonSql.executeUpdateBlocking(statement);
+
+ ResultSet rs = statement.getGeneratedKeys();
+
+ if (rs == null || !rs.next())
+ {
+ return null;
+ }
+
+ int id = rs.getInt(1);
+
+ statement = vizonSql.prepare("SELECT * FROM vizon_drawings "
+ + "WHERE id = ?");
+
+ statement.setInt(1, id);
+
+ rs = vizonSql.executeQuery(statement);
+
+ if (rs == null || !rs.next())
+ {
+ return null;
+ }
+
+ return VizonDrawing.fromResultSet(rs);
+ }
+ catch (SQLException ex)
+ {
+ logger.warn("Error while trying to create drawing in Vizon Database", ex);
+ return null;
+ }
+ }
+
+ public List<VizonUser> findAllUsers()
+ {
+ List<VizonUser> users = new ArrayList<>();
+
+ try
+ {
+ PreparedStatement statement = vizonSql.prepare("SELECT * FROM vizon_users");
+
+ ResultSet rs = vizonSql.executeQuery(statement);
+
+ while (rs.next())
+ {
+ VizonUser user = VizonUser.fromResultSet(rs);
+
+ if (user == null)
+ {
+ continue;
+ }
+
+ users.add(user);
+ }
+ }
+ catch (SQLException ex)
+ {
+ logger.warn("Error while trying to get all users in Vizon Database", ex);
+ }
+
+ return users;
+ }
+
+ public int expireVhosts()
+ {
+ try
+ {
+ PreparedStatement statement = vizonSql.prepare("UPDATE vizon_users "
+ + "SET vhost = null, "
+ + "eligible = 0, "
+ + "obtained = null, "
+ + "obtained_id = -1, "
+ + "multiplier = 0, "
+ + "bold = 0 "
+ + "WHERE permament = 0 "
+ + "AND DATE_ADD(obtained, INTERVAL days DAY) < NOW()");
+
+ return vizonSql.executeUpdateBlocking(statement);
+
+ }
+ catch (SQLException ex)
+ {
+ logger.warn("Error in SQL statement to expire vhosts", ex);
+ return 0;
+ }
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2017, orillion <orillion@rizon.net>
+ * All rights reserved.
+ *
+ * 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.
+ *
+ * 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 HOLDER 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.
+ */
+package net.rizon.acid.plugins.vizon.db;
+
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.sql.Timestamp;
+import java.time.Duration;
+import java.time.LocalDateTime;
+import java.util.Arrays;
+import java.util.List;
+import net.rizon.acid.plugins.vizon.Bet;
+import net.rizon.acid.plugins.vizon.DrawingState;
+import net.rizon.acid.plugins.vizon.Vizon;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ *
+ * @author orillion <orillion@rizon.net>
+ */
+public class VizonDrawing
+{
+ private static final Logger logger = LoggerFactory.getLogger(VizonDrawing.class);
+
+ private final int id;
+ private final List<Integer> draws;
+ private final LocalDateTime date;
+
+ /**
+ * Constructs a new {@link VizonDrawing} from the supplied
+ * {@link ResultSet}.
+ *
+ * @param rs {@link ResultSet} to construct object from.
+ *
+ * @return {@link VizonDrawing} or null if unable to construct object.
+ */
+ public static VizonDrawing fromResultSet(ResultSet rs)
+ {
+ try
+ {
+ // Grab id
+ int id = rs.getInt("id");
+
+ // Grab drawn numbers, ints default to 0 when they are NULL in
+ // the database, and we cannot bet 0, so this is okay for now.
+ // Should this change in the future, use rs.wasNull().
+ int first = rs.getInt("first");
+ int second = rs.getInt("second");
+ int third = rs.getInt("third");
+ int fourth = rs.getInt("fourth");
+ int fifth = rs.getInt("fifth");
+ int sixth = rs.getInt("sixth");
+
+ // Grab date this drawing is supposed to take place, or took place
+ // depending on what time it is now.
+ Timestamp ts = rs.getTimestamp("drawing_date");
+ List<Integer> draws = Arrays.asList(
+ first,
+ second,
+ third,
+ fourth,
+ fifth,
+ sixth);
+
+ return new VizonDrawing(id, draws, ts.toLocalDateTime());
+ }
+ catch (SQLException ex)
+ {
+ logger.warn("Unable to construct VizonDrawing object", ex);
+ return null;
+ }
+ }
+
+ private VizonDrawing(int id, List<Integer> draws, LocalDateTime date)
+ {
+ this.id = id;
+ this.draws = draws;
+ this.date = date;
+ }
+
+ public int getId()
+ {
+ return id;
+ }
+
+ public List<Integer> getDraws()
+ {
+ return draws;
+ }
+
+ public LocalDateTime getDate()
+ {
+ return date;
+ }
+
+ public int checkCorrect(Bet bet)
+ {
+ return checkCorrect(bet.asList());
+ }
+
+ public int checkCorrect(List<Integer> bets)
+ {
+ int correct = 0;
+
+ // Check how many of the bets are in the draws.
+ for (int bet : bets)
+ {
+ if (draws.contains(bet))
+ {
+ correct++;
+ }
+ }
+
+ return correct;
+ }
+
+ public void setDrawingResult(Bet result)
+ {
+ this.draws.set(0, result.getFirst());
+ this.draws.set(1, result.getSecond());
+ this.draws.set(2, result.getThird());
+ this.draws.set(3, result.getFourth());
+ this.draws.set(4, result.getFifth());
+ this.draws.set(5, result.getSixth());
+ }
+
+ public DrawingState getState()
+ {
+ LocalDateTime now = LocalDateTime.now();
+
+ if (getOpenDate().isAfter(now))
+ {
+ return DrawingState.PREPARING;
+ }
+ else if (getCloseDate().isAfter(now))
+ {
+ return DrawingState.OPEN;
+ }
+ else
+ {
+ return DrawingState.CLOSED;
+ }
+ }
+
+ public LocalDateTime getOpenDate()
+ {
+ Duration before = Vizon.getConf().getOpenTimeInterval();
+
+ return this.date.minus(before);
+ }
+
+ public LocalDateTime getCloseDate()
+ {
+ Duration before = Vizon.getConf().getCloseTimeInterval();
+
+ return this.date.minus(before);
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2017, orillion <orillion@rizon.net>
+ * All rights reserved.
+ *
+ * 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.
+ *
+ * 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 HOLDER 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.
+ */
+package net.rizon.acid.plugins.vizon.db;
+
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.time.LocalDateTime;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ *
+ * @author orillion <orillion@rizon.net>
+ */
+public class VizonRequest
+{
+ private static final Logger logger = LoggerFactory.getLogger(VizonRequest.class);
+
+ private final int id;
+ private final int userId;
+ private final String nick;
+ private String vhost;
+ private int status;
+ private String reason;
+ private String oper;
+ private LocalDateTime date;
+
+ public static VizonRequest fromResultSet(ResultSet rs)
+ {
+ try
+ {
+ int id = rs.getInt("id");
+ int userId = rs.getInt("user_id");
+ String vhost = rs.getString("vhost");
+ String nick = rs.getString("nick");
+ int status = rs.getInt("status");
+ String reason = rs.getString("reason");
+ String oper = rs.getString("oper");
+ LocalDateTime date = rs.getTimestamp("date").toLocalDateTime();
+
+ return new VizonRequest(id, userId, nick, vhost, status, reason, oper, date);
+ }
+ catch (SQLException ex)
+ {
+ logger.warn("Unable to construct VizonRequest from ResultSet", ex);
+ return null;
+ }
+ }
+
+ public VizonRequest(int id, int userId, String nick, String vhost, int status, String reason, String oper, LocalDateTime date)
+ {
+ this.id = id;
+ this.userId = userId;
+ this.nick = nick;
+ this.vhost = vhost;
+ this.status = status;
+ this.reason = reason;
+ this.oper = oper;
+ this.date = date;
+ }
+
+ public int getId()
+ {
+ return id;
+ }
+
+ public int getUserId()
+ {
+ return userId;
+ }
+
+ public String getNick()
+ {
+ return nick;
+ }
+
+ public String getVhost()
+ {
+ return vhost;
+ }
+
+ public int getStatus()
+ {
+ return status;
+ }
+
+ public String getReason()
+ {
+ return reason;
+ }
+
+ public String getOper()
+ {
+ return oper;
+ }
+
+ public LocalDateTime getDate()
+ {
+ return date;
+ }
+
+ public void setStatus(int status)
+ {
+ this.status = status;
+ }
+
+ public void setReason(String reason)
+ {
+ this.reason = reason;
+ }
+
+ public void setOper(String oper)
+ {
+ this.oper = oper;
+ }
+
+ public void setDate(LocalDateTime date)
+ {
+ this.date = date;
+ }
+
+ public void setVhost(String vhost)
+ {
+ this.vhost = vhost;
+ }
+
+}
--- /dev/null
+/*
+ * Copyright (c) 2017, orillion <orillion@rizon.net>
+ * All rights reserved.
+ *
+ * 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.
+ *
+ * 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 HOLDER 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.
+ */
+package net.rizon.acid.plugins.vizon.db;
+
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.sql.Timestamp;
+import java.time.LocalDateTime;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ *
+ * @author orillion <orillion@rizon.net>
+ */
+public class VizonUser
+{
+ private static final Logger logger = LoggerFactory.getLogger(VizonUser.class);
+
+ private final int id;
+ private final String nick;
+ private String vhost;
+ private boolean eligible;
+ private boolean bold;
+ private LocalDateTime obtained;
+ private int obtainedId;
+ private int expires;
+ private int multiplier;
+ private boolean jackpot;
+ private boolean permanent;
+ private int days;
+
+ public static VizonUser fromResultSet(ResultSet rs)
+ {
+ try
+ {
+ int id = rs.getInt("id");
+ String nick = rs.getString("nick");
+ String vhost = rs.getString("vhost");
+ boolean eligible = rs.getBoolean("eligible");
+ boolean bold = rs.getBoolean("bold");
+ int expires = rs.getInt("expires");
+ Timestamp obtained = rs.getTimestamp("obtained");
+ int obtainedId = rs.getInt("obtained_id");
+ int multiplier = rs.getInt("multiplier");
+ boolean jackpot = rs.getBoolean("jackpot");
+ boolean permanent = rs.getBoolean("permanent");
+ int days = rs.getInt("days");
+
+ LocalDateTime date = null;
+
+ if (obtained != null)
+ {
+ date = obtained.toLocalDateTime();
+ }
+
+ return new VizonUser(
+ id,
+ nick,
+ vhost,
+ eligible,
+ bold,
+ date,
+ obtainedId,
+ expires,
+ multiplier,
+ jackpot,
+ permanent,
+ days);
+ }
+ catch (SQLException ex)
+ {
+ logger.warn("Unable to construct VizonUser from ResultSet", ex);
+ return null;
+ }
+ }
+
+
+ private VizonUser(
+ int id,
+ String nick,
+ String vhost,
+ boolean eligible,
+ boolean bold,
+ LocalDateTime obtained,
+ int obtainedId,
+ int expires,
+ int multiplier,
+ boolean jackpot,
+ boolean permanent,
+ int days)
+ {
+ this.id = id;
+ this.nick = nick;
+ this.vhost = vhost;
+ this.eligible = eligible;
+ this.bold = bold;
+ this.obtained = obtained;
+ this.obtainedId = obtainedId;
+ this.expires = expires;
+ this.multiplier = multiplier;
+ this.jackpot = jackpot;
+ this.permanent = permanent;
+ this.days = days;
+ }
+
+ public int getId()
+ {
+ return id;
+ }
+
+ public String getNick()
+ {
+ return nick;
+ }
+
+ public String getVhost()
+ {
+ return vhost;
+ }
+
+ public boolean isEligible()
+ {
+ return eligible;
+ }
+
+ public boolean isBold()
+ {
+ return bold;
+ }
+
+ public LocalDateTime getObtained()
+ {
+ return obtained;
+ }
+
+ public int getExpires()
+ {
+ return expires;
+ }
+
+ public boolean isJackpot()
+ {
+ return jackpot;
+ }
+
+ public boolean isPermanent()
+ {
+ return permanent;
+ }
+
+ public int getDays()
+ {
+ return days;
+ }
+
+ public void addDays(int days)
+ {
+ this.days += days;
+ }
+
+ public int getMultiplier()
+ {
+ return multiplier;
+ }
+
+ public void incrementMultiplier()
+ {
+ multiplier++;
+ }
+
+ public void resetMultiplier()
+ {
+ multiplier = 0;
+ }
+
+ public void setBold(boolean bold)
+ {
+ this.bold = bold;
+ }
+
+ public void setVhost(String vhost)
+ {
+ this.vhost = vhost;
+ }
+
+ public void setEligible(boolean eligible)
+ {
+ this.eligible = eligible;
+ }
+
+ public void setObtained(LocalDateTime obtained)
+ {
+ this.obtained = obtained;
+ }
+
+ public void setExpires(int expires)
+ {
+ this.expires = expires;
+ }
+
+ public void setJackpot(boolean jackpot)
+ {
+ this.jackpot = jackpot;
+ }
+
+ public void setPermanent(boolean permanent)
+ {
+ this.permanent = permanent;
+ }
+
+ public int getObtainedId()
+ {
+ return this.obtainedId;
+ }
+
+ public void setObtainedId(int drawingId)
+ {
+ this.obtainedId = drawingId;
+ }
+
+}
--- /dev/null
+/*
+ * Copyright (c) 2017, orillion <orillion@rizon.net>
+ * All rights reserved.
+ *
+ * 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.
+ *
+ * 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 HOLDER 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.
+ */
+package net.rizon.acid.plugins.vizon.util;
+
+import java.time.DayOfWeek;
+import java.time.LocalDateTime;
+import java.time.LocalTime;
+import java.time.temporal.TemporalAdjusters;
+import net.rizon.acid.plugins.vizon.conf.VizonConfig;
+
+/**
+ *
+ * @author orillion <orillion@rizon.net>
+ */
+public class VizonTemporal
+{
+ /**
+ * Determines the next drawing that should place, after the specified date.
+ *
+ * @param date Date after which the next drawing should be determined.
+ * @param config Config file
+ *
+ * @return Next date
+ */
+ public static LocalDateTime determineNextDrawing(LocalDateTime date, VizonConfig config)
+ {
+ LocalTime drawingTime = LocalTime.parse(config.drawingTime);
+ LocalDateTime drawing = LocalDateTime.MAX;
+
+ /*
+ * This for loop constructs a LocalDateTime object for every day that is
+ * in the config and then checks if it is closer to now than the
+ * previous one it determined.
+ */
+ for (int dayOfWeek : config.days)
+ {
+ LocalDateTime temp = date
+ .with(TemporalAdjusters.nextOrSame(DayOfWeek.of(dayOfWeek)))
+ .withHour(drawingTime.getHour())
+ .withMinute(drawingTime.getMinute())
+ .withSecond(drawingTime.getSecond());
+
+ if (temp.isAfter(date) && temp.isBefore(drawing))
+ {
+ drawing = temp;
+ }
+ }
+
+ return drawing;
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2017, orillion <orillion@rizon.net>
+ * All rights reserved.
+ *
+ * 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.
+ *
+ * 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 HOLDER 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.
+ */
+package net.rizon.acid.plugins.vizon;
+
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+
+/**
+ *
+ * @author orillion <orillion@rizon.net>
+ */
+public class BetTest
+{
+
+ public BetTest()
+ {
+ }
+
+ @Before
+ public void setUp()
+ {
+ }
+
+ /**
+ * Test of getFirst method, of class Bet.
+ */
+ @Test
+ public void hasSameNumbersTest()
+ {
+ Bet bet = new Bet(1, 2, 3, 4, 5, 6);
+ Bet draw = new Bet(1, 2, 3, 4, 5, 6);
+
+ boolean areEqual = bet.hasSameNumbers(draw);
+
+ Assert.assertTrue(areEqual);
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2016, orillion <orillion@rizon.net>
+ * All rights reserved.
+ *
+ * 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.
+ *
+ * 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 HOLDER 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.
+ */
+package net.rizon.acid.plugins.vizon;
+
+import java.util.Optional;
+import org.junit.Assert;
+import org.junit.Test;
+
+/**
+ * Unit tests for the bet validator.
+ *
+ * @author orillion <orillion@rizon.net>
+ */
+public class BetValidatorTest
+{
+ /**
+ * Test whether or not the validate method returns an empty optional when
+ * you present null to it.
+ */
+ @Test
+ public void validateNullTest()
+ {
+ String bet = null;
+
+ Optional<Bet> result = BetValidator.validate(bet);
+
+ Assert.assertFalse(result.isPresent());
+ }
+
+ /**
+ * Test whether or not the validate method returns an empty optional when
+ * you present an empty to it.
+ */
+ @Test
+ public void validateEmptyStringTest()
+ {
+ String bet = "";
+
+ Optional<Bet> result = BetValidator.validate(bet);
+
+ Assert.assertFalse(result.isPresent());
+ }
+
+ /**
+ * Test whether or not the validate method returns an empty optional when
+ * you present an incorrect string to it.
+ */
+ @Test
+ public void validateNotEnoughNumbersTest()
+ {
+ String bet = "1 2 3";
+
+ Optional<Bet> result = BetValidator.validate(bet);
+
+ Assert.assertFalse(result.isPresent());
+ }
+
+ /**
+ * Test whether or not the validate method returns an empty optional when
+ * you present an incorrect string to it.
+ */
+ @Test
+ public void validateTooManyNumbersTest()
+ {
+ String bet = "1 2 3 4 5 6 7";
+
+ Optional<Bet> result = BetValidator.validate(bet);
+
+ Assert.assertFalse(result.isPresent());
+ }
+
+ /**
+ * Test whether or not the validate method returns an empty optional when
+ * you present an incorrect string to it.
+ */
+ @Test
+ public void validateDoubleNumbersTest()
+ {
+ String bet = "1 2 1 3 4 5";
+
+ Optional<Bet> result = BetValidator.validate(bet);
+
+ Assert.assertFalse(result.isPresent());
+ }
+
+ /**
+ * Test whether or not the validate method returns an empty optional when
+ * you present an incorrect string to it.
+ */
+ @Test
+ public void validateNegativeNumbersTest()
+ {
+ String bet = "1 2 -11 3 4 5";
+
+ Optional<Bet> result = BetValidator.validate(bet);
+
+ Assert.assertFalse(result.isPresent());
+ }
+
+ /**
+ * Test whether or not the validate method returns an empty optional when
+ * you present an incorrect string to it.
+ */
+ @Test
+ public void validateOutLowerBoundTest()
+ {
+ String bet = "1 2 0 3 4 5";
+
+ Optional<Bet> result = BetValidator.validate(bet);
+
+ Assert.assertFalse(result.isPresent());
+ }
+
+ /**
+ * Test whether or not the validate method returns an empty optional when
+ * you present an incorrect string to it.
+ */
+ @Test
+ public void validateOutUpperBoundTest()
+ {
+ String bet = "1 2 30 3 4 5";
+
+ Optional<Bet> result = BetValidator.validate(bet);
+
+ Assert.assertFalse(result.isPresent());
+ }
+
+ /**
+ * Test whether or not the validate method returns an filled optional when
+ * you present a correct string to it.
+ */
+ @Test
+ public void validateOnLowerBoundTest()
+ {
+ String bet = "1 2 3 4 5 6";
+
+ Optional<Bet> result = BetValidator.validate(bet);
+
+ Assert.assertTrue(result.isPresent());
+ Assert.assertEquals(1, result.get().getFirst());
+ Assert.assertEquals(2, result.get().getSecond());
+ Assert.assertEquals(3, result.get().getThird());
+ Assert.assertEquals(4, result.get().getFourth());
+ Assert.assertEquals(5, result.get().getFifth());
+ Assert.assertEquals(6, result.get().getSixth());
+ }
+
+ /**
+ * Test whether or not the validate method returns an filled optional when
+ * you present a correct string to it.
+ */
+ @Test
+ public void validateOnUpperBoundTest()
+ {
+ String bet = "1 2 3 4 5 29";
+
+ Optional<Bet> result = BetValidator.validate(bet);
+
+ Assert.assertTrue(result.isPresent());
+ Assert.assertEquals(1, result.get().getFirst());
+ Assert.assertEquals(2, result.get().getSecond());
+ Assert.assertEquals(3, result.get().getThird());
+ Assert.assertEquals(4, result.get().getFourth());
+ Assert.assertEquals(5, result.get().getFifth());
+ Assert.assertEquals(29, result.get().getSixth());
+ }
+
+ /**
+ * Test whether or not the validate method returns an filled optional when
+ * you present a correct string to it.
+ */
+ @Test
+ public void validateResultRemainsUnsortedTest()
+ {
+ String bet = "9 2 11 4 21 29";
+
+ Optional<Bet> result = BetValidator.validate(bet);
+
+ Assert.assertTrue(result.isPresent());
+ Assert.assertEquals(9, result.get().getFirst());
+ Assert.assertEquals(2, result.get().getSecond());
+ Assert.assertEquals(11, result.get().getThird());
+ Assert.assertEquals(4, result.get().getFourth());
+ Assert.assertEquals(21, result.get().getFifth());
+ Assert.assertEquals(29, result.get().getSixth());
+ }
+
+ /**
+ * Test whether or not the validator does not mind multiple spaces in front.
+ * <p>
+ * Reasoning: Users can accidentally type a space and it's something that
+ * can be solved easy with a removeEmptyEntries call in standard java
+ * library.
+ */
+ @Test
+ public void validateAccidentalSpaceFrontTest()
+ {
+ String bet = " 9 2 11 4 21 29";
+
+ Optional<Bet> result = BetValidator.validate(bet);
+
+ Assert.assertTrue(result.isPresent());
+ Assert.assertEquals(9, result.get().getFirst());
+ Assert.assertEquals(2, result.get().getSecond());
+ Assert.assertEquals(11, result.get().getThird());
+ Assert.assertEquals(4, result.get().getFourth());
+ Assert.assertEquals(21, result.get().getFifth());
+ Assert.assertEquals(29, result.get().getSixth());
+ }
+
+ /**
+ * Test whether or not the validator does not mind multiple spaces at the
+ * end.
+ * <p>
+ * Reasoning: Users can accidentally type a space and it's something that
+ * can be solved easy with a removeEmptyEntries call in standard java
+ * library.
+ */
+ @Test
+ public void validateAccidentalSpaceEndTest()
+ {
+ String bet = "9 2 11 4 21 29 ";
+
+ Optional<Bet> result = BetValidator.validate(bet);
+
+ Assert.assertTrue(result.isPresent());
+ Assert.assertEquals(9, result.get().getFirst());
+ Assert.assertEquals(2, result.get().getSecond());
+ Assert.assertEquals(11, result.get().getThird());
+ Assert.assertEquals(4, result.get().getFourth());
+ Assert.assertEquals(21, result.get().getFifth());
+ Assert.assertEquals(29, result.get().getSixth());
+ }
+
+ /**
+ * Test whether or not the validator does not mind multiple spaces in
+ * between.
+ * <p>
+ * Reasoning: Users can accidentally type a space and it's something that
+ * can be solved easy with a removeEmptyEntries call in standard java
+ * library.
+ */
+ @Test
+ public void validateAccidentalSpaceBetweenTest()
+ {
+ String bet = "9 2 11 4 21 29";
+
+ Optional<Bet> result = BetValidator.validate(bet);
+
+ Assert.assertTrue(result.isPresent());
+ Assert.assertEquals(9, result.get().getFirst());
+ Assert.assertEquals(2, result.get().getSecond());
+ Assert.assertEquals(11, result.get().getThird());
+ Assert.assertEquals(4, result.get().getFourth());
+ Assert.assertEquals(21, result.get().getFifth());
+ Assert.assertEquals(29, result.get().getSixth());
+ }
+
+ /**
+ * Test whether or not the validator returns an empty Optional when
+ * presented with gibberish.
+ */
+ @Test
+ public void validateNoNumbersTest()
+ {
+ String bet = "hello world!";
+
+ Optional<Bet> result = BetValidator.validate(bet);
+
+ Assert.assertFalse(result.isPresent());
+ }
+
+ /**
+ * Test whether or not the validator returns an empty Optional when
+ * presented with gibberish.
+ */
+ @Test
+ public void validateTextAfterNumbersTest()
+ {
+ String bet = "1 2 3 4 5 6 hello world!";
+
+ Optional<Bet> result = BetValidator.validate(bet);
+
+ Assert.assertFalse(result.isPresent());
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2017, orillion <orillion@rizon.net>
+ * All rights reserved.
+ *
+ * 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.
+ *
+ * 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 HOLDER 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.
+ */
+package net.rizon.acid.plugins.vizon;
+
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Ignore;
+import org.junit.Test;
+
+/**
+ *
+ * @author orillion <orillion@rizon.net>
+ */
+public class DrawGeneratorTest
+{
+ private DrawGenerator generator;
+
+ public DrawGeneratorTest()
+ {
+ }
+
+ @Before
+ public void setup()
+ {
+ generator = new DrawGenerator();
+ }
+
+ /**
+ * Test of generate method, of class DrawGenerator.
+ */
+ @Test
+ public void generateTest()
+ {
+ Bet bet = generator.generate();
+ Assert.assertNotNull(bet);
+ }
+
+ @Ignore("Testing randomness")
+ @Test
+ public void generate1000Test()
+ {
+ int[] draws = new int[29];
+
+ for (int i = 0; i < 10000; i++)
+ {
+ Bet bet = generator.generate();
+
+ draws[bet.getFirst() - 1]++;
+ draws[bet.getSecond() - 1]++;
+ draws[bet.getThird() - 1]++;
+ draws[bet.getFourth() - 1]++;
+ draws[bet.getFifth() - 1]++;
+ draws[bet.getSixth() - 1]++;
+ }
+
+ for (int i = 0; i < 29; i++)
+ {
+ int draw = draws[i];
+ System.out.println(String.format("Number %2d was drawn %d times", i + 1, draw));
+ }
+ }
+
+ @Ignore("Testing randomness")
+ @Test
+ public void bet123456Test()
+ {
+ Bet bet = new Bet(1, 2, 3, 4, 5, 6);
+
+ long totalRuns = 0;
+ int cycles = 100;
+
+ Bet draw;
+
+ for (int i = 0; i < cycles; i++)
+ {
+ int runs = 0;
+
+ do
+ {
+ draw = generator.generate();
+ runs++;
+ }
+ while (!draw.hasSameNumbers(bet));
+
+ totalRuns += runs;
+
+ System.out.println(String.format("Run %3d completed", i + 1));
+ }
+
+ System.out.println(String.format("It took an average of %d runs to win first prize with bet 1 2 3 4 5 6", totalRuns / cycles));
+ }
+
+ /**
+ * Test of generateSpecial method, of class DrawGenerator.
+ */
+ @Test
+ public void testGenerateSpecial()
+ {
+
+ }
+
+}
--- /dev/null
+/*
+ * Copyright (c) 2017, orillion <orillion@rizon.net>
+ * All rights reserved.
+ *
+ * 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.
+ *
+ * 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 HOLDER 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.
+ */
+package net.rizon.acid.plugins.vizon;
+
+import net.rizon.acid.plugins.vizon.db.VizonDrawing;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.sql.Timestamp;
+import org.junit.Assert;
+import static org.junit.Assert.fail;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import static org.mockito.Mockito.when;
+import org.mockito.runners.MockitoJUnitRunner;
+
+/**
+ *
+ * @author orillion <orillion@rizon.net>
+ */
+@RunWith(MockitoJUnitRunner.class)
+public class VizonDrawingTest
+{
+ @Mock
+ private ResultSet resultSet;
+
+ private VizonDrawing drawing;
+
+ public VizonDrawingTest()
+ {
+ }
+
+ @Before
+ public void setUp()
+ {
+ try
+ {
+ when(resultSet.getInt("id")).thenReturn(1);
+ when(resultSet.getInt("first")).thenReturn(1);
+ when(resultSet.getInt("second")).thenReturn(2);
+ when(resultSet.getInt("third")).thenReturn(3);
+ when(resultSet.getInt("fourth")).thenReturn(4);
+ when(resultSet.getInt("fifth")).thenReturn(5);
+ when(resultSet.getInt("sixth")).thenReturn(6);
+ when(resultSet.getTimestamp("drawing_date")).thenReturn(Timestamp.valueOf("2016-12-12 00:00:00"));
+ }
+ catch (SQLException ex)
+ {
+ fail("SQLException");
+ }
+
+ drawing = VizonDrawing.fromResultSet(resultSet);
+ }
+
+ /**
+ * Tests if the calculator returns the correct amount of correct values.
+ */
+ @Test
+ public void zeroCorrectTest()
+ {
+ Bet bet = new Bet(11, 12, 13, 14, 15, 16);
+
+ int actual = drawing.checkCorrect(bet);
+ int expected = 0;
+
+ Assert.assertEquals(expected, actual);
+ }
+
+ /**
+ * Tests if the calculator returns the correct amount of correct values.
+ */
+ @Test
+ public void oneCorrectTest()
+ {
+ Bet bet = new Bet(1, 12, 13, 14, 15, 16);
+
+ int actual = drawing.checkCorrect(bet);
+ int expected = 1;
+
+ Assert.assertEquals(expected, actual);
+ }
+
+ /**
+ * Tests if the calculator returns the correct amount of correct values.
+ */
+ @Test
+ public void twoCorrectTest()
+ {
+ Bet bet = new Bet(1, 2, 13, 14, 15, 16);
+
+ int actual = drawing.checkCorrect(bet);
+ int expected = 2;
+
+ Assert.assertEquals(expected, actual);
+ }
+
+ /**
+ * Tests if the calculator returns the correct amount of correct values.
+ */
+ @Test
+ public void threeCorrectTest()
+ {
+ Bet bet = new Bet(1, 2, 3, 14, 15, 16);
+
+ int actual = drawing.checkCorrect(bet);
+ int expected = 3;
+
+ Assert.assertEquals(expected, actual);
+ }
+
+ /**
+ * Tests if the calculator returns the correct amount of correct values.
+ */
+ @Test
+ public void fourCorrectTest()
+ {
+ Bet bet = new Bet(1, 2, 3, 4, 15, 16);
+
+ int actual = drawing.checkCorrect(bet);
+ int expected = 4;
+
+ Assert.assertEquals(expected, actual);
+ }
+
+ /**
+ * Tests if the calculator returns the correct amount of correct values.
+ */
+ @Test
+ public void fiveCorrectTest()
+ {
+ Bet bet = new Bet(1, 2, 3, 4, 5, 16);
+
+ int actual = drawing.checkCorrect(bet);
+ int expected = 5;
+
+ Assert.assertEquals(expected, actual);
+ }
+
+ /**
+ * Tests if the calculator returns the correct amount of correct values.
+ */
+ @Test
+ public void sixCorrectTest()
+ {
+ Bet bet = new Bet(1, 2, 3, 4, 5, 6);
+
+ int actual = drawing.checkCorrect(bet);
+ int expected = 6;
+
+ Assert.assertEquals(expected, actual);
+ }
+}
--- /dev/null
+clients:
+ -
+ nick: VizonBot
+ user: colors
+ host: services.rizon.net
+ vhost: for.everyone
+ name: VIzon
+ modes: iUop
+ channels: [ vizonChannel ]
+ commands:
+ -
+ name: help
+ privilege: anyone
+ clazz: net.rizon.acid.commands.Help
+ -
+ name: bet
+ privilege: anyone
+ clazz: net.rizon.acid.plugins.vizon.commands.BetCommand
+ -
+ name: "!bet"
+ privilege: anyone
+ clazz: net.rizon.acid.plugins.vizon.commands.BetCommand
+ -
+ name: check
+ privilege: anyone
+ clazz: net.rizon.acid.plugins.vizon.commands.CheckCommand
+ -
+ name: "!check"
+ privilege: anyone
+ clazz: net.rizon.acid.plugins.vizon.commands.CheckCommand
+ -
+ name: request
+ privilege: anyone
+ clazz: net.rizon.acid.plugins.vizon.commands.RequestCommand
+ -
+ name: "!request"
+ privilege: anyone
+ clazz: net.rizon.acid.plugins.vizon.commands.RequestCommand
+ -
+ name: vip
+ privilege: anyone
+ clazz: net.rizon.acid.plugins.vizon.commands.VipCommand
+ -
+ name: "!vip"
+ privilege: anyone
+ clazz: net.rizon.acid.plugins.vizon.commands.VipCommand
+ -
+ name: pending
+ channels: [vhost]
+ privilege: none
+ clazz: net.rizon.acid.plugins.vizon.commands.PendingRequestCommand
+ -
+ name: approve
+ channels: [vhost]
+ privilege: none
+ clazz: net.rizon.acid.plugins.vizon.commands.ApproveRequestCommand
+ -
+ name: reject
+ channels: [vhost]
+ privilege: none
+ clazz: net.rizon.acid.plugins.vizon.commands.RejectRequestCommand
+ -
+ name: delete
+ channels: [vhost]
+ privilege: none
+ clazz: net.rizon.acid.plugins.vizon.commands.DeleteCommand
+
+vizonChannel: "#opers"
+vizonBot: "VizonBot"
+
+days: [3, 5, 7]
+drawingOpen: "+24h"
+drawingClose: "+10m"
+drawingTime: "22:00:00"
+
+firstPrize: 120
+secondPrize: 60
+thirdPrize: 30
+consolationPrize: 10
--- /dev/null
+-- MySQL Script generated by MySQL Workbench
+-- 01/15/17 12:21:36
+-- Model: New Model Version: 1.0
+-- MySQL Workbench Forward Engineering
+
+SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0;
+SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0;
+SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='TRADITIONAL,ALLOW_INVALID_DATES';
+
+-- -----------------------------------------------------
+-- Schema vizon
+-- -----------------------------------------------------
+
+-- -----------------------------------------------------
+-- Schema vizon
+-- -----------------------------------------------------
+CREATE SCHEMA IF NOT EXISTS `vizon` DEFAULT CHARACTER SET latin1 ;
+USE `vizon` ;
+
+-- -----------------------------------------------------
+-- Table `vizon`.`vizon_users`
+-- -----------------------------------------------------
+CREATE TABLE IF NOT EXISTS `vizon`.`vizon_users` (
+ `id` INT NOT NULL AUTO_INCREMENT,
+ `nick` VARCHAR(64) NOT NULL,
+ `vhost` VARCHAR(64) NULL,
+ `eligible` TINYINT(1) NULL DEFAULT 0,
+ `bold` TINYINT(1) NULL DEFAULT 0,
+ `expires` INT NULL DEFAULT -1,
+ `obtained` TIMESTAMP NULL,
+ `multiplier` INT NULL DEFAULT 1,
+ `jackpot` TINYINT(1) NULL DEFAULT 0,
+ `permanent` TINYINT(1) NULL DEFAULT 0,
+ `days` INT NULL DEFAULT 0,
+ PRIMARY KEY (`id`),
+ UNIQUE INDEX `nick_UNIQUE` (`nick` ASC))
+ENGINE = InnoDB;
+
+
+-- -----------------------------------------------------
+-- Table `vizon`.`vizon_drawings`
+-- -----------------------------------------------------
+CREATE TABLE IF NOT EXISTS `vizon`.`vizon_drawings` (
+ `id` INT NOT NULL AUTO_INCREMENT,
+ `first` INT NULL,
+ `second` INT NULL,
+ `third` INT NULL,
+ `fourth` INT NULL,
+ `fifth` INT NULL,
+ `sixth` INT NULL,
+ `drawing_date` TIMESTAMP NOT NULL,
+ PRIMARY KEY (`id`))
+ENGINE = InnoDB;
+
+
+-- -----------------------------------------------------
+-- Table `vizon`.`vizon_bets`
+-- -----------------------------------------------------
+CREATE TABLE IF NOT EXISTS `vizon`.`vizon_bets` (
+ `id` INT NOT NULL AUTO_INCREMENT,
+ `vizon_users_id` INT NOT NULL,
+ `vizon_drawings_id` INT NOT NULL,
+ `first` INT NOT NULL,
+ `second` INT NOT NULL,
+ `third` INT NOT NULL,
+ `fourth` INT NOT NULL,
+ `fifth` INT NOT NULL,
+ `sixth` INT NOT NULL,
+ `placed` TIMESTAMP NOT NULL DEFAULT NOW(),
+ PRIMARY KEY (`id`),
+ INDEX `fk_vizon_bets_vizon_users_idx` (`vizon_users_id` ASC),
+ INDEX `fk_vizon_bets_vizon_drawings1_idx` (`vizon_drawings_id` ASC),
+ CONSTRAINT `fk_vizon_bets_vizon_users`
+ FOREIGN KEY (`vizon_users_id`)
+ REFERENCES `vizon`.`vizon_users` (`id`)
+ ON DELETE CASCADE
+ ON UPDATE CASCADE,
+ CONSTRAINT `fk_vizon_bets_vizon_drawings1`
+ FOREIGN KEY (`vizon_drawings_id`)
+ REFERENCES `vizon`.`vizon_drawings` (`id`)
+ ON DELETE CASCADE
+ ON UPDATE CASCADE)
+ENGINE = InnoDB;
+
+
+SET SQL_MODE=@OLD_SQL_MODE;
+SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS;
+SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS;